blob: c8016cd3fcee50ee0811540182b20d73d096bc8b [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
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500548drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400549 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100550{
551 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500552 struct drm_compositor *compositor =
553 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500554 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400555 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500556 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100557
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300558 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400559 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300560 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400561 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100562
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400563 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300564 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400565 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300566 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400567 &output->connector_id, 1,
568 &mode->mode_info);
569 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200570 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400571 return;
572 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200573 }
574
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500575 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300576 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500577 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200578 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500579 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500580 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100581
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300582 output->page_flip_pending = 1;
583
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400584 drm_output_set_cursor(output);
585
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 /*
587 * Now, update all the sprite surfaces
588 */
589 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200590 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500591 drmVBlank vbl = {
592 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
593 .request.sequence = 1,
594 };
595
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200596 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200597 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500598 continue;
599
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200600 if (s->next && !compositor->sprites_hidden)
601 fb_id = s->next->fb_id;
602
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200604 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 s->dest_x, s->dest_y,
606 s->dest_w, s->dest_h,
607 s->src_x, s->src_y,
608 s->src_w, s->src_h);
609 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200610 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611 ret, strerror(errno));
612
Rob Clark5ca1a472012-08-08 20:27:37 -0500613 if (output->pipe > 0)
614 vbl.request.type |= DRM_VBLANK_SECONDARY;
615
Jesse Barnes58ef3792012-02-23 09:45:49 -0500616 /*
617 * Queue a vblank signal so we know when the surface
618 * becomes active on the display or has been replaced.
619 */
620 vbl.request.signal = (unsigned long)s;
621 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
622 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200623 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 ret, strerror(errno));
625 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300626
627 s->output = output;
628 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629 }
630
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500631 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400632}
633
634static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200635drm_output_start_repaint_loop(struct weston_output *output_base)
636{
637 struct drm_output *output = (struct drm_output *) output_base;
638 struct drm_compositor *compositor = (struct drm_compositor *)
639 output_base->compositor;
640 uint32_t fb_id;
641
642 if (output->current)
643 fb_id = output->current->fb_id;
644 else
645 fb_id = output->original_crtc->buffer_id;
646
647 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
648 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
649 weston_log("queueing pageflip failed: %m\n");
650 return;
651 }
652}
653
654static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
656 void *data)
657{
658 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300659 struct drm_output *output = s->output;
660 uint32_t msecs;
661
662 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200664 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200665 s->current = s->next;
666 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300667
668 if (!output->page_flip_pending) {
669 msecs = sec * 1000 + usec / 1000;
670 weston_output_finish_frame(&output->base, msecs);
671 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500672}
673
674static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400675page_flip_handler(int fd, unsigned int frame,
676 unsigned int sec, unsigned int usec, void *data)
677{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200678 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400679 uint32_t msecs;
680
Jonas Ådahle5a12252013-04-05 23:07:11 +0200681 /* We don't set page_flip_pending on start_repaint_loop, in that case
682 * we just want to page flip to the current buffer to get an accurate
683 * timestamp */
684 if (output->page_flip_pending) {
685 drm_output_release_fb(output, output->current);
686 output->current = output->next;
687 output->next = NULL;
688 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300689
Jonas Ådahle5a12252013-04-05 23:07:11 +0200690 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400691
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300692 if (!output->vblank_pending) {
693 msecs = sec * 1000 + usec / 1000;
694 weston_output_finish_frame(&output->base, msecs);
695 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200696}
697
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500698static uint32_t
699drm_output_check_sprite_format(struct drm_sprite *s,
700 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500701{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500702 uint32_t i, format;
703
704 format = gbm_bo_get_format(bo);
705
706 if (format == GBM_FORMAT_ARGB8888) {
707 pixman_region32_t r;
708
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500709 pixman_region32_init_rect(&r, 0, 0,
710 es->geometry.width,
711 es->geometry.height);
712 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500713
714 if (!pixman_region32_not_empty(&r))
715 format = GBM_FORMAT_XRGB8888;
716
717 pixman_region32_fini(&r);
718 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500719
720 for (i = 0; i < s->count_formats; i++)
721 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500722 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500723
724 return 0;
725}
726
727static int
728drm_surface_transform_supported(struct weston_surface *es)
729{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500730 return !es->transform.enabled ||
731 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500732}
733
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400734static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500735drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400736 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500737{
738 struct weston_compositor *ec = output_base->compositor;
739 struct drm_compositor *c =(struct drm_compositor *) ec;
740 struct drm_sprite *s;
741 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500742 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200744 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500745 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400746 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200748 if (c->gbm == NULL)
749 return NULL;
750
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200751 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200752 return NULL;
753
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500754 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400755 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500756
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300757 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400758 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300759
Pekka Paalanende685b82012-12-04 15:58:12 +0200760 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400761 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200763 if (es->alpha != 1.0f)
764 return NULL;
765
Pekka Paalanende685b82012-12-04 15:58:12 +0200766 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500767 return NULL;
768
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400770 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772 wl_list_for_each(s, &c->sprite_list, link) {
773 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
774 continue;
775
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200776 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500777 found = 1;
778 break;
779 }
780 }
781
782 /* No sprites available */
783 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400784 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400786 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200787 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400788 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400789 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400790
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500791 format = drm_output_check_sprite_format(s, es, bo);
792 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200793 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795 }
796
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200797 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200798 if (!s->next) {
799 gbm_bo_destroy(bo);
800 return NULL;
801 }
802
Pekka Paalanende685b82012-12-04 15:58:12 +0200803 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400805 box = pixman_region32_extents(&es->transform.boundingbox);
806 s->plane.x = box->x1;
807 s->plane.y = box->y1;
808
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809 /*
810 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200811 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812 * for us already).
813 */
814 pixman_region32_init(&dest_rect);
815 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
816 &output_base->region);
817 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
818 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200819 tbox = weston_transformed_rect(output_base->width,
820 output_base->height,
821 output_base->transform, *box);
822 s->dest_x = tbox.x1;
823 s->dest_y = tbox.y1;
824 s->dest_w = tbox.x2 - tbox.x1;
825 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500826 pixman_region32_fini(&dest_rect);
827
828 pixman_region32_init(&src_rect);
829 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
830 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400832
833 weston_surface_from_global_fixed(es,
834 wl_fixed_from_int(box->x1),
835 wl_fixed_from_int(box->y1),
836 &sx1, &sy1);
837 weston_surface_from_global_fixed(es,
838 wl_fixed_from_int(box->x2),
839 wl_fixed_from_int(box->y2),
840 &sx2, &sy2);
841
842 if (sx1 < 0)
843 sx1 = 0;
844 if (sy1 < 0)
845 sy1 = 0;
846 if (sx2 > wl_fixed_from_int(es->geometry.width))
847 sx2 = wl_fixed_from_int(es->geometry.width);
848 if (sy2 > wl_fixed_from_int(es->geometry.height))
849 sy2 = wl_fixed_from_int(es->geometry.height);
850
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200851 tbox.x1 = sx1;
852 tbox.y1 = sy1;
853 tbox.x2 = sx2;
854 tbox.y2 = sy2;
855
856 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
857 wl_fixed_from_int(es->geometry.height),
858 es->buffer_transform, tbox);
859
860 s->src_x = tbox.x1 << 8;
861 s->src_y = tbox.y1 << 8;
862 s->src_w = (tbox.x2 - tbox.x1) << 8;
863 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500864 pixman_region32_fini(&src_rect);
865
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400866 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500867}
868
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400869static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400870drm_output_prepare_cursor_surface(struct weston_output *output_base,
871 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500872{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400873 struct drm_compositor *c =
874 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400875 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400876
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200877 if (c->gbm == NULL)
878 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200879 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
880 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400881 if (output->cursor_surface)
882 return NULL;
883 if (es->output_mask != (1u << output_base->id))
884 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500885 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400886 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200887 if (es->buffer_ref.buffer == NULL ||
888 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400889 es->geometry.width > 64 || es->geometry.height > 64)
890 return NULL;
891
892 output->cursor_surface = es;
893
894 return &output->cursor_plane;
895}
896
897static void
898drm_output_set_cursor(struct drm_output *output)
899{
900 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400901 struct drm_compositor *c =
902 (struct drm_compositor *) output->base.compositor;
903 EGLint handle, stride;
904 struct gbm_bo *bo;
905 uint32_t buf[64 * 64];
906 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400907 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500908
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400909 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400910 if (es == NULL) {
911 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
912 return;
913 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500914
Pekka Paalanende685b82012-12-04 15:58:12 +0200915 if (es->buffer_ref.buffer &&
916 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400917 pixman_region32_fini(&output->cursor_plane.damage);
918 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400919 output->current_cursor ^= 1;
920 bo = output->cursor_bo[output->current_cursor];
921 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200922 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
923 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400924 for (i = 0; i < es->geometry.height; i++)
925 memcpy(buf + i * 64, s + i * stride,
926 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500927
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400928 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300929 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400930
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400931 handle = gbm_bo_get_handle(bo).s32;
932 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500933 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300934 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500935 c->cursors_are_broken = 1;
936 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400937 }
938
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400939 x = es->geometry.x - output->base.x;
940 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400941 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500942 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400943 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500944 c->cursors_are_broken = 1;
945 }
946
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400947 output->cursor_plane.x = x;
948 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400949 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500950}
951
Jesse Barnes58ef3792012-02-23 09:45:49 -0500952static void
953drm_assign_planes(struct weston_output *output)
954{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400955 struct drm_compositor *c =
956 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400957 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500958 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400959 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500960
961 /*
962 * Find a surface for each sprite in the output using some heuristics:
963 * 1) size
964 * 2) frequency of update
965 * 3) opacity (though some hw might support alpha blending)
966 * 4) clipping (this can be fixed with color keys)
967 *
968 * The idea is to save on blitting since this should save power.
969 * If we can get a large video surface on the sprite for example,
970 * the main display surface may not need to update at all, and
971 * the client buffer can be used directly for the sprite surface
972 * as we do for flipping full screen surfaces.
973 */
974 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400975 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400976 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200977 /* test whether this buffer can ever go into a plane:
978 * non-shm, or small enough to be a cursor
979 */
980 if ((es->buffer_ref.buffer &&
981 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
982 (es->geometry.width <= 64 && es->geometry.height <= 64))
983 es->keep_buffer = 1;
984 else
985 es->keep_buffer = 0;
986
Jesse Barnes58ef3792012-02-23 09:45:49 -0500987 pixman_region32_init(&surface_overlap);
988 pixman_region32_intersect(&surface_overlap, &overlap,
989 &es->transform.boundingbox);
990
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400991 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400992 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400993 next_plane = primary;
994 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400995 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400996 if (next_plane == NULL)
997 next_plane = drm_output_prepare_scanout_surface(output, es);
998 if (next_plane == NULL)
999 next_plane = drm_output_prepare_overlay_surface(output, es);
1000 if (next_plane == NULL)
1001 next_plane = primary;
1002 weston_surface_move_to_plane(es, next_plane);
1003 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001004 pixman_region32_union(&overlap, &overlap,
1005 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001006
Jesse Barnes58ef3792012-02-23 09:45:49 -05001007 pixman_region32_fini(&surface_overlap);
1008 }
1009 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001010}
1011
Matt Roper361d2ad2011-08-29 13:52:23 -07001012static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001013drm_output_fini_pixman(struct drm_output *output);
1014
1015static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001016drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001017{
1018 struct drm_output *output = (struct drm_output *) output_base;
1019 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001020 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001021 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001022
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001023 if (output->backlight)
1024 backlight_destroy(output->backlight);
1025
Matt Roper361d2ad2011-08-29 13:52:23 -07001026 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001027 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001028
1029 /* Restore original CRTC state */
1030 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001031 origcrtc->x, origcrtc->y,
1032 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001033 drmModeFreeCrtc(origcrtc);
1034
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001035 c->crtc_allocator &= ~(1 << output->crtc_id);
1036 c->connector_allocator &= ~(1 << output->connector_id);
1037
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001038 if (c->use_pixman) {
1039 drm_output_fini_pixman(output);
1040 } else {
1041 gl_renderer_output_destroy(output_base);
1042 gbm_surface_destroy(output->surface);
1043 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001044
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001045 weston_plane_release(&output->fb_plane);
1046 weston_plane_release(&output->cursor_plane);
1047
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001048 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001049 wl_list_remove(&output->base.link);
1050
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001051 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001052 free(output);
1053}
1054
Alex Wub7b8bda2012-04-17 17:20:48 +08001055static struct drm_mode *
1056choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1057{
1058 struct drm_mode *tmp_mode = NULL, *mode;
1059
1060 if (output->base.current->width == target_mode->width &&
1061 output->base.current->height == target_mode->height &&
1062 (output->base.current->refresh == target_mode->refresh ||
1063 target_mode->refresh == 0))
1064 return (struct drm_mode *)output->base.current;
1065
1066 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1067 if (mode->mode_info.hdisplay == target_mode->width &&
1068 mode->mode_info.vdisplay == target_mode->height) {
1069 if (mode->mode_info.vrefresh == target_mode->refresh ||
1070 target_mode->refresh == 0) {
1071 return mode;
1072 } else if (!tmp_mode)
1073 tmp_mode = mode;
1074 }
1075 }
1076
1077 return tmp_mode;
1078}
1079
1080static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001081drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001082static int
1083drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001084
1085static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001086drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1087{
1088 struct drm_output *output;
1089 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001090 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001091
1092 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001093 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001094 return -1;
1095 }
1096
1097 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001098 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001099 return -1;
1100 }
1101
1102 ec = (struct drm_compositor *)output_base->compositor;
1103 output = (struct drm_output *)output_base;
1104 drm_mode = choose_mode (output, mode);
1105
1106 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001107 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001108 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001109 }
1110
1111 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001112 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001113
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001114 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001115
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001116 output->base.current = &drm_mode->base;
1117 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001118 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1119
Alex Wub7b8bda2012-04-17 17:20:48 +08001120 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001121 drm_output_release_fb(output, output->current);
1122 drm_output_release_fb(output, output->next);
1123 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001124
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001125 if (ec->use_pixman) {
1126 drm_output_fini_pixman(output);
1127 if (drm_output_init_pixman(output, ec) < 0) {
1128 weston_log("failed to init output pixman state with "
1129 "new mode\n");
1130 return -1;
1131 }
1132 } else {
1133 gl_renderer_output_destroy(&output->base);
1134 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001135
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001136 if (drm_output_init_egl(output, ec) < 0) {
1137 weston_log("failed to init output egl state with "
1138 "new mode");
1139 return -1;
1140 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001141 }
1142
Alex Wub7b8bda2012-04-17 17:20:48 +08001143 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001144}
1145
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001146static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001147on_drm_input(int fd, uint32_t mask, void *data)
1148{
1149 drmEventContext evctx;
1150
1151 memset(&evctx, 0, sizeof evctx);
1152 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1153 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001154 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001155 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001156
1157 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001158}
1159
1160static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001161init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001162{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001163 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001164 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001165
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001166 sysnum = udev_device_get_sysnum(device);
1167 if (sysnum)
1168 ec->drm.id = atoi(sysnum);
1169 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001170 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001171 return -1;
1172 }
1173
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001174 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001175 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001176 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001177 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001178 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001179 udev_device_get_devnode(device));
1180 return -1;
1181 }
1182
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001183 weston_log("using %s\n", filename);
1184
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001185 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001186
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001187
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001188 return 0;
1189}
1190
1191static int
1192init_egl(struct drm_compositor *ec)
1193{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001194 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001195
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001196 if (!ec->gbm)
1197 return -1;
1198
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001199 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001200 NULL) < 0) {
1201 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001202 return -1;
1203 }
1204
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001205 return 0;
1206}
1207
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001208static int
1209init_pixman(struct drm_compositor *ec)
1210{
1211 return pixman_renderer_init(&ec->base);
1212}
1213
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001214static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001215drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1216{
1217 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001218 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001219
1220 mode = malloc(sizeof *mode);
1221 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001222 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001223
1224 mode->base.flags = 0;
1225 mode->base.width = info->hdisplay;
1226 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001227
1228 /* Calculate higher precision (mHz) refresh rate */
1229 refresh = (info->clock * 1000000LL / info->htotal +
1230 info->vtotal / 2) / info->vtotal;
1231
1232 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1233 refresh *= 2;
1234 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1235 refresh /= 2;
1236 if (info->vscan > 1)
1237 refresh /= info->vscan;
1238
1239 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001240 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001241
1242 if (info->type & DRM_MODE_TYPE_PREFERRED)
1243 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1244
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001245 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1246
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001247 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001248}
1249
1250static int
1251drm_subpixel_to_wayland(int drm_value)
1252{
1253 switch (drm_value) {
1254 default:
1255 case DRM_MODE_SUBPIXEL_UNKNOWN:
1256 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1257 case DRM_MODE_SUBPIXEL_NONE:
1258 return WL_OUTPUT_SUBPIXEL_NONE;
1259 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1260 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1261 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1262 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1263 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1264 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1265 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1266 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1267 }
1268}
1269
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001270/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001271static uint32_t
1272drm_get_backlight(struct drm_output *output)
1273{
1274 long brightness, max_brightness, norm;
1275
1276 brightness = backlight_get_brightness(output->backlight);
1277 max_brightness = backlight_get_max_brightness(output->backlight);
1278
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001279 /* convert it on a scale of 0 to 255 */
1280 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001281
1282 return (uint32_t) norm;
1283}
1284
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001285/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001286static void
1287drm_set_backlight(struct weston_output *output_base, uint32_t value)
1288{
1289 struct drm_output *output = (struct drm_output *) output_base;
1290 long max_brightness, new_brightness;
1291
1292 if (!output->backlight)
1293 return;
1294
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001295 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001296 return;
1297
1298 max_brightness = backlight_get_max_brightness(output->backlight);
1299
1300 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001301 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001302
1303 backlight_set_brightness(output->backlight, new_brightness);
1304}
1305
1306static drmModePropertyPtr
1307drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1308{
1309 drmModePropertyPtr props;
1310 int i;
1311
1312 for (i = 0; i < connector->count_props; i++) {
1313 props = drmModeGetProperty(fd, connector->props[i]);
1314 if (!props)
1315 continue;
1316
1317 if (!strcmp(props->name, name))
1318 return props;
1319
1320 drmModeFreeProperty(props);
1321 }
1322
1323 return NULL;
1324}
1325
1326static void
1327drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1328{
1329 struct drm_output *output = (struct drm_output *) output_base;
1330 struct weston_compositor *ec = output_base->compositor;
1331 struct drm_compositor *c = (struct drm_compositor *) ec;
1332 drmModeConnectorPtr connector;
1333 drmModePropertyPtr prop;
1334
1335 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1336 if (!connector)
1337 return;
1338
1339 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1340 if (!prop) {
1341 drmModeFreeConnector(connector);
1342 return;
1343 }
1344
1345 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1346 prop->prop_id, level);
1347 drmModeFreeProperty(prop);
1348 drmModeFreeConnector(connector);
1349}
1350
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001351static const char *connector_type_names[] = {
1352 "None",
1353 "VGA",
1354 "DVI",
1355 "DVI",
1356 "DVI",
1357 "Composite",
1358 "TV",
1359 "LVDS",
1360 "CTV",
1361 "DIN",
1362 "DP",
1363 "HDMI",
1364 "HDMI",
1365 "TV",
1366 "eDP",
1367};
1368
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001369static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001370find_crtc_for_connector(struct drm_compositor *ec,
1371 drmModeRes *resources, drmModeConnector *connector)
1372{
1373 drmModeEncoder *encoder;
1374 uint32_t possible_crtcs;
1375 int i, j;
1376
1377 for (j = 0; j < connector->count_encoders; j++) {
1378 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1379 if (encoder == NULL) {
1380 weston_log("Failed to get encoder.\n");
1381 return -1;
1382 }
1383 possible_crtcs = encoder->possible_crtcs;
1384 drmModeFreeEncoder(encoder);
1385
1386 for (i = 0; i < resources->count_crtcs; i++) {
1387 if (possible_crtcs & (1 << i) &&
1388 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1389 return i;
1390 }
1391 }
1392
1393 return -1;
1394}
1395
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001396/* Init output state that depends on gl or gbm */
1397static int
1398drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1399{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001400 int i, flags;
1401
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001402 output->surface = gbm_surface_create(ec->gbm,
1403 output->base.current->width,
1404 output->base.current->height,
1405 GBM_FORMAT_XRGB8888,
1406 GBM_BO_USE_SCANOUT |
1407 GBM_BO_USE_RENDERING);
1408 if (!output->surface) {
1409 weston_log("failed to create gbm surface\n");
1410 return -1;
1411 }
1412
1413 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001414 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001415 gbm_surface_destroy(output->surface);
1416 return -1;
1417 }
1418
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001419 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1420
1421 for (i = 0; i < 2; i++) {
1422 if (output->cursor_bo[i])
1423 continue;
1424
1425 output->cursor_bo[i] =
1426 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1427 flags);
1428 }
1429
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001430 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1431 weston_log("cursor buffers unavailable, using gl cursors\n");
1432 ec->cursors_are_broken = 1;
1433 }
1434
1435 return 0;
1436}
1437
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001438static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001439drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1440{
1441 int w = output->base.current->width;
1442 int h = output->base.current->height;
1443 unsigned int i;
1444
1445 /* FIXME error checking */
1446
1447 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1448 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1449 if (!output->dumb[i])
1450 goto err;
1451
1452 output->image[i] =
1453 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1454 output->dumb[i]->map,
1455 output->dumb[i]->stride);
1456 if (!output->image[i])
1457 goto err;
1458 }
1459
1460 if (pixman_renderer_output_create(&output->base) < 0)
1461 goto err;
1462
1463 pixman_region32_init_rect(&output->previous_damage,
1464 output->base.x, output->base.y, w, h);
1465
1466 return 0;
1467
1468err:
1469 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1470 if (output->dumb[i])
1471 drm_fb_destroy_dumb(output->dumb[i]);
1472 if (output->image[i])
1473 pixman_image_unref(output->image[i]);
1474
1475 output->dumb[i] = NULL;
1476 output->image[i] = NULL;
1477 }
1478
1479 return -1;
1480}
1481
1482static void
1483drm_output_fini_pixman(struct drm_output *output)
1484{
1485 unsigned int i;
1486
1487 pixman_renderer_output_destroy(&output->base);
1488 pixman_region32_fini(&output->previous_damage);
1489
1490 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1491 drm_fb_destroy_dumb(output->dumb[i]);
1492 pixman_image_unref(output->image[i]);
1493 output->dumb[i] = NULL;
1494 output->image[i] = NULL;
1495 }
1496}
1497
Richard Hughes2b2092a2013-04-24 14:58:02 +01001498static void
1499edid_parse_string(const uint8_t *data, char text[])
1500{
1501 int i;
1502 int replaced = 0;
1503
1504 /* this is always 12 bytes, but we can't guarantee it's null
1505 * terminated or not junk. */
1506 strncpy(text, (const char *) data, 12);
1507
1508 /* remove insane chars */
1509 for (i = 0; text[i] != '\0'; i++) {
1510 if (text[i] == '\n' ||
1511 text[i] == '\r') {
1512 text[i] = '\0';
1513 break;
1514 }
1515 }
1516
1517 /* ensure string is printable */
1518 for (i = 0; text[i] != '\0'; i++) {
1519 if (!isprint(text[i])) {
1520 text[i] = '-';
1521 replaced++;
1522 }
1523 }
1524
1525 /* if the string is random junk, ignore the string */
1526 if (replaced > 4)
1527 text[0] = '\0';
1528}
1529
1530#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1531#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1532#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1533#define EDID_OFFSET_DATA_BLOCKS 0x36
1534#define EDID_OFFSET_LAST_BLOCK 0x6c
1535#define EDID_OFFSET_PNPID 0x08
1536#define EDID_OFFSET_SERIAL 0x0c
1537
1538static int
1539edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1540{
1541 int i;
1542 uint32_t serial_number;
1543
1544 /* check header */
1545 if (length < 128)
1546 return -1;
1547 if (data[0] != 0x00 || data[1] != 0xff)
1548 return -1;
1549
1550 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1551 * /--08--\/--09--\
1552 * 7654321076543210
1553 * |\---/\---/\---/
1554 * R C1 C2 C3 */
1555 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1556 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1557 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1558 edid->pnp_id[3] = '\0';
1559
1560 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1561 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1562 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1563 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1564 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1565 if (serial_number > 0)
1566 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1567
1568 /* parse EDID data */
1569 for (i = EDID_OFFSET_DATA_BLOCKS;
1570 i <= EDID_OFFSET_LAST_BLOCK;
1571 i += 18) {
1572 /* ignore pixel clock data */
1573 if (data[i] != 0)
1574 continue;
1575 if (data[i+2] != 0)
1576 continue;
1577
1578 /* any useful blocks? */
1579 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1580 edid_parse_string(&data[i+5],
1581 edid->monitor_name);
1582 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1583 edid_parse_string(&data[i+5],
1584 edid->serial_number);
1585 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1586 edid_parse_string(&data[i+5],
1587 edid->eisa_id);
1588 }
1589 }
1590 return 0;
1591}
1592
1593static void
1594find_and_parse_output_edid(struct drm_compositor *ec,
1595 struct drm_output *output,
1596 drmModeConnector *connector)
1597{
1598 drmModePropertyBlobPtr edid_blob = NULL;
1599 drmModePropertyPtr property;
1600 int i;
1601 int rc;
1602
1603 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1604 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1605 if (!property)
1606 continue;
1607 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1608 !strcmp(property->name, "EDID")) {
1609 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1610 connector->prop_values[i]);
1611 }
1612 drmModeFreeProperty(property);
1613 }
1614 if (!edid_blob)
1615 return;
1616
1617 rc = edid_parse(&output->edid,
1618 edid_blob->data,
1619 edid_blob->length);
1620 if (!rc) {
1621 weston_log("EDID data '%s', '%s', '%s'\n",
1622 output->edid.pnp_id,
1623 output->edid.monitor_name,
1624 output->edid.serial_number);
1625 if (output->edid.pnp_id[0] != '\0')
1626 output->base.make = output->edid.pnp_id;
1627 if (output->edid.monitor_name[0] != '\0')
1628 output->base.model = output->edid.monitor_name;
1629 if (output->edid.serial_number[0] != '\0')
1630 output->base.serial_number = output->edid.serial_number;
1631 }
1632 drmModeFreePropertyBlob(edid_blob);
1633}
1634
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001635static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001636create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001637 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001638 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001639 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001640{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001641 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001642 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1643 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001644 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001645 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001646 drmModeModeInfo crtc_mode;
1647 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001648 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001649 char name[32];
1650 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001651
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001652 i = find_crtc_for_connector(ec, resources, connector);
1653 if (i < 0) {
1654 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001655 return -1;
1656 }
1657
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001658 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001659 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001660 return -1;
1661
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001662 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001663 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1664 output->base.make = "unknown";
1665 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001666 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001667 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001668
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001669 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1670 type_name = connector_type_names[connector->connector_type];
1671 else
1672 type_name = "UNKNOWN";
1673 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1674 output->name = strdup(name);
1675
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001676 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001677 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001679 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001680 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001681
Matt Roper361d2ad2011-08-29 13:52:23 -07001682 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1683
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001684 /* Get the current mode on the crtc that's currently driving
1685 * this connector. */
1686 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001687 memset(&crtc_mode, 0, sizeof crtc_mode);
1688 if (encoder != NULL) {
1689 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1690 drmModeFreeEncoder(encoder);
1691 if (crtc == NULL)
1692 goto err_free;
1693 if (crtc->mode_valid)
1694 crtc_mode = crtc->mode;
1695 drmModeFreeCrtc(crtc);
1696 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001697
David Herrmann0f0d54e2011-12-08 17:05:45 +01001698 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001699 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1700 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001701 goto err_free;
1702 }
1703
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001704 preferred = NULL;
1705 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001706 configured = NULL;
1707
1708 wl_list_for_each(temp, &configured_output_list, link) {
1709 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001710 if (temp->mode)
1711 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001712 temp->name, temp->mode);
1713 o = temp;
1714 break;
1715 }
1716 }
1717
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001718 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001719 weston_log("Disabling output %s\n", o->name);
1720
1721 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1722 0, 0, 0, 0, 0, NULL);
1723 goto err_free;
1724 }
1725
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001726 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001727 if (o && o->config == OUTPUT_CONFIG_MODE &&
1728 o->width == drm_mode->base.width &&
1729 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001730 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001731 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001732 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001733 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001734 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001735 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001736
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001737 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001738 configured = drm_output_add_mode(output, &o->crtc_mode);
1739 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001740 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001741 current = configured;
1742 }
1743
Wang Quanxianacb805a2012-07-30 18:09:46 -04001744 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001745 current = drm_output_add_mode(output, &crtc_mode);
1746 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001747 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001748 }
1749
Scott Moreau8ab5d452012-07-30 19:51:08 -06001750 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1751 configured = current;
1752
Wang Quanxianacb805a2012-07-30 18:09:46 -04001753 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001754 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001755 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001756 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001757 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001758 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001759 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001760 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001761
1762 if (output->base.current == NULL) {
1763 weston_log("no available modes for %s\n", output->name);
1764 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001765 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001766
Wang Quanxianacb805a2012-07-30 18:09:46 -04001767 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1768
John Kåre Alsaker94659272012-11-13 19:10:18 +01001769 weston_output_init(&output->base, &ec->base, x, y,
1770 connector->mmWidth, connector->mmHeight,
1771 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1772
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001773 if (ec->use_pixman) {
1774 if (drm_output_init_pixman(output, ec) < 0) {
1775 weston_log("Failed to init output pixman state\n");
1776 goto err_output;
1777 }
1778 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001779 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001780 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001781 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001782
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001783 output->backlight = backlight_init(drm_device,
1784 connector->connector_type);
1785 if (output->backlight) {
1786 output->base.set_backlight = drm_set_backlight;
1787 output->base.backlight_current = drm_get_backlight(output);
1788 }
1789
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001790 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1791
Richard Hughes2b2092a2013-04-24 14:58:02 +01001792 find_and_parse_output_edid(ec, output, connector);
1793
Alex Wubd3354b2012-04-17 17:20:49 +08001794 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001795 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001796 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001797 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001798 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001799 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001800 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001801
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001802 weston_plane_init(&output->cursor_plane, 0, 0);
1803 weston_plane_init(&output->fb_plane, 0, 0);
1804
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001805 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1806 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1807 &ec->base.primary_plane);
1808
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001809 weston_log("Output %s, (connector %d, crtc %d)\n",
1810 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001811 wl_list_for_each(m, &output->base.mode_list, link)
1812 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1813 m->width, m->height, m->refresh / 1000.0,
1814 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1815 ", preferred" : "",
1816 m->flags & WL_OUTPUT_MODE_CURRENT ?
1817 ", current" : "",
1818 connector->count_modes == 0 ?
1819 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001820
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001821 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001822
John Kåre Alsaker94659272012-11-13 19:10:18 +01001823err_output:
1824 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001825err_free:
1826 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1827 base.link) {
1828 wl_list_remove(&drm_mode->base.link);
1829 free(drm_mode);
1830 }
1831
1832 drmModeFreeCrtc(output->original_crtc);
1833 ec->crtc_allocator &= ~(1 << output->crtc_id);
1834 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001835 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001836 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001837
David Herrmann0f0d54e2011-12-08 17:05:45 +01001838 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001839}
1840
Jesse Barnes58ef3792012-02-23 09:45:49 -05001841static void
1842create_sprites(struct drm_compositor *ec)
1843{
1844 struct drm_sprite *sprite;
1845 drmModePlaneRes *plane_res;
1846 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001847 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001848
1849 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1850 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001851 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001852 strerror(errno));
1853 return;
1854 }
1855
1856 for (i = 0; i < plane_res->count_planes; i++) {
1857 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1858 if (!plane)
1859 continue;
1860
1861 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1862 plane->count_formats));
1863 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001864 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001865 __func__);
1866 free(plane);
1867 continue;
1868 }
1869
1870 memset(sprite, 0, sizeof *sprite);
1871
1872 sprite->possible_crtcs = plane->possible_crtcs;
1873 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001874 sprite->current = NULL;
1875 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001876 sprite->compositor = ec;
1877 sprite->count_formats = plane->count_formats;
1878 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001879 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001880 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001881 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001882 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1883 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001884
1885 wl_list_insert(&ec->sprite_list, &sprite->link);
1886 }
1887
1888 free(plane_res->planes);
1889 free(plane_res);
1890}
1891
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001892static void
1893destroy_sprites(struct drm_compositor *compositor)
1894{
1895 struct drm_sprite *sprite, *next;
1896 struct drm_output *output;
1897
1898 output = container_of(compositor->base.output_list.next,
1899 struct drm_output, base.link);
1900
1901 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1902 drmModeSetPlane(compositor->drm.fd,
1903 sprite->plane_id,
1904 output->crtc_id, 0, 0,
1905 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001906 drm_output_release_fb(output, sprite->current);
1907 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001908 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001909 free(sprite);
1910 }
1911}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001912
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001913static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001914create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001915 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001916{
1917 drmModeConnector *connector;
1918 drmModeRes *resources;
1919 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001920 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001921
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001922 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001923 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001924 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001925 return -1;
1926 }
1927
Jesse Barnes58ef3792012-02-23 09:45:49 -05001928 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001929 if (!ec->crtcs) {
1930 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001931 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001932 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001933
Rob Clark4339add2012-08-09 14:18:28 -05001934 ec->min_width = resources->min_width;
1935 ec->max_width = resources->max_width;
1936 ec->min_height = resources->min_height;
1937 ec->max_height = resources->max_height;
1938
Jesse Barnes58ef3792012-02-23 09:45:49 -05001939 ec->num_crtcs = resources->count_crtcs;
1940 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1941
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001942 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001943 connector = drmModeGetConnector(ec->drm.fd,
1944 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001945 if (connector == NULL)
1946 continue;
1947
1948 if (connector->connection == DRM_MODE_CONNECTED &&
1949 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001950 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001951 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001952 connector, x, y,
1953 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001954 drmModeFreeConnector(connector);
1955 continue;
1956 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001957
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001958 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001959 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001960 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001961 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001962
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001963 drmModeFreeConnector(connector);
1964 }
1965
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001966 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001967 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001968 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001969 return -1;
1970 }
1971
1972 drmModeFreeResources(resources);
1973
1974 return 0;
1975}
1976
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001977static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001978update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001979{
1980 drmModeConnector *connector;
1981 drmModeRes *resources;
1982 struct drm_output *output, *next;
1983 int x = 0, y = 0;
1984 int x_offset = 0, y_offset = 0;
1985 uint32_t connected = 0, disconnects = 0;
1986 int i;
1987
1988 resources = drmModeGetResources(ec->drm.fd);
1989 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001990 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001991 return;
1992 }
1993
1994 /* collect new connects */
1995 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001996 int connector_id = resources->connectors[i];
1997
1998 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001999 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002000 continue;
2001
David Herrmann7551cff2011-12-08 17:05:43 +01002002 if (connector->connection != DRM_MODE_CONNECTED) {
2003 drmModeFreeConnector(connector);
2004 continue;
2005 }
2006
Benjamin Franzke117483d2011-08-30 11:38:26 +02002007 connected |= (1 << connector_id);
2008
2009 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002010 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002011 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002012 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002013
2014 /* XXX: not yet needed, we die with 0 outputs */
2015 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002016 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002017 else
2018 x = 0;
2019 y = 0;
2020 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002021 connector, x, y,
2022 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002023 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002024
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002025 }
2026 drmModeFreeConnector(connector);
2027 }
2028 drmModeFreeResources(resources);
2029
2030 disconnects = ec->connector_allocator & ~connected;
2031 if (disconnects) {
2032 wl_list_for_each_safe(output, next, &ec->base.output_list,
2033 base.link) {
2034 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002035 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002036 output->base.x - x_offset,
2037 output->base.y - y_offset);
2038 }
2039
2040 if (disconnects & (1 << output->connector_id)) {
2041 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002042 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002043 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002044 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002045 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002046 }
2047 }
2048 }
2049
2050 /* FIXME: handle zero outputs, without terminating */
2051 if (ec->connector_allocator == 0)
2052 wl_display_terminate(ec->base.wl_display);
2053}
2054
2055static int
David Herrmannd7488c22012-03-11 20:05:21 +01002056udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002057{
David Herrmannd7488c22012-03-11 20:05:21 +01002058 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002059 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002060
2061 sysnum = udev_device_get_sysnum(device);
2062 if (!sysnum || atoi(sysnum) != ec->drm.id)
2063 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002064
David Herrmann6ac52db2012-03-11 20:05:22 +01002065 val = udev_device_get_property_value(device, "HOTPLUG");
2066 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002067 return 0;
2068
David Herrmann6ac52db2012-03-11 20:05:22 +01002069 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002070}
2071
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002072static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002073udev_drm_event(int fd, uint32_t mask, void *data)
2074{
2075 struct drm_compositor *ec = data;
2076 struct udev_device *event;
2077
2078 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002079
David Herrmannd7488c22012-03-11 20:05:21 +01002080 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002081 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002082
2083 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002084
2085 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002086}
2087
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002088static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002089drm_restore(struct weston_compositor *ec)
2090{
2091 struct drm_compositor *d = (struct drm_compositor *) ec;
2092
2093 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2094 weston_log("failed to drop master: %m\n");
2095 tty_reset(d->tty);
2096}
2097
2098static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002099drm_free_configured_output(struct drm_configured_output *output)
2100{
2101 free(output->name);
2102 free(output->mode);
2103 free(output);
2104}
2105
2106static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002107drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002108{
2109 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002110 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002111 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002112
Kristian Høgsberge8091032013-02-18 15:43:29 -05002113 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2114 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002115 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002116 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002117
2118 wl_event_source_remove(d->udev_drm_source);
2119 wl_event_source_remove(d->drm_source);
2120
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002121 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002122
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002123 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002124
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002125 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002126
2127 if (d->gbm)
2128 gbm_device_destroy(d->gbm);
2129
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002130 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002131 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002132 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002133
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002134 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002135}
2136
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002137static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002138drm_compositor_set_modes(struct drm_compositor *compositor)
2139{
2140 struct drm_output *output;
2141 struct drm_mode *drm_mode;
2142 int ret;
2143
2144 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002145 if (!output->current) {
2146 /* If something that would cause the output to
2147 * switch mode happened while in another vt, we
2148 * might not have a current drm_fb. In that case,
2149 * schedule a repaint and let drm_output_repaint
2150 * handle setting the mode. */
2151 weston_output_schedule_repaint(&output->base);
2152 continue;
2153 }
2154
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002155 drm_mode = (struct drm_mode *) output->base.current;
2156 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002157 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002158 &output->connector_id, 1,
2159 &drm_mode->mode_info);
2160 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002161 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002162 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002163 drm_mode->base.width, drm_mode->base.height,
2164 output->base.x, output->base.y);
2165 }
2166 }
2167}
2168
2169static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002170vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002171{
2172 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002173 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002174 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002175 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002176
2177 switch (event) {
2178 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002179 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002180 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002181 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002182 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002183 wl_display_terminate(compositor->wl_display);
2184 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002185 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002186 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002187 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002188 wl_list_for_each(seat, &compositor->seat_list, base.link)
2189 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002190 break;
2191 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002192 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002193 wl_list_for_each(seat, &compositor->seat_list, base.link)
2194 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002195
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002196 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002197 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002198 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002199
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002200 /* If we have a repaint scheduled (either from a
2201 * pending pageflip or the idle handler), make sure we
2202 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002203 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002204 * further attemps at repainting. When we switch
2205 * back, we schedule a repaint, which will process
2206 * pending frame callbacks. */
2207
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002208 wl_list_for_each(output, &ec->base.output_list, base.link) {
2209 output->base.repaint_needed = 0;
2210 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002211 }
2212
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002213 output = container_of(ec->base.output_list.next,
2214 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002215
2216 wl_list_for_each(sprite, &ec->sprite_list, link)
2217 drmModeSetPlane(ec->drm.fd,
2218 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002219 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002220 0, 0, 0, 0, 0, 0, 0, 0);
2221
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002222 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002223 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002224
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002225 break;
2226 };
2227}
2228
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002229static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002230switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002231{
2232 struct drm_compositor *ec = data;
2233
Daniel Stone325fc2d2012-05-30 16:31:58 +01002234 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002235}
2236
David Herrmann0af066f2012-10-29 19:21:16 +01002237/*
2238 * Find primary GPU
2239 * Some systems may have multiple DRM devices attached to a single seat. This
2240 * function loops over all devices and tries to find a PCI device with the
2241 * boot_vga sysfs attribute set to 1.
2242 * If no such device is found, the first DRM device reported by udev is used.
2243 */
2244static struct udev_device*
2245find_primary_gpu(struct drm_compositor *ec, const char *seat)
2246{
2247 struct udev_enumerate *e;
2248 struct udev_list_entry *entry;
2249 const char *path, *device_seat, *id;
2250 struct udev_device *device, *drm_device, *pci;
2251
2252 e = udev_enumerate_new(ec->udev);
2253 udev_enumerate_add_match_subsystem(e, "drm");
2254 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2255
2256 udev_enumerate_scan_devices(e);
2257 drm_device = NULL;
2258 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2259 path = udev_list_entry_get_name(entry);
2260 device = udev_device_new_from_syspath(ec->udev, path);
2261 if (!device)
2262 continue;
2263 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2264 if (!device_seat)
2265 device_seat = default_seat;
2266 if (strcmp(device_seat, seat)) {
2267 udev_device_unref(device);
2268 continue;
2269 }
2270
2271 pci = udev_device_get_parent_with_subsystem_devtype(device,
2272 "pci", NULL);
2273 if (pci) {
2274 id = udev_device_get_sysattr_value(pci, "boot_vga");
2275 if (id && !strcmp(id, "1")) {
2276 if (drm_device)
2277 udev_device_unref(drm_device);
2278 drm_device = device;
2279 break;
2280 }
2281 }
2282
2283 if (!drm_device)
2284 drm_device = device;
2285 else
2286 udev_device_unref(device);
2287 }
2288
2289 udev_enumerate_unref(e);
2290 return drm_device;
2291}
2292
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002293static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002294planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002295{
2296 struct drm_compositor *c = data;
2297
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002298 switch (key) {
2299 case KEY_C:
2300 c->cursors_are_broken ^= 1;
2301 break;
2302 case KEY_V:
2303 c->sprites_are_broken ^= 1;
2304 break;
2305 case KEY_O:
2306 c->sprites_hidden ^= 1;
2307 break;
2308 default:
2309 break;
2310 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002311}
2312
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002313static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002314drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002315 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002316 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002317{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002318 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002319 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002320 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002321 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002322 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002323 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002324
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002325 weston_log("initializing drm backend\n");
2326
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002327 ec = malloc(sizeof *ec);
2328 if (ec == NULL)
2329 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002330 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002331
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002332 /* KMS support for sprites is not complete yet, so disable the
2333 * functionality for now. */
2334 ec->sprites_are_broken = 1;
2335
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002336 ec->use_pixman = pixman;
2337
Daniel Stone725c2c32012-06-22 14:04:36 +01002338 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002339 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002340 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002341 goto err_base;
2342 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002343
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002344 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002345 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002346 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002347 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002348 goto err_compositor;
2349 }
2350
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002351 ec->udev = udev_new();
2352 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002353 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002354 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002355 }
2356
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002357 ec->base.wl_display = display;
2358 ec->tty = tty_create(&ec->base, vt_func, tty);
2359 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002360 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002361 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002362 }
2363
David Herrmann0af066f2012-10-29 19:21:16 +01002364 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002365 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002366 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002367 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002368 }
David Herrmann0af066f2012-10-29 19:21:16 +01002369 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002370
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002371 if (init_drm(ec, drm_device) < 0) {
2372 weston_log("failed to initialize kms\n");
2373 goto err_udev_dev;
2374 }
2375
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002376 if (ec->use_pixman) {
2377 if (init_pixman(ec) < 0) {
2378 weston_log("failed to initialize pixman renderer\n");
2379 goto err_udev_dev;
2380 }
2381 } else {
2382 if (init_egl(ec) < 0) {
2383 weston_log("failed to initialize egl\n");
2384 goto err_udev_dev;
2385 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002386 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002387
2388 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002389 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002390
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002391 ec->base.focus = 1;
2392
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002393 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002394
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002395 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002396 weston_compositor_add_key_binding(&ec->base, key,
2397 MODIFIER_CTRL | MODIFIER_ALT,
2398 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002399
Jesse Barnes58ef3792012-02-23 09:45:49 -05002400 wl_list_init(&ec->sprite_list);
2401 create_sprites(ec);
2402
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002403 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002404 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002405 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002406 }
2407
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002408 path = NULL;
2409
Kristian Høgsberge8091032013-02-18 15:43:29 -05002410 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002411 weston_log("failed to create input devices\n");
2412 goto err_sprite;
2413 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002414
2415 loop = wl_display_get_event_loop(ec->base.wl_display);
2416 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002417 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002418 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002419
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002420 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2421 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002422 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002423 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002424 }
2425 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2426 "drm", NULL);
2427 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002428 wl_event_loop_add_fd(loop,
2429 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002430 WL_EVENT_READABLE, udev_drm_event, ec);
2431
2432 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002433 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002434 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002435 }
2436
Daniel Stonea96b93c2012-06-22 14:04:37 +01002437 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002438
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002439 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002440 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002441 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002442 planes_binding, ec);
2443 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2444 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002445
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002446 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002447
2448err_udev_monitor:
2449 wl_event_source_remove(ec->udev_drm_source);
2450 udev_monitor_unref(ec->udev_monitor);
2451err_drm_source:
2452 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002453 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2454 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002455err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002456 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002457 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002458 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002459err_udev_dev:
2460 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002461err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002462 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2463 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002464 tty_destroy(ec->tty);
2465err_udev:
2466 udev_unref(ec->udev);
2467err_compositor:
2468 weston_compositor_shutdown(&ec->base);
2469err_base:
2470 free(ec);
2471 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002472}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002473
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002474static int
2475set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2476{
2477 mode->flags = 0;
2478
2479 if (strcmp(hsync, "+hsync") == 0)
2480 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2481 else if (strcmp(hsync, "-hsync") == 0)
2482 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2483 else
2484 return -1;
2485
2486 if (strcmp(vsync, "+vsync") == 0)
2487 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2488 else if (strcmp(vsync, "-vsync") == 0)
2489 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2490 else
2491 return -1;
2492
2493 return 0;
2494}
2495
2496static int
2497check_for_modeline(struct drm_configured_output *output)
2498{
2499 drmModeModeInfo mode;
2500 char hsync[16];
2501 char vsync[16];
2502 char mode_name[16];
2503 float fclock;
2504
2505 mode.type = DRM_MODE_TYPE_USERDEF;
2506 mode.hskew = 0;
2507 mode.vscan = 0;
2508 mode.vrefresh = 0;
2509
2510 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2511 &fclock, &mode.hdisplay,
2512 &mode.hsync_start,
2513 &mode.hsync_end, &mode.htotal,
2514 &mode.vdisplay,
2515 &mode.vsync_start,
2516 &mode.vsync_end, &mode.vtotal,
2517 hsync, vsync) == 11) {
2518 if (set_sync_flags(&mode, hsync, vsync))
2519 return -1;
2520
2521 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2522 strcpy(mode.name, mode_name);
2523
2524 mode.clock = fclock * 1000;
2525 } else
2526 return -1;
2527
2528 output->crtc_mode = mode;
2529
2530 return 0;
2531}
2532
Scott Moreau8ab5d452012-07-30 19:51:08 -06002533static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002534drm_output_set_transform(struct drm_configured_output *output)
2535{
2536 if (!output_transform) {
2537 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2538 return;
2539 }
2540
2541 if (!strcmp(output_transform, "normal"))
2542 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2543 else if (!strcmp(output_transform, "90"))
2544 output->transform = WL_OUTPUT_TRANSFORM_90;
2545 else if (!strcmp(output_transform, "180"))
2546 output->transform = WL_OUTPUT_TRANSFORM_180;
2547 else if (!strcmp(output_transform, "270"))
2548 output->transform = WL_OUTPUT_TRANSFORM_270;
2549 else if (!strcmp(output_transform, "flipped"))
2550 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2551 else if (!strcmp(output_transform, "flipped-90"))
2552 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2553 else if (!strcmp(output_transform, "flipped-180"))
2554 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2555 else if (!strcmp(output_transform, "flipped-270"))
2556 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2557 else {
2558 weston_log("Invalid transform \"%s\" for output %s\n",
2559 output_transform, output_name);
2560 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2561 }
2562
2563 free(output_transform);
2564 output_transform = NULL;
2565}
2566
2567static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002568output_section_done(void *data)
2569{
2570 struct drm_configured_output *output;
2571
2572 output = malloc(sizeof *output);
2573
Scott Moreau1bad5db2012-08-18 01:04:05 -06002574 if (!output || !output_name || (output_name[0] == 'X') ||
2575 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002576 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002577 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002578 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002579 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002580 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002581 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002582 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002583 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002584 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002585
2586 output->config = OUTPUT_CONFIG_INVALID;
2587 output->name = output_name;
2588 output->mode = output_mode;
2589
Scott Moreau1bad5db2012-08-18 01:04:05 -06002590 if (output_mode) {
2591 if (strcmp(output_mode, "off") == 0)
2592 output->config = OUTPUT_CONFIG_OFF;
2593 else if (strcmp(output_mode, "preferred") == 0)
2594 output->config = OUTPUT_CONFIG_PREFERRED;
2595 else if (strcmp(output_mode, "current") == 0)
2596 output->config = OUTPUT_CONFIG_CURRENT;
2597 else if (sscanf(output_mode, "%dx%d",
2598 &output->width, &output->height) == 2)
2599 output->config = OUTPUT_CONFIG_MODE;
2600 else if (check_for_modeline(output) == 0)
2601 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002602
Scott Moreau1bad5db2012-08-18 01:04:05 -06002603 if (output->config == OUTPUT_CONFIG_INVALID)
2604 weston_log("Invalid mode \"%s\" for output %s\n",
2605 output_mode, output_name);
2606 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002607 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002608
2609 drm_output_set_transform(output);
2610
2611 wl_list_insert(&configured_output_list, &output->link);
2612
2613 if (output_transform)
2614 free(output_transform);
2615 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002616}
2617
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002618WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002619backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002620 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002621{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002622 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002623 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002624
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002625 const struct weston_option drm_options[] = {
2626 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2627 { WESTON_OPTION_STRING, "seat", 0, &seat },
2628 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002629 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002630 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002631 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002632
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002633 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002634
Scott Moreau8ab5d452012-07-30 19:51:08 -06002635 wl_list_init(&configured_output_list);
2636
2637 const struct config_key drm_config_keys[] = {
2638 { "name", CONFIG_KEY_STRING, &output_name },
2639 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002640 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002641 };
2642
2643 const struct config_section config_section[] = {
2644 { "output", drm_config_keys,
2645 ARRAY_LENGTH(drm_config_keys), output_section_done },
2646 };
2647
2648 parse_config_file(config_file, config_section,
2649 ARRAY_LENGTH(config_section), NULL);
2650
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002651 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2652 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002653}