blob: 857aeed5577a636fcf8dc6abb620ea22547cc8bf [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
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
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>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030033#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020034#include <sys/mman.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040035
Benjamin Franzkec649a922011-03-02 11:56:04 +010036#include <xf86drm.h>
37#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050038#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010039
Benjamin Franzke060cf802011-04-30 09:32:11 +020040#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020041#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040042#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020043
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040044#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010045#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020046#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050047#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010048#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040049
Kristian Høgsberg061c4252012-06-28 11:28:15 -040050static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060051static char *output_name;
52static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060053static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060054static struct wl_list configured_output_list;
55
56enum output_config {
57 OUTPUT_CONFIG_INVALID = 0,
58 OUTPUT_CONFIG_OFF,
59 OUTPUT_CONFIG_PREFERRED,
60 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060061 OUTPUT_CONFIG_MODE,
62 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060063};
64
65struct drm_configured_output {
66 char *name;
67 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060068 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060069 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060070 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060071 enum output_config config;
72 struct wl_list link;
73};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040074
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040075struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050076 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040077
78 struct udev *udev;
79 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040080
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010081 struct udev_monitor *udev_monitor;
82 struct wl_event_source *udev_drm_source;
83
Benjamin Franzke2af7f102011-03-02 11:14:59 +010084 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010085 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010086 int fd;
87 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020088 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050089 uint32_t *crtcs;
90 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050091 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010092 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050093 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020094
Rob Clark4339add2012-08-09 14:18:28 -050095 /* we need these parameters in order to not fail drmModeAddFB2()
96 * due to out of bounds dimensions, and then mistakenly set
97 * sprites_are_broken:
98 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020099 uint32_t min_width, max_width;
100 uint32_t min_height, max_height;
101 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500102
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500104 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200105 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500106
Rob Clarkab5b1e32012-08-09 13:24:45 -0500107 int cursors_are_broken;
108
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200109 int use_pixman;
110
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200111 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400112};
113
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400114struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500115 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400116 drmModeModeInfo mode_info;
117};
118
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300119struct drm_output;
120
121struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300122 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200123 uint32_t fb_id, stride, handle, size;
124 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300125 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200126 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200127
128 /* Used by gbm fbs */
129 struct gbm_bo *bo;
130
131 /* Used by dumb fbs */
132 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300133};
134
Richard Hughes2b2092a2013-04-24 14:58:02 +0100135struct drm_edid {
136 char eisa_id[13];
137 char monitor_name[13];
138 char pnp_id[5];
139 char serial_number[13];
140};
141
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400142struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500143 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400145 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500147 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400148 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700149 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100150 struct drm_edid edid;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200151
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300152 int vblank_pending;
153 int page_flip_pending;
154
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400155 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400156 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400157 struct weston_plane cursor_plane;
158 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400159 struct weston_surface *cursor_surface;
160 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300161 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200162 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200163
164 struct drm_fb *dumb[2];
165 pixman_image_t *image[2];
166 int current_image;
167 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400168};
169
Jesse Barnes58ef3792012-02-23 09:45:49 -0500170/*
171 * An output has a primary display plane plus zero or more sprites for
172 * blending display contents.
173 */
174struct drm_sprite {
175 struct wl_list link;
176
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400177 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500178
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200179 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300180 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181 struct drm_compositor *compositor;
182
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183 uint32_t possible_crtcs;
184 uint32_t plane_id;
185 uint32_t count_formats;
186
187 int32_t src_x, src_y;
188 uint32_t src_w, src_h;
189 uint32_t dest_x, dest_y;
190 uint32_t dest_w, dest_h;
191
192 uint32_t formats[];
193};
194
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500195static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400196
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400197static void
198drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400199
Jesse Barnes58ef3792012-02-23 09:45:49 -0500200static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500201drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
202{
203 struct weston_compositor *ec = output_base->compositor;
204 struct drm_compositor *c =(struct drm_compositor *) ec;
205 struct drm_output *output = (struct drm_output *) output_base;
206 int crtc;
207
208 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
209 if (c->crtcs[crtc] != output->crtc_id)
210 continue;
211
212 if (supported & (1 << crtc))
213 return -1;
214 }
215
216 return 0;
217}
218
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300219static void
220drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
221{
222 struct drm_fb *fb = data;
223 struct gbm_device *gbm = gbm_bo_get_device(bo);
224
225 if (fb->fb_id)
226 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
227
Pekka Paalanende685b82012-12-04 15:58:12 +0200228 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300229
230 free(data);
231}
232
233static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200234drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
235{
236 struct drm_fb *fb;
237 int ret;
238
239 struct drm_mode_create_dumb create_arg;
240 struct drm_mode_destroy_dumb destroy_arg;
241 struct drm_mode_map_dumb map_arg;
242
243 fb = calloc(1, sizeof *fb);
244 if (!fb)
245 return NULL;
246
247 create_arg.bpp = 32;
248 create_arg.width = width;
249 create_arg.height = height;
250
251 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
252 if (ret)
253 goto err_fb;
254
255 fb->handle = create_arg.handle;
256 fb->stride = create_arg.pitch;
257 fb->size = create_arg.size;
258 fb->fd = ec->drm.fd;
259
260 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
261 fb->stride, fb->handle, &fb->fb_id);
262 if (ret)
263 goto err_bo;
264
265 memset(&map_arg, 0, sizeof(map_arg));
266 map_arg.handle = fb->handle;
267 drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
268
269 if (ret)
270 goto err_add_fb;
271
272 fb->map = mmap(0, fb->size, PROT_WRITE,
273 MAP_SHARED, ec->drm.fd, map_arg.offset);
274 if (fb->map == MAP_FAILED)
275 goto err_add_fb;
276
277 return fb;
278
279err_add_fb:
280 drmModeRmFB(ec->drm.fd, fb->fb_id);
281err_bo:
282 memset(&destroy_arg, 0, sizeof(destroy_arg));
283 destroy_arg.handle = create_arg.handle;
284 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
285err_fb:
286 free(fb);
287 return NULL;
288}
289
290static void
291drm_fb_destroy_dumb(struct drm_fb *fb)
292{
293 struct drm_mode_destroy_dumb destroy_arg;
294
295 if (!fb->map)
296 return;
297
298 if (fb->fb_id)
299 drmModeRmFB(fb->fd, fb->fb_id);
300
301 weston_buffer_reference(&fb->buffer_ref, NULL);
302
303 munmap(fb->map, fb->size);
304
305 memset(&destroy_arg, 0, sizeof(destroy_arg));
306 destroy_arg.handle = fb->handle;
307 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
308
309 free(fb);
310}
311
312static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500313drm_fb_get_from_bo(struct gbm_bo *bo,
314 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300315{
316 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200317 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200318 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300319 int ret;
320
321 if (fb)
322 return fb;
323
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200324 fb = calloc(1, sizeof *fb);
325 if (!fb)
326 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327
328 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329
330 width = gbm_bo_get_width(bo);
331 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200332 fb->stride = gbm_bo_get_stride(bo);
333 fb->handle = gbm_bo_get_handle(bo).u32;
334 fb->size = fb->stride * height;
335 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300336
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200337 if (compositor->min_width > width || width > compositor->max_width ||
338 compositor->min_height > height ||
339 height > compositor->max_height) {
340 weston_log("bo geometry out of bounds\n");
341 goto err_free;
342 }
343
344 ret = -1;
345
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200346 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200347 handles[0] = fb->handle;
348 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 offsets[0] = 0;
350
351 ret = drmModeAddFB2(compositor->drm.fd, width, height,
352 format, handles, pitches, offsets,
353 &fb->fb_id, 0);
354 if (ret) {
355 weston_log("addfb2 failed: %m\n");
356 compositor->no_addfb2 = 1;
357 compositor->sprites_are_broken = 1;
358 }
359 }
360
361 if (ret)
362 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200363 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200366 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200367 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368 }
369
370 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
371
372 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200373
374err_free:
375 free(fb);
376 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377}
378
379static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
381{
Pekka Paalanende685b82012-12-04 15:58:12 +0200382 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200383
384 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
Pekka Paalanende685b82012-12-04 15:58:12 +0200386 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200387}
388
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200389static void
390drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
391{
392 if (!fb)
393 return;
394
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200395 if (fb->map &&
396 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200397 drm_fb_destroy_dumb(fb);
398 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200399 if (fb->is_client_buffer)
400 gbm_bo_destroy(fb->bo);
401 else
402 gbm_surface_release_buffer(output->surface,
403 output->current->bo);
404 }
405}
406
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500407static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200408drm_output_check_scanout_format(struct drm_output *output,
409 struct weston_surface *es, struct gbm_bo *bo)
410{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200411 uint32_t format;
412 pixman_region32_t r;
413
414 format = gbm_bo_get_format(bo);
415
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500416 switch (format) {
417 case GBM_FORMAT_XRGB8888:
418 return format;
419 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420 /* We can only scanout an ARGB buffer if the surface's
421 * opaque region covers the whole output */
422 pixman_region32_init(&r);
423 pixman_region32_subtract(&r, &output->base.region,
424 &es->opaque);
425
426 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500427 format = GBM_FORMAT_XRGB8888;
428 else
429 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200430
431 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200432
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500433 return format;
434 default:
435 return 0;
436 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200437}
438
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400439static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400440drm_output_prepare_scanout_surface(struct weston_output *_output,
441 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500442{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400443 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500444 struct drm_compositor *c =
445 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200446 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300447 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500448 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500449
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500450 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200451 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200452 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200453 buffer->width != output->base.current->width ||
454 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200455 output->base.transform != es->buffer_transform ||
456 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400457 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500458
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400459 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200460 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500461
Rob Bradford9b101872012-09-14 23:25:41 +0100462 /* Unable to use the buffer for scanout */
463 if (!bo)
464 return NULL;
465
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500466 format = drm_output_check_scanout_format(output, es, bo);
467 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300468 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400469 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300470 }
471
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500472 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 if (!output->next) {
474 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400475 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300476 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500477
Pekka Paalanende685b82012-12-04 15:58:12 +0200478 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500479
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400480 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500481}
482
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500483static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200484drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400485{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200486 struct drm_compositor *c =
487 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300488 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400489
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200490 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400491
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300492 bo = gbm_surface_lock_front_buffer(output->surface);
493 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200494 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400495 return;
496 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300497
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500498 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200500 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 gbm_surface_release_buffer(output->surface, bo);
502 return;
503 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400504}
505
506static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200507drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
508{
509 struct weston_compositor *ec = output->base.compositor;
510 pixman_region32_t total_damage, previous_damage;
511
512 pixman_region32_init(&total_damage);
513 pixman_region32_init(&previous_damage);
514
515 pixman_region32_copy(&previous_damage, damage);
516
517 pixman_region32_union(&total_damage, damage, &output->previous_damage);
518 pixman_region32_copy(&output->previous_damage, &previous_damage);
519
520 output->current_image ^= 1;
521
522 output->next = output->dumb[output->current_image];
523 pixman_renderer_output_set_buffer(&output->base,
524 output->image[output->current_image]);
525
526 ec->renderer->repaint_output(&output->base, &total_damage);
527
528 pixman_region32_fini(&total_damage);
529 pixman_region32_fini(&previous_damage);
530}
531
532static void
533drm_output_render(struct drm_output *output, pixman_region32_t *damage)
534{
535 struct drm_compositor *c =
536 (struct drm_compositor *) output->base.compositor;
537
538 if (c->use_pixman)
539 drm_output_render_pixman(output, damage);
540 else
541 drm_output_render_gl(output, damage);
542
543 pixman_region32_subtract(&c->base.primary_plane.damage,
544 &c->base.primary_plane.damage, damage);
545}
546
547static void
Richard Hughese7299962013-05-01 21:52:12 +0100548drm_output_set_gamma(struct weston_output *output_base,
549 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
550{
551 int rc;
552 struct drm_output *output = (struct drm_output *) output_base;
553 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
554
555 /* check */
556 if (output_base->gamma_size != size)
557 return;
558 if (!output->original_crtc)
559 return;
560
561 rc = drmModeCrtcSetGamma(compositor->drm.fd,
562 output->crtc_id,
563 size, r, g, b);
564 if (rc)
565 weston_log("set gamma failed: %m\n");
566}
567
568static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500569drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400570 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100571{
572 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500573 struct drm_compositor *compositor =
574 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500575 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400576 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100578
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300579 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400580 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300581 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400582 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100583
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400584 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300585 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400586 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300587 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400588 &output->connector_id, 1,
589 &mode->mode_info);
590 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200591 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400592 return;
593 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200594 }
595
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500596 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300597 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500598 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200599 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500600 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500601 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100602
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300603 output->page_flip_pending = 1;
604
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400605 drm_output_set_cursor(output);
606
Jesse Barnes58ef3792012-02-23 09:45:49 -0500607 /*
608 * Now, update all the sprite surfaces
609 */
610 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200611 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500612 drmVBlank vbl = {
613 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
614 .request.sequence = 1,
615 };
616
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200617 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200618 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500619 continue;
620
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200621 if (s->next && !compositor->sprites_hidden)
622 fb_id = s->next->fb_id;
623
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200625 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 s->dest_x, s->dest_y,
627 s->dest_w, s->dest_h,
628 s->src_x, s->src_y,
629 s->src_w, s->src_h);
630 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200631 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 ret, strerror(errno));
633
Rob Clark5ca1a472012-08-08 20:27:37 -0500634 if (output->pipe > 0)
635 vbl.request.type |= DRM_VBLANK_SECONDARY;
636
Jesse Barnes58ef3792012-02-23 09:45:49 -0500637 /*
638 * Queue a vblank signal so we know when the surface
639 * becomes active on the display or has been replaced.
640 */
641 vbl.request.signal = (unsigned long)s;
642 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
643 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200644 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 ret, strerror(errno));
646 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300647
648 s->output = output;
649 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 }
651
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500652 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400653}
654
655static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200656drm_output_start_repaint_loop(struct weston_output *output_base)
657{
658 struct drm_output *output = (struct drm_output *) output_base;
659 struct drm_compositor *compositor = (struct drm_compositor *)
660 output_base->compositor;
661 uint32_t fb_id;
662
663 if (output->current)
664 fb_id = output->current->fb_id;
665 else
666 fb_id = output->original_crtc->buffer_id;
667
668 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
669 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
670 weston_log("queueing pageflip failed: %m\n");
671 return;
672 }
673}
674
675static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500676vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
677 void *data)
678{
679 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300680 struct drm_output *output = s->output;
681 uint32_t msecs;
682
683 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500684
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200685 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200686 s->current = s->next;
687 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300688
689 if (!output->page_flip_pending) {
690 msecs = sec * 1000 + usec / 1000;
691 weston_output_finish_frame(&output->base, msecs);
692 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500693}
694
695static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400696page_flip_handler(int fd, unsigned int frame,
697 unsigned int sec, unsigned int usec, void *data)
698{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200699 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400700 uint32_t msecs;
701
Jonas Ådahle5a12252013-04-05 23:07:11 +0200702 /* We don't set page_flip_pending on start_repaint_loop, in that case
703 * we just want to page flip to the current buffer to get an accurate
704 * timestamp */
705 if (output->page_flip_pending) {
706 drm_output_release_fb(output, output->current);
707 output->current = output->next;
708 output->next = NULL;
709 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300710
Jonas Ådahle5a12252013-04-05 23:07:11 +0200711 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400712
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300713 if (!output->vblank_pending) {
714 msecs = sec * 1000 + usec / 1000;
715 weston_output_finish_frame(&output->base, msecs);
716 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200717}
718
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500719static uint32_t
720drm_output_check_sprite_format(struct drm_sprite *s,
721 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500722{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500723 uint32_t i, format;
724
725 format = gbm_bo_get_format(bo);
726
727 if (format == GBM_FORMAT_ARGB8888) {
728 pixman_region32_t r;
729
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500730 pixman_region32_init_rect(&r, 0, 0,
731 es->geometry.width,
732 es->geometry.height);
733 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500734
735 if (!pixman_region32_not_empty(&r))
736 format = GBM_FORMAT_XRGB8888;
737
738 pixman_region32_fini(&r);
739 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500740
741 for (i = 0; i < s->count_formats; i++)
742 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500743 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500744
745 return 0;
746}
747
748static int
749drm_surface_transform_supported(struct weston_surface *es)
750{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500751 return !es->transform.enabled ||
752 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500753}
754
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400755static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500756drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400757 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500758{
759 struct weston_compositor *ec = output_base->compositor;
760 struct drm_compositor *c =(struct drm_compositor *) ec;
761 struct drm_sprite *s;
762 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500763 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500764 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200765 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400767 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200769 if (c->gbm == NULL)
770 return NULL;
771
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200772 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200773 return NULL;
774
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500775 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400776 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500777
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300778 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400779 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300780
Pekka Paalanende685b82012-12-04 15:58:12 +0200781 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400782 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500783
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200784 if (es->alpha != 1.0f)
785 return NULL;
786
Pekka Paalanende685b82012-12-04 15:58:12 +0200787 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500788 return NULL;
789
Jesse Barnes58ef3792012-02-23 09:45:49 -0500790 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400791 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792
Jesse Barnes58ef3792012-02-23 09:45:49 -0500793 wl_list_for_each(s, &c->sprite_list, link) {
794 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
795 continue;
796
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200797 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798 found = 1;
799 break;
800 }
801 }
802
803 /* No sprites available */
804 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400805 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400807 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200808 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400809 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400811
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500812 format = drm_output_check_sprite_format(s, es, bo);
813 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200814 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400815 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816 }
817
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200818 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200819 if (!s->next) {
820 gbm_bo_destroy(bo);
821 return NULL;
822 }
823
Pekka Paalanende685b82012-12-04 15:58:12 +0200824 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500825
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400826 box = pixman_region32_extents(&es->transform.boundingbox);
827 s->plane.x = box->x1;
828 s->plane.y = box->y1;
829
Jesse Barnes58ef3792012-02-23 09:45:49 -0500830 /*
831 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200832 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833 * for us already).
834 */
835 pixman_region32_init(&dest_rect);
836 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
837 &output_base->region);
838 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
839 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200840 tbox = weston_transformed_rect(output_base->width,
841 output_base->height,
842 output_base->transform, *box);
843 s->dest_x = tbox.x1;
844 s->dest_y = tbox.y1;
845 s->dest_w = tbox.x2 - tbox.x1;
846 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500847 pixman_region32_fini(&dest_rect);
848
849 pixman_region32_init(&src_rect);
850 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
851 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400853
854 weston_surface_from_global_fixed(es,
855 wl_fixed_from_int(box->x1),
856 wl_fixed_from_int(box->y1),
857 &sx1, &sy1);
858 weston_surface_from_global_fixed(es,
859 wl_fixed_from_int(box->x2),
860 wl_fixed_from_int(box->y2),
861 &sx2, &sy2);
862
863 if (sx1 < 0)
864 sx1 = 0;
865 if (sy1 < 0)
866 sy1 = 0;
867 if (sx2 > wl_fixed_from_int(es->geometry.width))
868 sx2 = wl_fixed_from_int(es->geometry.width);
869 if (sy2 > wl_fixed_from_int(es->geometry.height))
870 sy2 = wl_fixed_from_int(es->geometry.height);
871
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200872 tbox.x1 = sx1;
873 tbox.y1 = sy1;
874 tbox.x2 = sx2;
875 tbox.y2 = sy2;
876
877 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
878 wl_fixed_from_int(es->geometry.height),
879 es->buffer_transform, tbox);
880
881 s->src_x = tbox.x1 << 8;
882 s->src_y = tbox.y1 << 8;
883 s->src_w = (tbox.x2 - tbox.x1) << 8;
884 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500885 pixman_region32_fini(&src_rect);
886
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400887 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500888}
889
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400890static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400891drm_output_prepare_cursor_surface(struct weston_output *output_base,
892 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500893{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400894 struct drm_compositor *c =
895 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400896 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400897
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200898 if (c->gbm == NULL)
899 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200900 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
901 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400902 if (output->cursor_surface)
903 return NULL;
904 if (es->output_mask != (1u << output_base->id))
905 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500906 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400907 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200908 if (es->buffer_ref.buffer == NULL ||
909 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400910 es->geometry.width > 64 || es->geometry.height > 64)
911 return NULL;
912
913 output->cursor_surface = es;
914
915 return &output->cursor_plane;
916}
917
918static void
919drm_output_set_cursor(struct drm_output *output)
920{
921 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400922 struct drm_compositor *c =
923 (struct drm_compositor *) output->base.compositor;
924 EGLint handle, stride;
925 struct gbm_bo *bo;
926 uint32_t buf[64 * 64];
927 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400928 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500929
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400930 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400931 if (es == NULL) {
932 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
933 return;
934 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500935
Pekka Paalanende685b82012-12-04 15:58:12 +0200936 if (es->buffer_ref.buffer &&
937 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400938 pixman_region32_fini(&output->cursor_plane.damage);
939 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400940 output->current_cursor ^= 1;
941 bo = output->cursor_bo[output->current_cursor];
942 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200943 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
944 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400945 for (i = 0; i < es->geometry.height; i++)
946 memcpy(buf + i * 64, s + i * stride,
947 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500948
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400949 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300950 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400951
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400952 handle = gbm_bo_get_handle(bo).s32;
953 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500954 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300955 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500956 c->cursors_are_broken = 1;
957 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400958 }
959
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400960 x = es->geometry.x - output->base.x;
961 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400962 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500963 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400964 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500965 c->cursors_are_broken = 1;
966 }
967
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400968 output->cursor_plane.x = x;
969 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400970 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500971}
972
Jesse Barnes58ef3792012-02-23 09:45:49 -0500973static void
974drm_assign_planes(struct weston_output *output)
975{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400976 struct drm_compositor *c =
977 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400978 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500979 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400980 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500981
982 /*
983 * Find a surface for each sprite in the output using some heuristics:
984 * 1) size
985 * 2) frequency of update
986 * 3) opacity (though some hw might support alpha blending)
987 * 4) clipping (this can be fixed with color keys)
988 *
989 * The idea is to save on blitting since this should save power.
990 * If we can get a large video surface on the sprite for example,
991 * the main display surface may not need to update at all, and
992 * the client buffer can be used directly for the sprite surface
993 * as we do for flipping full screen surfaces.
994 */
995 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400996 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400997 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200998 /* test whether this buffer can ever go into a plane:
999 * non-shm, or small enough to be a cursor
1000 */
1001 if ((es->buffer_ref.buffer &&
1002 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1003 (es->geometry.width <= 64 && es->geometry.height <= 64))
1004 es->keep_buffer = 1;
1005 else
1006 es->keep_buffer = 0;
1007
Jesse Barnes58ef3792012-02-23 09:45:49 -05001008 pixman_region32_init(&surface_overlap);
1009 pixman_region32_intersect(&surface_overlap, &overlap,
1010 &es->transform.boundingbox);
1011
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001012 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001013 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001014 next_plane = primary;
1015 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001016 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001017 if (next_plane == NULL)
1018 next_plane = drm_output_prepare_scanout_surface(output, es);
1019 if (next_plane == NULL)
1020 next_plane = drm_output_prepare_overlay_surface(output, es);
1021 if (next_plane == NULL)
1022 next_plane = primary;
1023 weston_surface_move_to_plane(es, next_plane);
1024 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001025 pixman_region32_union(&overlap, &overlap,
1026 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001027
Jesse Barnes58ef3792012-02-23 09:45:49 -05001028 pixman_region32_fini(&surface_overlap);
1029 }
1030 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001031}
1032
Matt Roper361d2ad2011-08-29 13:52:23 -07001033static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001034drm_output_fini_pixman(struct drm_output *output);
1035
1036static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001037drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001038{
1039 struct drm_output *output = (struct drm_output *) output_base;
1040 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001041 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001042 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001043
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001044 if (output->backlight)
1045 backlight_destroy(output->backlight);
1046
Matt Roper361d2ad2011-08-29 13:52:23 -07001047 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001048 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001049
1050 /* Restore original CRTC state */
1051 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001052 origcrtc->x, origcrtc->y,
1053 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001054 drmModeFreeCrtc(origcrtc);
1055
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001056 c->crtc_allocator &= ~(1 << output->crtc_id);
1057 c->connector_allocator &= ~(1 << output->connector_id);
1058
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001059 if (c->use_pixman) {
1060 drm_output_fini_pixman(output);
1061 } else {
1062 gl_renderer_output_destroy(output_base);
1063 gbm_surface_destroy(output->surface);
1064 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001065
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001066 weston_plane_release(&output->fb_plane);
1067 weston_plane_release(&output->cursor_plane);
1068
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001069 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001070 wl_list_remove(&output->base.link);
1071
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001072 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001073 free(output);
1074}
1075
Alex Wub7b8bda2012-04-17 17:20:48 +08001076static struct drm_mode *
1077choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1078{
1079 struct drm_mode *tmp_mode = NULL, *mode;
1080
1081 if (output->base.current->width == target_mode->width &&
1082 output->base.current->height == target_mode->height &&
1083 (output->base.current->refresh == target_mode->refresh ||
1084 target_mode->refresh == 0))
1085 return (struct drm_mode *)output->base.current;
1086
1087 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1088 if (mode->mode_info.hdisplay == target_mode->width &&
1089 mode->mode_info.vdisplay == target_mode->height) {
1090 if (mode->mode_info.vrefresh == target_mode->refresh ||
1091 target_mode->refresh == 0) {
1092 return mode;
1093 } else if (!tmp_mode)
1094 tmp_mode = mode;
1095 }
1096 }
1097
1098 return tmp_mode;
1099}
1100
1101static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001102drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001103static int
1104drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001105
1106static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001107drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1108{
1109 struct drm_output *output;
1110 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001111 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001112
1113 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001114 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001115 return -1;
1116 }
1117
1118 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001119 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001120 return -1;
1121 }
1122
1123 ec = (struct drm_compositor *)output_base->compositor;
1124 output = (struct drm_output *)output_base;
1125 drm_mode = choose_mode (output, mode);
1126
1127 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001128 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001129 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001130 }
1131
1132 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001133 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001134
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001135 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001136
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001137 output->base.current = &drm_mode->base;
1138 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001139 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1140
Alex Wub7b8bda2012-04-17 17:20:48 +08001141 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001142 drm_output_release_fb(output, output->current);
1143 drm_output_release_fb(output, output->next);
1144 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001145
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001146 if (ec->use_pixman) {
1147 drm_output_fini_pixman(output);
1148 if (drm_output_init_pixman(output, ec) < 0) {
1149 weston_log("failed to init output pixman state with "
1150 "new mode\n");
1151 return -1;
1152 }
1153 } else {
1154 gl_renderer_output_destroy(&output->base);
1155 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001156
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001157 if (drm_output_init_egl(output, ec) < 0) {
1158 weston_log("failed to init output egl state with "
1159 "new mode");
1160 return -1;
1161 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001162 }
1163
Alex Wub7b8bda2012-04-17 17:20:48 +08001164 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001165}
1166
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001167static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001168on_drm_input(int fd, uint32_t mask, void *data)
1169{
1170 drmEventContext evctx;
1171
1172 memset(&evctx, 0, sizeof evctx);
1173 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1174 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001175 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001176 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001177
1178 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001179}
1180
1181static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001182init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001183{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001184 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001185 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001186
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001187 sysnum = udev_device_get_sysnum(device);
1188 if (sysnum)
1189 ec->drm.id = atoi(sysnum);
1190 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001191 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001192 return -1;
1193 }
1194
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001195 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001196 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001197 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001198 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001199 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001200 udev_device_get_devnode(device));
1201 return -1;
1202 }
1203
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001204 weston_log("using %s\n", filename);
1205
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001206 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001207
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001208
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001209 return 0;
1210}
1211
1212static int
1213init_egl(struct drm_compositor *ec)
1214{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001215 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001216
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001217 if (!ec->gbm)
1218 return -1;
1219
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001220 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001221 NULL) < 0) {
1222 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001223 return -1;
1224 }
1225
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001226 return 0;
1227}
1228
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001229static int
1230init_pixman(struct drm_compositor *ec)
1231{
1232 return pixman_renderer_init(&ec->base);
1233}
1234
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001235static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001236drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1237{
1238 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001239 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001240
1241 mode = malloc(sizeof *mode);
1242 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001243 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001244
1245 mode->base.flags = 0;
1246 mode->base.width = info->hdisplay;
1247 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001248
1249 /* Calculate higher precision (mHz) refresh rate */
1250 refresh = (info->clock * 1000000LL / info->htotal +
1251 info->vtotal / 2) / info->vtotal;
1252
1253 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1254 refresh *= 2;
1255 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1256 refresh /= 2;
1257 if (info->vscan > 1)
1258 refresh /= info->vscan;
1259
1260 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001261 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001262
1263 if (info->type & DRM_MODE_TYPE_PREFERRED)
1264 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1265
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001266 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1267
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001268 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001269}
1270
1271static int
1272drm_subpixel_to_wayland(int drm_value)
1273{
1274 switch (drm_value) {
1275 default:
1276 case DRM_MODE_SUBPIXEL_UNKNOWN:
1277 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1278 case DRM_MODE_SUBPIXEL_NONE:
1279 return WL_OUTPUT_SUBPIXEL_NONE;
1280 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1281 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1282 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1283 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1284 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1285 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1286 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1287 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1288 }
1289}
1290
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001291/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001292static uint32_t
1293drm_get_backlight(struct drm_output *output)
1294{
1295 long brightness, max_brightness, norm;
1296
1297 brightness = backlight_get_brightness(output->backlight);
1298 max_brightness = backlight_get_max_brightness(output->backlight);
1299
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001300 /* convert it on a scale of 0 to 255 */
1301 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001302
1303 return (uint32_t) norm;
1304}
1305
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001306/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001307static void
1308drm_set_backlight(struct weston_output *output_base, uint32_t value)
1309{
1310 struct drm_output *output = (struct drm_output *) output_base;
1311 long max_brightness, new_brightness;
1312
1313 if (!output->backlight)
1314 return;
1315
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001316 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001317 return;
1318
1319 max_brightness = backlight_get_max_brightness(output->backlight);
1320
1321 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001322 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001323
1324 backlight_set_brightness(output->backlight, new_brightness);
1325}
1326
1327static drmModePropertyPtr
1328drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1329{
1330 drmModePropertyPtr props;
1331 int i;
1332
1333 for (i = 0; i < connector->count_props; i++) {
1334 props = drmModeGetProperty(fd, connector->props[i]);
1335 if (!props)
1336 continue;
1337
1338 if (!strcmp(props->name, name))
1339 return props;
1340
1341 drmModeFreeProperty(props);
1342 }
1343
1344 return NULL;
1345}
1346
1347static void
1348drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1349{
1350 struct drm_output *output = (struct drm_output *) output_base;
1351 struct weston_compositor *ec = output_base->compositor;
1352 struct drm_compositor *c = (struct drm_compositor *) ec;
1353 drmModeConnectorPtr connector;
1354 drmModePropertyPtr prop;
1355
1356 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1357 if (!connector)
1358 return;
1359
1360 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1361 if (!prop) {
1362 drmModeFreeConnector(connector);
1363 return;
1364 }
1365
1366 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1367 prop->prop_id, level);
1368 drmModeFreeProperty(prop);
1369 drmModeFreeConnector(connector);
1370}
1371
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001372static const char *connector_type_names[] = {
1373 "None",
1374 "VGA",
1375 "DVI",
1376 "DVI",
1377 "DVI",
1378 "Composite",
1379 "TV",
1380 "LVDS",
1381 "CTV",
1382 "DIN",
1383 "DP",
1384 "HDMI",
1385 "HDMI",
1386 "TV",
1387 "eDP",
1388};
1389
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001390static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001391find_crtc_for_connector(struct drm_compositor *ec,
1392 drmModeRes *resources, drmModeConnector *connector)
1393{
1394 drmModeEncoder *encoder;
1395 uint32_t possible_crtcs;
1396 int i, j;
1397
1398 for (j = 0; j < connector->count_encoders; j++) {
1399 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1400 if (encoder == NULL) {
1401 weston_log("Failed to get encoder.\n");
1402 return -1;
1403 }
1404 possible_crtcs = encoder->possible_crtcs;
1405 drmModeFreeEncoder(encoder);
1406
1407 for (i = 0; i < resources->count_crtcs; i++) {
1408 if (possible_crtcs & (1 << i) &&
1409 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1410 return i;
1411 }
1412 }
1413
1414 return -1;
1415}
1416
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001417/* Init output state that depends on gl or gbm */
1418static int
1419drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1420{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001421 int i, flags;
1422
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001423 output->surface = gbm_surface_create(ec->gbm,
1424 output->base.current->width,
1425 output->base.current->height,
1426 GBM_FORMAT_XRGB8888,
1427 GBM_BO_USE_SCANOUT |
1428 GBM_BO_USE_RENDERING);
1429 if (!output->surface) {
1430 weston_log("failed to create gbm surface\n");
1431 return -1;
1432 }
1433
1434 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001435 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001436 gbm_surface_destroy(output->surface);
1437 return -1;
1438 }
1439
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001440 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1441
1442 for (i = 0; i < 2; i++) {
1443 if (output->cursor_bo[i])
1444 continue;
1445
1446 output->cursor_bo[i] =
1447 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1448 flags);
1449 }
1450
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001451 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1452 weston_log("cursor buffers unavailable, using gl cursors\n");
1453 ec->cursors_are_broken = 1;
1454 }
1455
1456 return 0;
1457}
1458
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001459static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001460drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1461{
1462 int w = output->base.current->width;
1463 int h = output->base.current->height;
1464 unsigned int i;
1465
1466 /* FIXME error checking */
1467
1468 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1469 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1470 if (!output->dumb[i])
1471 goto err;
1472
1473 output->image[i] =
1474 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1475 output->dumb[i]->map,
1476 output->dumb[i]->stride);
1477 if (!output->image[i])
1478 goto err;
1479 }
1480
1481 if (pixman_renderer_output_create(&output->base) < 0)
1482 goto err;
1483
1484 pixman_region32_init_rect(&output->previous_damage,
1485 output->base.x, output->base.y, w, h);
1486
1487 return 0;
1488
1489err:
1490 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1491 if (output->dumb[i])
1492 drm_fb_destroy_dumb(output->dumb[i]);
1493 if (output->image[i])
1494 pixman_image_unref(output->image[i]);
1495
1496 output->dumb[i] = NULL;
1497 output->image[i] = NULL;
1498 }
1499
1500 return -1;
1501}
1502
1503static void
1504drm_output_fini_pixman(struct drm_output *output)
1505{
1506 unsigned int i;
1507
1508 pixman_renderer_output_destroy(&output->base);
1509 pixman_region32_fini(&output->previous_damage);
1510
1511 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1512 drm_fb_destroy_dumb(output->dumb[i]);
1513 pixman_image_unref(output->image[i]);
1514 output->dumb[i] = NULL;
1515 output->image[i] = NULL;
1516 }
1517}
1518
Richard Hughes2b2092a2013-04-24 14:58:02 +01001519static void
1520edid_parse_string(const uint8_t *data, char text[])
1521{
1522 int i;
1523 int replaced = 0;
1524
1525 /* this is always 12 bytes, but we can't guarantee it's null
1526 * terminated or not junk. */
1527 strncpy(text, (const char *) data, 12);
1528
1529 /* remove insane chars */
1530 for (i = 0; text[i] != '\0'; i++) {
1531 if (text[i] == '\n' ||
1532 text[i] == '\r') {
1533 text[i] = '\0';
1534 break;
1535 }
1536 }
1537
1538 /* ensure string is printable */
1539 for (i = 0; text[i] != '\0'; i++) {
1540 if (!isprint(text[i])) {
1541 text[i] = '-';
1542 replaced++;
1543 }
1544 }
1545
1546 /* if the string is random junk, ignore the string */
1547 if (replaced > 4)
1548 text[0] = '\0';
1549}
1550
1551#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1552#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1553#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1554#define EDID_OFFSET_DATA_BLOCKS 0x36
1555#define EDID_OFFSET_LAST_BLOCK 0x6c
1556#define EDID_OFFSET_PNPID 0x08
1557#define EDID_OFFSET_SERIAL 0x0c
1558
1559static int
1560edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1561{
1562 int i;
1563 uint32_t serial_number;
1564
1565 /* check header */
1566 if (length < 128)
1567 return -1;
1568 if (data[0] != 0x00 || data[1] != 0xff)
1569 return -1;
1570
1571 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1572 * /--08--\/--09--\
1573 * 7654321076543210
1574 * |\---/\---/\---/
1575 * R C1 C2 C3 */
1576 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1577 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1578 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1579 edid->pnp_id[3] = '\0';
1580
1581 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1582 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1583 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1584 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1585 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1586 if (serial_number > 0)
1587 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1588
1589 /* parse EDID data */
1590 for (i = EDID_OFFSET_DATA_BLOCKS;
1591 i <= EDID_OFFSET_LAST_BLOCK;
1592 i += 18) {
1593 /* ignore pixel clock data */
1594 if (data[i] != 0)
1595 continue;
1596 if (data[i+2] != 0)
1597 continue;
1598
1599 /* any useful blocks? */
1600 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1601 edid_parse_string(&data[i+5],
1602 edid->monitor_name);
1603 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1604 edid_parse_string(&data[i+5],
1605 edid->serial_number);
1606 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1607 edid_parse_string(&data[i+5],
1608 edid->eisa_id);
1609 }
1610 }
1611 return 0;
1612}
1613
1614static void
1615find_and_parse_output_edid(struct drm_compositor *ec,
1616 struct drm_output *output,
1617 drmModeConnector *connector)
1618{
1619 drmModePropertyBlobPtr edid_blob = NULL;
1620 drmModePropertyPtr property;
1621 int i;
1622 int rc;
1623
1624 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1625 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1626 if (!property)
1627 continue;
1628 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1629 !strcmp(property->name, "EDID")) {
1630 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1631 connector->prop_values[i]);
1632 }
1633 drmModeFreeProperty(property);
1634 }
1635 if (!edid_blob)
1636 return;
1637
1638 rc = edid_parse(&output->edid,
1639 edid_blob->data,
1640 edid_blob->length);
1641 if (!rc) {
1642 weston_log("EDID data '%s', '%s', '%s'\n",
1643 output->edid.pnp_id,
1644 output->edid.monitor_name,
1645 output->edid.serial_number);
1646 if (output->edid.pnp_id[0] != '\0')
1647 output->base.make = output->edid.pnp_id;
1648 if (output->edid.monitor_name[0] != '\0')
1649 output->base.model = output->edid.monitor_name;
1650 if (output->edid.serial_number[0] != '\0')
1651 output->base.serial_number = output->edid.serial_number;
1652 }
1653 drmModeFreePropertyBlob(edid_blob);
1654}
1655
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001656static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001657create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001658 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001659 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001660 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001661{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001662 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001663 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1664 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001665 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001666 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001667 drmModeModeInfo crtc_mode;
1668 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001669 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001670 char name[32];
1671 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001672
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001673 i = find_crtc_for_connector(ec, resources, connector);
1674 if (i < 0) {
1675 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001676 return -1;
1677 }
1678
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001679 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001680 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001681 return -1;
1682
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001683 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001684 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1685 output->base.make = "unknown";
1686 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001687 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001688 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001689
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001690 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1691 type_name = connector_type_names[connector->connector_type];
1692 else
1693 type_name = "UNKNOWN";
1694 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1695 output->name = strdup(name);
1696
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001697 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001698 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001699 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001700 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001701 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001702
Matt Roper361d2ad2011-08-29 13:52:23 -07001703 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1704
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001705 /* Get the current mode on the crtc that's currently driving
1706 * this connector. */
1707 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001708 memset(&crtc_mode, 0, sizeof crtc_mode);
1709 if (encoder != NULL) {
1710 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1711 drmModeFreeEncoder(encoder);
1712 if (crtc == NULL)
1713 goto err_free;
1714 if (crtc->mode_valid)
1715 crtc_mode = crtc->mode;
1716 drmModeFreeCrtc(crtc);
1717 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001718
David Herrmann0f0d54e2011-12-08 17:05:45 +01001719 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001720 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1721 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001722 goto err_free;
1723 }
1724
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001725 preferred = NULL;
1726 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001727 configured = NULL;
1728
1729 wl_list_for_each(temp, &configured_output_list, link) {
1730 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001731 if (temp->mode)
1732 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001733 temp->name, temp->mode);
1734 o = temp;
1735 break;
1736 }
1737 }
1738
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001739 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001740 weston_log("Disabling output %s\n", o->name);
1741
1742 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1743 0, 0, 0, 0, 0, NULL);
1744 goto err_free;
1745 }
1746
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001747 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001748 if (o && o->config == OUTPUT_CONFIG_MODE &&
1749 o->width == drm_mode->base.width &&
1750 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001751 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001752 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001753 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001754 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001755 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001756 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001757
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001758 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001759 configured = drm_output_add_mode(output, &o->crtc_mode);
1760 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001761 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001762 current = configured;
1763 }
1764
Wang Quanxianacb805a2012-07-30 18:09:46 -04001765 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001766 current = drm_output_add_mode(output, &crtc_mode);
1767 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001768 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001769 }
1770
Scott Moreau8ab5d452012-07-30 19:51:08 -06001771 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1772 configured = current;
1773
Wang Quanxianacb805a2012-07-30 18:09:46 -04001774 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001775 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001776 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001777 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001778 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001779 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001780 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001781 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001782
1783 if (output->base.current == NULL) {
1784 weston_log("no available modes for %s\n", output->name);
1785 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001786 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001787
Wang Quanxianacb805a2012-07-30 18:09:46 -04001788 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1789
John Kåre Alsaker94659272012-11-13 19:10:18 +01001790 weston_output_init(&output->base, &ec->base, x, y,
1791 connector->mmWidth, connector->mmHeight,
1792 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1793
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001794 if (ec->use_pixman) {
1795 if (drm_output_init_pixman(output, ec) < 0) {
1796 weston_log("Failed to init output pixman state\n");
1797 goto err_output;
1798 }
1799 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001800 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001801 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001802 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001803
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001804 output->backlight = backlight_init(drm_device,
1805 connector->connector_type);
1806 if (output->backlight) {
1807 output->base.set_backlight = drm_set_backlight;
1808 output->base.backlight_current = drm_get_backlight(output);
1809 }
1810
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001811 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1812
Richard Hughes2b2092a2013-04-24 14:58:02 +01001813 find_and_parse_output_edid(ec, output, connector);
1814
Alex Wubd3354b2012-04-17 17:20:49 +08001815 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001816 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001817 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001818 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001819 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001820 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001821 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001822
Richard Hughese7299962013-05-01 21:52:12 +01001823 output->base.gamma_size = output->original_crtc->gamma_size;
1824 output->base.set_gamma = drm_output_set_gamma;
1825
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001826 weston_plane_init(&output->cursor_plane, 0, 0);
1827 weston_plane_init(&output->fb_plane, 0, 0);
1828
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001829 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1830 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1831 &ec->base.primary_plane);
1832
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001833 weston_log("Output %s, (connector %d, crtc %d)\n",
1834 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001835 wl_list_for_each(m, &output->base.mode_list, link)
1836 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1837 m->width, m->height, m->refresh / 1000.0,
1838 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1839 ", preferred" : "",
1840 m->flags & WL_OUTPUT_MODE_CURRENT ?
1841 ", current" : "",
1842 connector->count_modes == 0 ?
1843 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001844
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001845 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001846
John Kåre Alsaker94659272012-11-13 19:10:18 +01001847err_output:
1848 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001849err_free:
1850 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1851 base.link) {
1852 wl_list_remove(&drm_mode->base.link);
1853 free(drm_mode);
1854 }
1855
1856 drmModeFreeCrtc(output->original_crtc);
1857 ec->crtc_allocator &= ~(1 << output->crtc_id);
1858 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001859 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001860 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001861
David Herrmann0f0d54e2011-12-08 17:05:45 +01001862 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001863}
1864
Jesse Barnes58ef3792012-02-23 09:45:49 -05001865static void
1866create_sprites(struct drm_compositor *ec)
1867{
1868 struct drm_sprite *sprite;
1869 drmModePlaneRes *plane_res;
1870 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001871 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001872
1873 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1874 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001875 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001876 strerror(errno));
1877 return;
1878 }
1879
1880 for (i = 0; i < plane_res->count_planes; i++) {
1881 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1882 if (!plane)
1883 continue;
1884
1885 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1886 plane->count_formats));
1887 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001888 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001889 __func__);
1890 free(plane);
1891 continue;
1892 }
1893
1894 memset(sprite, 0, sizeof *sprite);
1895
1896 sprite->possible_crtcs = plane->possible_crtcs;
1897 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001898 sprite->current = NULL;
1899 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001900 sprite->compositor = ec;
1901 sprite->count_formats = plane->count_formats;
1902 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001903 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001904 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001905 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001906 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1907 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001908
1909 wl_list_insert(&ec->sprite_list, &sprite->link);
1910 }
1911
1912 free(plane_res->planes);
1913 free(plane_res);
1914}
1915
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001916static void
1917destroy_sprites(struct drm_compositor *compositor)
1918{
1919 struct drm_sprite *sprite, *next;
1920 struct drm_output *output;
1921
1922 output = container_of(compositor->base.output_list.next,
1923 struct drm_output, base.link);
1924
1925 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1926 drmModeSetPlane(compositor->drm.fd,
1927 sprite->plane_id,
1928 output->crtc_id, 0, 0,
1929 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001930 drm_output_release_fb(output, sprite->current);
1931 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001932 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001933 free(sprite);
1934 }
1935}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001936
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001937static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001938create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001939 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001940{
1941 drmModeConnector *connector;
1942 drmModeRes *resources;
1943 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001944 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001945
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001946 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001947 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001948 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001949 return -1;
1950 }
1951
Jesse Barnes58ef3792012-02-23 09:45:49 -05001952 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001953 if (!ec->crtcs) {
1954 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001955 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001956 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001957
Rob Clark4339add2012-08-09 14:18:28 -05001958 ec->min_width = resources->min_width;
1959 ec->max_width = resources->max_width;
1960 ec->min_height = resources->min_height;
1961 ec->max_height = resources->max_height;
1962
Jesse Barnes58ef3792012-02-23 09:45:49 -05001963 ec->num_crtcs = resources->count_crtcs;
1964 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1965
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001966 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001967 connector = drmModeGetConnector(ec->drm.fd,
1968 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001969 if (connector == NULL)
1970 continue;
1971
1972 if (connector->connection == DRM_MODE_CONNECTED &&
1973 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001974 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001975 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001976 connector, x, y,
1977 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001978 drmModeFreeConnector(connector);
1979 continue;
1980 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001981
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001982 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001983 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001984 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001985 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001986
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001987 drmModeFreeConnector(connector);
1988 }
1989
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001990 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001991 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001992 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001993 return -1;
1994 }
1995
1996 drmModeFreeResources(resources);
1997
1998 return 0;
1999}
2000
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002001static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002002update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002003{
2004 drmModeConnector *connector;
2005 drmModeRes *resources;
2006 struct drm_output *output, *next;
2007 int x = 0, y = 0;
2008 int x_offset = 0, y_offset = 0;
2009 uint32_t connected = 0, disconnects = 0;
2010 int i;
2011
2012 resources = drmModeGetResources(ec->drm.fd);
2013 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002014 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002015 return;
2016 }
2017
2018 /* collect new connects */
2019 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002020 int connector_id = resources->connectors[i];
2021
2022 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002023 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002024 continue;
2025
David Herrmann7551cff2011-12-08 17:05:43 +01002026 if (connector->connection != DRM_MODE_CONNECTED) {
2027 drmModeFreeConnector(connector);
2028 continue;
2029 }
2030
Benjamin Franzke117483d2011-08-30 11:38:26 +02002031 connected |= (1 << connector_id);
2032
2033 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002034 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002035 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002036 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002037
2038 /* XXX: not yet needed, we die with 0 outputs */
2039 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002040 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002041 else
2042 x = 0;
2043 y = 0;
2044 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002045 connector, x, y,
2046 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002047 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002048
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002049 }
2050 drmModeFreeConnector(connector);
2051 }
2052 drmModeFreeResources(resources);
2053
2054 disconnects = ec->connector_allocator & ~connected;
2055 if (disconnects) {
2056 wl_list_for_each_safe(output, next, &ec->base.output_list,
2057 base.link) {
2058 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002059 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002060 output->base.x - x_offset,
2061 output->base.y - y_offset);
2062 }
2063
2064 if (disconnects & (1 << output->connector_id)) {
2065 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002066 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002067 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002068 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002069 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002070 }
2071 }
2072 }
2073
2074 /* FIXME: handle zero outputs, without terminating */
2075 if (ec->connector_allocator == 0)
2076 wl_display_terminate(ec->base.wl_display);
2077}
2078
2079static int
David Herrmannd7488c22012-03-11 20:05:21 +01002080udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002081{
David Herrmannd7488c22012-03-11 20:05:21 +01002082 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002083 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002084
2085 sysnum = udev_device_get_sysnum(device);
2086 if (!sysnum || atoi(sysnum) != ec->drm.id)
2087 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002088
David Herrmann6ac52db2012-03-11 20:05:22 +01002089 val = udev_device_get_property_value(device, "HOTPLUG");
2090 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002091 return 0;
2092
David Herrmann6ac52db2012-03-11 20:05:22 +01002093 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002094}
2095
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002096static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002097udev_drm_event(int fd, uint32_t mask, void *data)
2098{
2099 struct drm_compositor *ec = data;
2100 struct udev_device *event;
2101
2102 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002103
David Herrmannd7488c22012-03-11 20:05:21 +01002104 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002105 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002106
2107 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002108
2109 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002110}
2111
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002112static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002113drm_restore(struct weston_compositor *ec)
2114{
2115 struct drm_compositor *d = (struct drm_compositor *) ec;
2116
2117 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2118 weston_log("failed to drop master: %m\n");
2119 tty_reset(d->tty);
2120}
2121
2122static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002123drm_free_configured_output(struct drm_configured_output *output)
2124{
2125 free(output->name);
2126 free(output->mode);
2127 free(output);
2128}
2129
2130static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002131drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002132{
2133 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002134 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002135 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002136
Kristian Høgsberge8091032013-02-18 15:43:29 -05002137 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2138 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002139 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002140 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002141
2142 wl_event_source_remove(d->udev_drm_source);
2143 wl_event_source_remove(d->drm_source);
2144
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002145 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002146
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002147 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002148
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002149 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002150
2151 if (d->gbm)
2152 gbm_device_destroy(d->gbm);
2153
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002154 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002155 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002156 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002157
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002158 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002159}
2160
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002161static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002162drm_compositor_set_modes(struct drm_compositor *compositor)
2163{
2164 struct drm_output *output;
2165 struct drm_mode *drm_mode;
2166 int ret;
2167
2168 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002169 if (!output->current) {
2170 /* If something that would cause the output to
2171 * switch mode happened while in another vt, we
2172 * might not have a current drm_fb. In that case,
2173 * schedule a repaint and let drm_output_repaint
2174 * handle setting the mode. */
2175 weston_output_schedule_repaint(&output->base);
2176 continue;
2177 }
2178
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002179 drm_mode = (struct drm_mode *) output->base.current;
2180 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002181 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002182 &output->connector_id, 1,
2183 &drm_mode->mode_info);
2184 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002185 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002186 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002187 drm_mode->base.width, drm_mode->base.height,
2188 output->base.x, output->base.y);
2189 }
2190 }
2191}
2192
2193static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002194vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002195{
2196 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002197 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002198 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002199 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002200
2201 switch (event) {
2202 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002203 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002204 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002205 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002206 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002207 wl_display_terminate(compositor->wl_display);
2208 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002209 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002210 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002211 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002212 wl_list_for_each(seat, &compositor->seat_list, base.link)
2213 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002214 break;
2215 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002216 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002217 wl_list_for_each(seat, &compositor->seat_list, base.link)
2218 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002219
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002220 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002221 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002222 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002223
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002224 /* If we have a repaint scheduled (either from a
2225 * pending pageflip or the idle handler), make sure we
2226 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002227 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002228 * further attemps at repainting. When we switch
2229 * back, we schedule a repaint, which will process
2230 * pending frame callbacks. */
2231
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002232 wl_list_for_each(output, &ec->base.output_list, base.link) {
2233 output->base.repaint_needed = 0;
2234 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002235 }
2236
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002237 output = container_of(ec->base.output_list.next,
2238 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002239
2240 wl_list_for_each(sprite, &ec->sprite_list, link)
2241 drmModeSetPlane(ec->drm.fd,
2242 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002243 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002244 0, 0, 0, 0, 0, 0, 0, 0);
2245
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002246 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002247 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002248
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002249 break;
2250 };
2251}
2252
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002253static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002254switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002255{
2256 struct drm_compositor *ec = data;
2257
Daniel Stone325fc2d2012-05-30 16:31:58 +01002258 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002259}
2260
David Herrmann0af066f2012-10-29 19:21:16 +01002261/*
2262 * Find primary GPU
2263 * Some systems may have multiple DRM devices attached to a single seat. This
2264 * function loops over all devices and tries to find a PCI device with the
2265 * boot_vga sysfs attribute set to 1.
2266 * If no such device is found, the first DRM device reported by udev is used.
2267 */
2268static struct udev_device*
2269find_primary_gpu(struct drm_compositor *ec, const char *seat)
2270{
2271 struct udev_enumerate *e;
2272 struct udev_list_entry *entry;
2273 const char *path, *device_seat, *id;
2274 struct udev_device *device, *drm_device, *pci;
2275
2276 e = udev_enumerate_new(ec->udev);
2277 udev_enumerate_add_match_subsystem(e, "drm");
2278 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2279
2280 udev_enumerate_scan_devices(e);
2281 drm_device = NULL;
2282 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2283 path = udev_list_entry_get_name(entry);
2284 device = udev_device_new_from_syspath(ec->udev, path);
2285 if (!device)
2286 continue;
2287 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2288 if (!device_seat)
2289 device_seat = default_seat;
2290 if (strcmp(device_seat, seat)) {
2291 udev_device_unref(device);
2292 continue;
2293 }
2294
2295 pci = udev_device_get_parent_with_subsystem_devtype(device,
2296 "pci", NULL);
2297 if (pci) {
2298 id = udev_device_get_sysattr_value(pci, "boot_vga");
2299 if (id && !strcmp(id, "1")) {
2300 if (drm_device)
2301 udev_device_unref(drm_device);
2302 drm_device = device;
2303 break;
2304 }
2305 }
2306
2307 if (!drm_device)
2308 drm_device = device;
2309 else
2310 udev_device_unref(device);
2311 }
2312
2313 udev_enumerate_unref(e);
2314 return drm_device;
2315}
2316
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002317static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002318planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002319{
2320 struct drm_compositor *c = data;
2321
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002322 switch (key) {
2323 case KEY_C:
2324 c->cursors_are_broken ^= 1;
2325 break;
2326 case KEY_V:
2327 c->sprites_are_broken ^= 1;
2328 break;
2329 case KEY_O:
2330 c->sprites_hidden ^= 1;
2331 break;
2332 default:
2333 break;
2334 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002335}
2336
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002337static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002338drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002339 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002340 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002341{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002342 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002343 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002344 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002345 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002346 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002347 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002348
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002349 weston_log("initializing drm backend\n");
2350
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002351 ec = malloc(sizeof *ec);
2352 if (ec == NULL)
2353 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002354 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002355
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002356 /* KMS support for sprites is not complete yet, so disable the
2357 * functionality for now. */
2358 ec->sprites_are_broken = 1;
2359
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002360 ec->use_pixman = pixman;
2361
Daniel Stone725c2c32012-06-22 14:04:36 +01002362 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002363 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002364 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002365 goto err_base;
2366 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002367
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002368 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002369 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002370 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002371 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002372 goto err_compositor;
2373 }
2374
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002375 ec->udev = udev_new();
2376 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002377 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002378 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002379 }
2380
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002381 ec->base.wl_display = display;
2382 ec->tty = tty_create(&ec->base, vt_func, tty);
2383 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002384 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002385 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002386 }
2387
David Herrmann0af066f2012-10-29 19:21:16 +01002388 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002389 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002390 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002391 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002392 }
David Herrmann0af066f2012-10-29 19:21:16 +01002393 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002394
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002395 if (init_drm(ec, drm_device) < 0) {
2396 weston_log("failed to initialize kms\n");
2397 goto err_udev_dev;
2398 }
2399
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002400 if (ec->use_pixman) {
2401 if (init_pixman(ec) < 0) {
2402 weston_log("failed to initialize pixman renderer\n");
2403 goto err_udev_dev;
2404 }
2405 } else {
2406 if (init_egl(ec) < 0) {
2407 weston_log("failed to initialize egl\n");
2408 goto err_udev_dev;
2409 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002410 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002411
2412 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002413 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002414
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002415 ec->base.focus = 1;
2416
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002417 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002418
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002419 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002420 weston_compositor_add_key_binding(&ec->base, key,
2421 MODIFIER_CTRL | MODIFIER_ALT,
2422 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002423
Jesse Barnes58ef3792012-02-23 09:45:49 -05002424 wl_list_init(&ec->sprite_list);
2425 create_sprites(ec);
2426
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002427 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002428 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002429 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002430 }
2431
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002432 path = NULL;
2433
Kristian Høgsberge8091032013-02-18 15:43:29 -05002434 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002435 weston_log("failed to create input devices\n");
2436 goto err_sprite;
2437 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002438
2439 loop = wl_display_get_event_loop(ec->base.wl_display);
2440 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002441 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002442 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002443
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002444 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2445 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002446 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002447 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002448 }
2449 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2450 "drm", NULL);
2451 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002452 wl_event_loop_add_fd(loop,
2453 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002454 WL_EVENT_READABLE, udev_drm_event, ec);
2455
2456 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002457 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002458 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002459 }
2460
Daniel Stonea96b93c2012-06-22 14:04:37 +01002461 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002462
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002463 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002464 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002465 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002466 planes_binding, ec);
2467 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2468 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002469
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002470 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002471
2472err_udev_monitor:
2473 wl_event_source_remove(ec->udev_drm_source);
2474 udev_monitor_unref(ec->udev_monitor);
2475err_drm_source:
2476 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002477 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2478 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002479err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002480 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002481 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002482 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002483err_udev_dev:
2484 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002485err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002486 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2487 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002488 tty_destroy(ec->tty);
2489err_udev:
2490 udev_unref(ec->udev);
2491err_compositor:
2492 weston_compositor_shutdown(&ec->base);
2493err_base:
2494 free(ec);
2495 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002496}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002497
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002498static int
2499set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2500{
2501 mode->flags = 0;
2502
2503 if (strcmp(hsync, "+hsync") == 0)
2504 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2505 else if (strcmp(hsync, "-hsync") == 0)
2506 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2507 else
2508 return -1;
2509
2510 if (strcmp(vsync, "+vsync") == 0)
2511 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2512 else if (strcmp(vsync, "-vsync") == 0)
2513 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2514 else
2515 return -1;
2516
2517 return 0;
2518}
2519
2520static int
2521check_for_modeline(struct drm_configured_output *output)
2522{
2523 drmModeModeInfo mode;
2524 char hsync[16];
2525 char vsync[16];
2526 char mode_name[16];
2527 float fclock;
2528
2529 mode.type = DRM_MODE_TYPE_USERDEF;
2530 mode.hskew = 0;
2531 mode.vscan = 0;
2532 mode.vrefresh = 0;
2533
2534 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2535 &fclock, &mode.hdisplay,
2536 &mode.hsync_start,
2537 &mode.hsync_end, &mode.htotal,
2538 &mode.vdisplay,
2539 &mode.vsync_start,
2540 &mode.vsync_end, &mode.vtotal,
2541 hsync, vsync) == 11) {
2542 if (set_sync_flags(&mode, hsync, vsync))
2543 return -1;
2544
2545 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2546 strcpy(mode.name, mode_name);
2547
2548 mode.clock = fclock * 1000;
2549 } else
2550 return -1;
2551
2552 output->crtc_mode = mode;
2553
2554 return 0;
2555}
2556
Scott Moreau8ab5d452012-07-30 19:51:08 -06002557static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002558drm_output_set_transform(struct drm_configured_output *output)
2559{
2560 if (!output_transform) {
2561 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2562 return;
2563 }
2564
2565 if (!strcmp(output_transform, "normal"))
2566 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2567 else if (!strcmp(output_transform, "90"))
2568 output->transform = WL_OUTPUT_TRANSFORM_90;
2569 else if (!strcmp(output_transform, "180"))
2570 output->transform = WL_OUTPUT_TRANSFORM_180;
2571 else if (!strcmp(output_transform, "270"))
2572 output->transform = WL_OUTPUT_TRANSFORM_270;
2573 else if (!strcmp(output_transform, "flipped"))
2574 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2575 else if (!strcmp(output_transform, "flipped-90"))
2576 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2577 else if (!strcmp(output_transform, "flipped-180"))
2578 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2579 else if (!strcmp(output_transform, "flipped-270"))
2580 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2581 else {
2582 weston_log("Invalid transform \"%s\" for output %s\n",
2583 output_transform, output_name);
2584 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2585 }
2586
2587 free(output_transform);
2588 output_transform = NULL;
2589}
2590
2591static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002592output_section_done(void *data)
2593{
2594 struct drm_configured_output *output;
2595
2596 output = malloc(sizeof *output);
2597
Scott Moreau1bad5db2012-08-18 01:04:05 -06002598 if (!output || !output_name || (output_name[0] == 'X') ||
2599 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002600 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002601 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002602 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002603 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002604 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002605 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002606 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002607 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002608 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002609
2610 output->config = OUTPUT_CONFIG_INVALID;
2611 output->name = output_name;
2612 output->mode = output_mode;
2613
Scott Moreau1bad5db2012-08-18 01:04:05 -06002614 if (output_mode) {
2615 if (strcmp(output_mode, "off") == 0)
2616 output->config = OUTPUT_CONFIG_OFF;
2617 else if (strcmp(output_mode, "preferred") == 0)
2618 output->config = OUTPUT_CONFIG_PREFERRED;
2619 else if (strcmp(output_mode, "current") == 0)
2620 output->config = OUTPUT_CONFIG_CURRENT;
2621 else if (sscanf(output_mode, "%dx%d",
2622 &output->width, &output->height) == 2)
2623 output->config = OUTPUT_CONFIG_MODE;
2624 else if (check_for_modeline(output) == 0)
2625 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002626
Scott Moreau1bad5db2012-08-18 01:04:05 -06002627 if (output->config == OUTPUT_CONFIG_INVALID)
2628 weston_log("Invalid mode \"%s\" for output %s\n",
2629 output_mode, output_name);
2630 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002631 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002632
2633 drm_output_set_transform(output);
2634
2635 wl_list_insert(&configured_output_list, &output->link);
2636
2637 if (output_transform)
2638 free(output_transform);
2639 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002640}
2641
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002642WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002643backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002644 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002645{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002646 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002647 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002648
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002649 const struct weston_option drm_options[] = {
2650 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2651 { WESTON_OPTION_STRING, "seat", 0, &seat },
2652 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002653 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002654 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002655 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002656
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002657 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002658
Scott Moreau8ab5d452012-07-30 19:51:08 -06002659 wl_list_init(&configured_output_list);
2660
2661 const struct config_key drm_config_keys[] = {
2662 { "name", CONFIG_KEY_STRING, &output_name },
2663 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002664 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002665 };
2666
2667 const struct config_section config_section[] = {
2668 { "output", drm_config_keys,
2669 ARRAY_LENGTH(drm_config_keys), output_section_done },
2670 };
2671
2672 parse_config_file(config_file, config_section,
2673 ARRAY_LENGTH(config_section), NULL);
2674
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002675 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2676 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002677}