blob: a51ac2b49770f8d3a02c98b72cfd8eec9c65b69a [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
Richard Hughesab745622013-05-01 21:52:13 +010024#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040028#define _GNU_SOURCE
29
Jesse Barnes58ef3792012-02-23 09:45:49 -050030#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040031#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010032#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033#include <string.h>
34#include <fcntl.h>
35#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040036#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030037#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020038#include <sys/mman.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040039
Benjamin Franzkec649a922011-03-02 11:56:04 +010040#include <xf86drm.h>
41#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050042#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010043
Benjamin Franzke060cf802011-04-30 09:32:11 +020044#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020045#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040046#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020047
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040048#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010049#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020050#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050051#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010052#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Kristian Høgsberg061c4252012-06-28 11:28:15 -040054static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060055static char *output_name;
56static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060057static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060058static struct wl_list configured_output_list;
59
60enum output_config {
61 OUTPUT_CONFIG_INVALID = 0,
62 OUTPUT_CONFIG_OFF,
63 OUTPUT_CONFIG_PREFERRED,
64 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060065 OUTPUT_CONFIG_MODE,
66 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060067};
68
69struct drm_configured_output {
70 char *name;
71 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060072 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060073 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060074 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060075 enum output_config config;
76 struct wl_list link;
77};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040078
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040079struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050080 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040081
82 struct udev *udev;
83 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040084
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010085 struct udev_monitor *udev_monitor;
86 struct wl_event_source *udev_drm_source;
87
Benjamin Franzke2af7f102011-03-02 11:14:59 +010088 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010089 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010090 int fd;
91 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020092 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050093 uint32_t *crtcs;
94 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050095 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010096 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050097 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020098
Rob Clark4339add2012-08-09 14:18:28 -050099 /* we need these parameters in order to not fail drmModeAddFB2()
100 * due to out of bounds dimensions, and then mistakenly set
101 * sprites_are_broken:
102 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200103 uint32_t min_width, max_width;
104 uint32_t min_height, max_height;
105 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500106
Jesse Barnes58ef3792012-02-23 09:45:49 -0500107 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500108 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200109 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500110
Rob Clarkab5b1e32012-08-09 13:24:45 -0500111 int cursors_are_broken;
112
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200113 int use_pixman;
114
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200115 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400116};
117
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400118struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500119 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400120 drmModeModeInfo mode_info;
121};
122
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300123struct drm_output;
124
125struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300126 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200127 uint32_t fb_id, stride, handle, size;
128 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300129 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200130 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200131
132 /* Used by gbm fbs */
133 struct gbm_bo *bo;
134
135 /* Used by dumb fbs */
136 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300137};
138
Richard Hughes2b2092a2013-04-24 14:58:02 +0100139struct drm_edid {
140 char eisa_id[13];
141 char monitor_name[13];
142 char pnp_id[5];
143 char serial_number[13];
144};
145
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500147 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400148
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400149 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400150 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500151 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400152 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700153 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100154 struct drm_edid edid;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200155
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300156 int vblank_pending;
157 int page_flip_pending;
158
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400159 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400160 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400161 struct weston_plane cursor_plane;
162 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400163 struct weston_surface *cursor_surface;
164 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300165 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200166 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200167
168 struct drm_fb *dumb[2];
169 pixman_image_t *image[2];
170 int current_image;
171 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400172};
173
Jesse Barnes58ef3792012-02-23 09:45:49 -0500174/*
175 * An output has a primary display plane plus zero or more sprites for
176 * blending display contents.
177 */
178struct drm_sprite {
179 struct wl_list link;
180
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400181 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200183 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300184 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500185 struct drm_compositor *compositor;
186
Jesse Barnes58ef3792012-02-23 09:45:49 -0500187 uint32_t possible_crtcs;
188 uint32_t plane_id;
189 uint32_t count_formats;
190
191 int32_t src_x, src_y;
192 uint32_t src_w, src_h;
193 uint32_t dest_x, dest_y;
194 uint32_t dest_w, dest_h;
195
196 uint32_t formats[];
197};
198
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500199static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400200
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400201static void
202drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400203
Jesse Barnes58ef3792012-02-23 09:45:49 -0500204static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500205drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
206{
207 struct weston_compositor *ec = output_base->compositor;
208 struct drm_compositor *c =(struct drm_compositor *) ec;
209 struct drm_output *output = (struct drm_output *) output_base;
210 int crtc;
211
212 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
213 if (c->crtcs[crtc] != output->crtc_id)
214 continue;
215
216 if (supported & (1 << crtc))
217 return -1;
218 }
219
220 return 0;
221}
222
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300223static void
224drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
225{
226 struct drm_fb *fb = data;
227 struct gbm_device *gbm = gbm_bo_get_device(bo);
228
229 if (fb->fb_id)
230 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
231
Pekka Paalanende685b82012-12-04 15:58:12 +0200232 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300233
234 free(data);
235}
236
237static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200238drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
239{
240 struct drm_fb *fb;
241 int ret;
242
243 struct drm_mode_create_dumb create_arg;
244 struct drm_mode_destroy_dumb destroy_arg;
245 struct drm_mode_map_dumb map_arg;
246
247 fb = calloc(1, sizeof *fb);
248 if (!fb)
249 return NULL;
250
251 create_arg.bpp = 32;
252 create_arg.width = width;
253 create_arg.height = height;
254
255 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
256 if (ret)
257 goto err_fb;
258
259 fb->handle = create_arg.handle;
260 fb->stride = create_arg.pitch;
261 fb->size = create_arg.size;
262 fb->fd = ec->drm.fd;
263
264 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
265 fb->stride, fb->handle, &fb->fb_id);
266 if (ret)
267 goto err_bo;
268
269 memset(&map_arg, 0, sizeof(map_arg));
270 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400271 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200272 if (ret)
273 goto err_add_fb;
274
275 fb->map = mmap(0, fb->size, PROT_WRITE,
276 MAP_SHARED, ec->drm.fd, map_arg.offset);
277 if (fb->map == MAP_FAILED)
278 goto err_add_fb;
279
280 return fb;
281
282err_add_fb:
283 drmModeRmFB(ec->drm.fd, fb->fb_id);
284err_bo:
285 memset(&destroy_arg, 0, sizeof(destroy_arg));
286 destroy_arg.handle = create_arg.handle;
287 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
288err_fb:
289 free(fb);
290 return NULL;
291}
292
293static void
294drm_fb_destroy_dumb(struct drm_fb *fb)
295{
296 struct drm_mode_destroy_dumb destroy_arg;
297
298 if (!fb->map)
299 return;
300
301 if (fb->fb_id)
302 drmModeRmFB(fb->fd, fb->fb_id);
303
304 weston_buffer_reference(&fb->buffer_ref, NULL);
305
306 munmap(fb->map, fb->size);
307
308 memset(&destroy_arg, 0, sizeof(destroy_arg));
309 destroy_arg.handle = fb->handle;
310 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
311
312 free(fb);
313}
314
315static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500316drm_fb_get_from_bo(struct gbm_bo *bo,
317 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300318{
319 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200320 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200321 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300322 int ret;
323
324 if (fb)
325 return fb;
326
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200327 fb = calloc(1, sizeof *fb);
328 if (!fb)
329 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300330
331 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300332
333 width = gbm_bo_get_width(bo);
334 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200335 fb->stride = gbm_bo_get_stride(bo);
336 fb->handle = gbm_bo_get_handle(bo).u32;
337 fb->size = fb->stride * height;
338 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200340 if (compositor->min_width > width || width > compositor->max_width ||
341 compositor->min_height > height ||
342 height > compositor->max_height) {
343 weston_log("bo geometry out of bounds\n");
344 goto err_free;
345 }
346
347 ret = -1;
348
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200350 handles[0] = fb->handle;
351 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200352 offsets[0] = 0;
353
354 ret = drmModeAddFB2(compositor->drm.fd, width, height,
355 format, handles, pitches, offsets,
356 &fb->fb_id, 0);
357 if (ret) {
358 weston_log("addfb2 failed: %m\n");
359 compositor->no_addfb2 = 1;
360 compositor->sprites_are_broken = 1;
361 }
362 }
363
364 if (ret)
365 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200366 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200367
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200369 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200370 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300371 }
372
373 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
374
375 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
377err_free:
378 free(fb);
379 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380}
381
382static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200383drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
384{
Pekka Paalanende685b82012-12-04 15:58:12 +0200385 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200386
387 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200388
Pekka Paalanende685b82012-12-04 15:58:12 +0200389 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200390}
391
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200392static void
393drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
394{
395 if (!fb)
396 return;
397
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200398 if (fb->map &&
399 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200400 drm_fb_destroy_dumb(fb);
401 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200402 if (fb->is_client_buffer)
403 gbm_bo_destroy(fb->bo);
404 else
405 gbm_surface_release_buffer(output->surface,
406 output->current->bo);
407 }
408}
409
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500410static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200411drm_output_check_scanout_format(struct drm_output *output,
412 struct weston_surface *es, struct gbm_bo *bo)
413{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200414 uint32_t format;
415 pixman_region32_t r;
416
417 format = gbm_bo_get_format(bo);
418
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500419 switch (format) {
420 case GBM_FORMAT_XRGB8888:
421 return format;
422 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200423 /* We can only scanout an ARGB buffer if the surface's
424 * opaque region covers the whole output */
425 pixman_region32_init(&r);
426 pixman_region32_subtract(&r, &output->base.region,
427 &es->opaque);
428
429 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500430 format = GBM_FORMAT_XRGB8888;
431 else
432 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200433
434 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200435
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500436 return format;
437 default:
438 return 0;
439 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200440}
441
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400442static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400443drm_output_prepare_scanout_surface(struct weston_output *_output,
444 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500445{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400446 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500447 struct drm_compositor *c =
448 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200449 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300450 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500451 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500452
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500453 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200454 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200455 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200456 buffer->width != output->base.current->width ||
457 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200458 output->base.transform != es->buffer_transform ||
459 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400460 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500461
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400462 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200463 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500464
Rob Bradford9b101872012-09-14 23:25:41 +0100465 /* Unable to use the buffer for scanout */
466 if (!bo)
467 return NULL;
468
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500469 format = drm_output_check_scanout_format(output, es, bo);
470 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300471 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400472 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300473 }
474
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500475 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300476 if (!output->next) {
477 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400478 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300479 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500480
Pekka Paalanende685b82012-12-04 15:58:12 +0200481 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500482
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400483 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500484}
485
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500486static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200487drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200489 struct drm_compositor *c =
490 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300491 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400492
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200493 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400494
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300495 bo = gbm_surface_lock_front_buffer(output->surface);
496 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200497 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400498 return;
499 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300500
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500501 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300502 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200503 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300504 gbm_surface_release_buffer(output->surface, bo);
505 return;
506 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400507}
508
509static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200510drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
511{
512 struct weston_compositor *ec = output->base.compositor;
513 pixman_region32_t total_damage, previous_damage;
514
515 pixman_region32_init(&total_damage);
516 pixman_region32_init(&previous_damage);
517
518 pixman_region32_copy(&previous_damage, damage);
519
520 pixman_region32_union(&total_damage, damage, &output->previous_damage);
521 pixman_region32_copy(&output->previous_damage, &previous_damage);
522
523 output->current_image ^= 1;
524
525 output->next = output->dumb[output->current_image];
526 pixman_renderer_output_set_buffer(&output->base,
527 output->image[output->current_image]);
528
529 ec->renderer->repaint_output(&output->base, &total_damage);
530
531 pixman_region32_fini(&total_damage);
532 pixman_region32_fini(&previous_damage);
533}
534
535static void
536drm_output_render(struct drm_output *output, pixman_region32_t *damage)
537{
538 struct drm_compositor *c =
539 (struct drm_compositor *) output->base.compositor;
540
541 if (c->use_pixman)
542 drm_output_render_pixman(output, damage);
543 else
544 drm_output_render_gl(output, damage);
545
546 pixman_region32_subtract(&c->base.primary_plane.damage,
547 &c->base.primary_plane.damage, damage);
548}
549
550static void
Richard Hughese7299962013-05-01 21:52:12 +0100551drm_output_set_gamma(struct weston_output *output_base,
552 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
553{
554 int rc;
555 struct drm_output *output = (struct drm_output *) output_base;
556 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
557
558 /* check */
559 if (output_base->gamma_size != size)
560 return;
561 if (!output->original_crtc)
562 return;
563
564 rc = drmModeCrtcSetGamma(compositor->drm.fd,
565 output->crtc_id,
566 size, r, g, b);
567 if (rc)
568 weston_log("set gamma failed: %m\n");
569}
570
571static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500572drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400573 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100574{
575 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500576 struct drm_compositor *compositor =
577 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400579 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500580 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100581
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300582 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400583 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300584 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400585 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100586
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400587 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300588 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400589 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300590 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400591 &output->connector_id, 1,
592 &mode->mode_info);
593 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200594 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400595 return;
596 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200597 }
598
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500599 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300600 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500601 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200602 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500603 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500604 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100605
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300606 output->page_flip_pending = 1;
607
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400608 drm_output_set_cursor(output);
609
Jesse Barnes58ef3792012-02-23 09:45:49 -0500610 /*
611 * Now, update all the sprite surfaces
612 */
613 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200614 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615 drmVBlank vbl = {
616 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
617 .request.sequence = 1,
618 };
619
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200620 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200621 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 continue;
623
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200624 if (s->next && !compositor->sprites_hidden)
625 fb_id = s->next->fb_id;
626
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200628 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629 s->dest_x, s->dest_y,
630 s->dest_w, s->dest_h,
631 s->src_x, s->src_y,
632 s->src_w, s->src_h);
633 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200634 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635 ret, strerror(errno));
636
Rob Clark5ca1a472012-08-08 20:27:37 -0500637 if (output->pipe > 0)
638 vbl.request.type |= DRM_VBLANK_SECONDARY;
639
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640 /*
641 * Queue a vblank signal so we know when the surface
642 * becomes active on the display or has been replaced.
643 */
644 vbl.request.signal = (unsigned long)s;
645 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
646 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200647 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500648 ret, strerror(errno));
649 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300650
651 s->output = output;
652 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653 }
654
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500655 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400656}
657
658static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200659drm_output_start_repaint_loop(struct weston_output *output_base)
660{
661 struct drm_output *output = (struct drm_output *) output_base;
662 struct drm_compositor *compositor = (struct drm_compositor *)
663 output_base->compositor;
664 uint32_t fb_id;
665
666 if (output->current)
667 fb_id = output->current->fb_id;
668 else
669 fb_id = output->original_crtc->buffer_id;
670
671 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
672 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
673 weston_log("queueing pageflip failed: %m\n");
674 return;
675 }
676}
677
678static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500679vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
680 void *data)
681{
682 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300683 struct drm_output *output = s->output;
684 uint32_t msecs;
685
686 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500687
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200688 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200689 s->current = s->next;
690 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300691
692 if (!output->page_flip_pending) {
693 msecs = sec * 1000 + usec / 1000;
694 weston_output_finish_frame(&output->base, msecs);
695 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500696}
697
698static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400699page_flip_handler(int fd, unsigned int frame,
700 unsigned int sec, unsigned int usec, void *data)
701{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200702 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400703 uint32_t msecs;
704
Jonas Ådahle5a12252013-04-05 23:07:11 +0200705 /* We don't set page_flip_pending on start_repaint_loop, in that case
706 * we just want to page flip to the current buffer to get an accurate
707 * timestamp */
708 if (output->page_flip_pending) {
709 drm_output_release_fb(output, output->current);
710 output->current = output->next;
711 output->next = NULL;
712 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300713
Jonas Ådahle5a12252013-04-05 23:07:11 +0200714 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400715
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300716 if (!output->vblank_pending) {
717 msecs = sec * 1000 + usec / 1000;
718 weston_output_finish_frame(&output->base, msecs);
719 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200720}
721
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500722static uint32_t
723drm_output_check_sprite_format(struct drm_sprite *s,
724 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500725{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500726 uint32_t i, format;
727
728 format = gbm_bo_get_format(bo);
729
730 if (format == GBM_FORMAT_ARGB8888) {
731 pixman_region32_t r;
732
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500733 pixman_region32_init_rect(&r, 0, 0,
734 es->geometry.width,
735 es->geometry.height);
736 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500737
738 if (!pixman_region32_not_empty(&r))
739 format = GBM_FORMAT_XRGB8888;
740
741 pixman_region32_fini(&r);
742 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743
744 for (i = 0; i < s->count_formats; i++)
745 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500746 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747
748 return 0;
749}
750
751static int
752drm_surface_transform_supported(struct weston_surface *es)
753{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500754 return !es->transform.enabled ||
755 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500756}
757
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400758static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500759drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400760 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500761{
762 struct weston_compositor *ec = output_base->compositor;
763 struct drm_compositor *c =(struct drm_compositor *) ec;
764 struct drm_sprite *s;
765 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500767 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200768 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400770 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200772 if (c->gbm == NULL)
773 return NULL;
774
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200775 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200776 return NULL;
777
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500778 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400779 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500780
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300781 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400782 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300783
Pekka Paalanende685b82012-12-04 15:58:12 +0200784 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400785 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500786
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200787 if (es->alpha != 1.0f)
788 return NULL;
789
Pekka Paalanende685b82012-12-04 15:58:12 +0200790 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500791 return NULL;
792
Jesse Barnes58ef3792012-02-23 09:45:49 -0500793 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796 wl_list_for_each(s, &c->sprite_list, link) {
797 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
798 continue;
799
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200800 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 found = 1;
802 break;
803 }
804 }
805
806 /* No sprites available */
807 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400808 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400810 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200811 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400812 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400813 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400814
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500815 format = drm_output_check_sprite_format(s, es, bo);
816 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200817 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400818 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500819 }
820
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200821 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200822 if (!s->next) {
823 gbm_bo_destroy(bo);
824 return NULL;
825 }
826
Pekka Paalanende685b82012-12-04 15:58:12 +0200827 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500828
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400829 box = pixman_region32_extents(&es->transform.boundingbox);
830 s->plane.x = box->x1;
831 s->plane.y = box->y1;
832
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833 /*
834 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200835 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836 * for us already).
837 */
838 pixman_region32_init(&dest_rect);
839 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
840 &output_base->region);
841 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
842 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200843 tbox = weston_transformed_rect(output_base->width,
844 output_base->height,
845 output_base->transform, *box);
846 s->dest_x = tbox.x1;
847 s->dest_y = tbox.y1;
848 s->dest_w = tbox.x2 - tbox.x1;
849 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 pixman_region32_fini(&dest_rect);
851
852 pixman_region32_init(&src_rect);
853 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
854 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400856
857 weston_surface_from_global_fixed(es,
858 wl_fixed_from_int(box->x1),
859 wl_fixed_from_int(box->y1),
860 &sx1, &sy1);
861 weston_surface_from_global_fixed(es,
862 wl_fixed_from_int(box->x2),
863 wl_fixed_from_int(box->y2),
864 &sx2, &sy2);
865
866 if (sx1 < 0)
867 sx1 = 0;
868 if (sy1 < 0)
869 sy1 = 0;
870 if (sx2 > wl_fixed_from_int(es->geometry.width))
871 sx2 = wl_fixed_from_int(es->geometry.width);
872 if (sy2 > wl_fixed_from_int(es->geometry.height))
873 sy2 = wl_fixed_from_int(es->geometry.height);
874
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200875 tbox.x1 = sx1;
876 tbox.y1 = sy1;
877 tbox.x2 = sx2;
878 tbox.y2 = sy2;
879
880 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
881 wl_fixed_from_int(es->geometry.height),
882 es->buffer_transform, tbox);
883
884 s->src_x = tbox.x1 << 8;
885 s->src_y = tbox.y1 << 8;
886 s->src_w = (tbox.x2 - tbox.x1) << 8;
887 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500888 pixman_region32_fini(&src_rect);
889
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400890 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500891}
892
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400893static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400894drm_output_prepare_cursor_surface(struct weston_output *output_base,
895 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500896{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400897 struct drm_compositor *c =
898 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400899 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400900
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200901 if (c->gbm == NULL)
902 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200903 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
904 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400905 if (output->cursor_surface)
906 return NULL;
907 if (es->output_mask != (1u << output_base->id))
908 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500909 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400910 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200911 if (es->buffer_ref.buffer == NULL ||
912 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400913 es->geometry.width > 64 || es->geometry.height > 64)
914 return NULL;
915
916 output->cursor_surface = es;
917
918 return &output->cursor_plane;
919}
920
921static void
922drm_output_set_cursor(struct drm_output *output)
923{
924 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400925 struct drm_compositor *c =
926 (struct drm_compositor *) output->base.compositor;
927 EGLint handle, stride;
928 struct gbm_bo *bo;
929 uint32_t buf[64 * 64];
930 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400931 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500932
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400933 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400934 if (es == NULL) {
935 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
936 return;
937 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500938
Pekka Paalanende685b82012-12-04 15:58:12 +0200939 if (es->buffer_ref.buffer &&
940 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400941 pixman_region32_fini(&output->cursor_plane.damage);
942 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400943 output->current_cursor ^= 1;
944 bo = output->cursor_bo[output->current_cursor];
945 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200946 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
947 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400948 for (i = 0; i < es->geometry.height; i++)
949 memcpy(buf + i * 64, s + i * stride,
950 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500951
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400952 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300953 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400954
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400955 handle = gbm_bo_get_handle(bo).s32;
956 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500957 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300958 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500959 c->cursors_are_broken = 1;
960 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400961 }
962
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400963 x = es->geometry.x - output->base.x;
964 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400965 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500966 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400967 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500968 c->cursors_are_broken = 1;
969 }
970
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400971 output->cursor_plane.x = x;
972 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400973 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500974}
975
Jesse Barnes58ef3792012-02-23 09:45:49 -0500976static void
977drm_assign_planes(struct weston_output *output)
978{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400979 struct drm_compositor *c =
980 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400981 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500982 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400983 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500984
985 /*
986 * Find a surface for each sprite in the output using some heuristics:
987 * 1) size
988 * 2) frequency of update
989 * 3) opacity (though some hw might support alpha blending)
990 * 4) clipping (this can be fixed with color keys)
991 *
992 * The idea is to save on blitting since this should save power.
993 * If we can get a large video surface on the sprite for example,
994 * the main display surface may not need to update at all, and
995 * the client buffer can be used directly for the sprite surface
996 * as we do for flipping full screen surfaces.
997 */
998 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400999 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001000 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001001 /* test whether this buffer can ever go into a plane:
1002 * non-shm, or small enough to be a cursor
1003 */
1004 if ((es->buffer_ref.buffer &&
1005 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1006 (es->geometry.width <= 64 && es->geometry.height <= 64))
1007 es->keep_buffer = 1;
1008 else
1009 es->keep_buffer = 0;
1010
Jesse Barnes58ef3792012-02-23 09:45:49 -05001011 pixman_region32_init(&surface_overlap);
1012 pixman_region32_intersect(&surface_overlap, &overlap,
1013 &es->transform.boundingbox);
1014
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001015 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001016 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001017 next_plane = primary;
1018 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001019 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001020 if (next_plane == NULL)
1021 next_plane = drm_output_prepare_scanout_surface(output, es);
1022 if (next_plane == NULL)
1023 next_plane = drm_output_prepare_overlay_surface(output, es);
1024 if (next_plane == NULL)
1025 next_plane = primary;
1026 weston_surface_move_to_plane(es, next_plane);
1027 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001028 pixman_region32_union(&overlap, &overlap,
1029 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001030
Jesse Barnes58ef3792012-02-23 09:45:49 -05001031 pixman_region32_fini(&surface_overlap);
1032 }
1033 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001034}
1035
Matt Roper361d2ad2011-08-29 13:52:23 -07001036static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001037drm_output_fini_pixman(struct drm_output *output);
1038
1039static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001040drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001041{
1042 struct drm_output *output = (struct drm_output *) output_base;
1043 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001044 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001045 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001046
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001047 if (output->backlight)
1048 backlight_destroy(output->backlight);
1049
Matt Roper361d2ad2011-08-29 13:52:23 -07001050 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001051 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001052
1053 /* Restore original CRTC state */
1054 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001055 origcrtc->x, origcrtc->y,
1056 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001057 drmModeFreeCrtc(origcrtc);
1058
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001059 c->crtc_allocator &= ~(1 << output->crtc_id);
1060 c->connector_allocator &= ~(1 << output->connector_id);
1061
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001062 if (c->use_pixman) {
1063 drm_output_fini_pixman(output);
1064 } else {
1065 gl_renderer_output_destroy(output_base);
1066 gbm_surface_destroy(output->surface);
1067 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001068
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001069 weston_plane_release(&output->fb_plane);
1070 weston_plane_release(&output->cursor_plane);
1071
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001072 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001073 wl_list_remove(&output->base.link);
1074
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001075 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001076 free(output);
1077}
1078
Alex Wub7b8bda2012-04-17 17:20:48 +08001079static struct drm_mode *
1080choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1081{
1082 struct drm_mode *tmp_mode = NULL, *mode;
1083
1084 if (output->base.current->width == target_mode->width &&
1085 output->base.current->height == target_mode->height &&
1086 (output->base.current->refresh == target_mode->refresh ||
1087 target_mode->refresh == 0))
1088 return (struct drm_mode *)output->base.current;
1089
1090 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1091 if (mode->mode_info.hdisplay == target_mode->width &&
1092 mode->mode_info.vdisplay == target_mode->height) {
1093 if (mode->mode_info.vrefresh == target_mode->refresh ||
1094 target_mode->refresh == 0) {
1095 return mode;
1096 } else if (!tmp_mode)
1097 tmp_mode = mode;
1098 }
1099 }
1100
1101 return tmp_mode;
1102}
1103
1104static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001105drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001106static int
1107drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001108
1109static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001110drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1111{
1112 struct drm_output *output;
1113 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001114 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001115
1116 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001117 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001118 return -1;
1119 }
1120
1121 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001122 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001123 return -1;
1124 }
1125
1126 ec = (struct drm_compositor *)output_base->compositor;
1127 output = (struct drm_output *)output_base;
1128 drm_mode = choose_mode (output, mode);
1129
1130 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001131 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001132 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001133 }
1134
1135 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001136 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001137
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001138 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001139
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001140 output->base.current = &drm_mode->base;
1141 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001142 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1143
Alex Wub7b8bda2012-04-17 17:20:48 +08001144 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001145 drm_output_release_fb(output, output->current);
1146 drm_output_release_fb(output, output->next);
1147 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001148
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001149 if (ec->use_pixman) {
1150 drm_output_fini_pixman(output);
1151 if (drm_output_init_pixman(output, ec) < 0) {
1152 weston_log("failed to init output pixman state with "
1153 "new mode\n");
1154 return -1;
1155 }
1156 } else {
1157 gl_renderer_output_destroy(&output->base);
1158 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001159
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001160 if (drm_output_init_egl(output, ec) < 0) {
1161 weston_log("failed to init output egl state with "
1162 "new mode");
1163 return -1;
1164 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001165 }
1166
Alex Wub7b8bda2012-04-17 17:20:48 +08001167 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001168}
1169
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001170static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001171on_drm_input(int fd, uint32_t mask, void *data)
1172{
1173 drmEventContext evctx;
1174
1175 memset(&evctx, 0, sizeof evctx);
1176 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1177 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001178 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001179 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001180
1181 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001182}
1183
1184static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001185init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001186{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001187 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001188 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001189
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001190 sysnum = udev_device_get_sysnum(device);
1191 if (sysnum)
1192 ec->drm.id = atoi(sysnum);
1193 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001194 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001195 return -1;
1196 }
1197
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001198 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001199 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001200 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001201 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001202 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001203 udev_device_get_devnode(device));
1204 return -1;
1205 }
1206
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001207 weston_log("using %s\n", filename);
1208
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001209 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001210
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001211
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001212 return 0;
1213}
1214
1215static int
1216init_egl(struct drm_compositor *ec)
1217{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001218 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001219
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001220 if (!ec->gbm)
1221 return -1;
1222
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001223 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001224 NULL) < 0) {
1225 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001226 return -1;
1227 }
1228
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001229 return 0;
1230}
1231
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001232static int
1233init_pixman(struct drm_compositor *ec)
1234{
1235 return pixman_renderer_init(&ec->base);
1236}
1237
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001238static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001239drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1240{
1241 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001242 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001243
1244 mode = malloc(sizeof *mode);
1245 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001246 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001247
1248 mode->base.flags = 0;
1249 mode->base.width = info->hdisplay;
1250 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001251
1252 /* Calculate higher precision (mHz) refresh rate */
1253 refresh = (info->clock * 1000000LL / info->htotal +
1254 info->vtotal / 2) / info->vtotal;
1255
1256 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1257 refresh *= 2;
1258 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1259 refresh /= 2;
1260 if (info->vscan > 1)
1261 refresh /= info->vscan;
1262
1263 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001264 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001265
1266 if (info->type & DRM_MODE_TYPE_PREFERRED)
1267 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1268
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001269 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1270
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001271 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001272}
1273
1274static int
1275drm_subpixel_to_wayland(int drm_value)
1276{
1277 switch (drm_value) {
1278 default:
1279 case DRM_MODE_SUBPIXEL_UNKNOWN:
1280 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1281 case DRM_MODE_SUBPIXEL_NONE:
1282 return WL_OUTPUT_SUBPIXEL_NONE;
1283 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1284 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1285 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1286 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1287 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1288 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1289 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1290 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1291 }
1292}
1293
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001294/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001295static uint32_t
1296drm_get_backlight(struct drm_output *output)
1297{
1298 long brightness, max_brightness, norm;
1299
1300 brightness = backlight_get_brightness(output->backlight);
1301 max_brightness = backlight_get_max_brightness(output->backlight);
1302
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001303 /* convert it on a scale of 0 to 255 */
1304 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001305
1306 return (uint32_t) norm;
1307}
1308
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001309/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001310static void
1311drm_set_backlight(struct weston_output *output_base, uint32_t value)
1312{
1313 struct drm_output *output = (struct drm_output *) output_base;
1314 long max_brightness, new_brightness;
1315
1316 if (!output->backlight)
1317 return;
1318
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001319 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001320 return;
1321
1322 max_brightness = backlight_get_max_brightness(output->backlight);
1323
1324 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001325 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001326
1327 backlight_set_brightness(output->backlight, new_brightness);
1328}
1329
1330static drmModePropertyPtr
1331drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1332{
1333 drmModePropertyPtr props;
1334 int i;
1335
1336 for (i = 0; i < connector->count_props; i++) {
1337 props = drmModeGetProperty(fd, connector->props[i]);
1338 if (!props)
1339 continue;
1340
1341 if (!strcmp(props->name, name))
1342 return props;
1343
1344 drmModeFreeProperty(props);
1345 }
1346
1347 return NULL;
1348}
1349
1350static void
1351drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1352{
1353 struct drm_output *output = (struct drm_output *) output_base;
1354 struct weston_compositor *ec = output_base->compositor;
1355 struct drm_compositor *c = (struct drm_compositor *) ec;
1356 drmModeConnectorPtr connector;
1357 drmModePropertyPtr prop;
1358
1359 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1360 if (!connector)
1361 return;
1362
1363 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1364 if (!prop) {
1365 drmModeFreeConnector(connector);
1366 return;
1367 }
1368
1369 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1370 prop->prop_id, level);
1371 drmModeFreeProperty(prop);
1372 drmModeFreeConnector(connector);
1373}
1374
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001375static const char *connector_type_names[] = {
1376 "None",
1377 "VGA",
1378 "DVI",
1379 "DVI",
1380 "DVI",
1381 "Composite",
1382 "TV",
1383 "LVDS",
1384 "CTV",
1385 "DIN",
1386 "DP",
1387 "HDMI",
1388 "HDMI",
1389 "TV",
1390 "eDP",
1391};
1392
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001393static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001394find_crtc_for_connector(struct drm_compositor *ec,
1395 drmModeRes *resources, drmModeConnector *connector)
1396{
1397 drmModeEncoder *encoder;
1398 uint32_t possible_crtcs;
1399 int i, j;
1400
1401 for (j = 0; j < connector->count_encoders; j++) {
1402 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1403 if (encoder == NULL) {
1404 weston_log("Failed to get encoder.\n");
1405 return -1;
1406 }
1407 possible_crtcs = encoder->possible_crtcs;
1408 drmModeFreeEncoder(encoder);
1409
1410 for (i = 0; i < resources->count_crtcs; i++) {
1411 if (possible_crtcs & (1 << i) &&
1412 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1413 return i;
1414 }
1415 }
1416
1417 return -1;
1418}
1419
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001420/* Init output state that depends on gl or gbm */
1421static int
1422drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1423{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001424 int i, flags;
1425
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001426 output->surface = gbm_surface_create(ec->gbm,
1427 output->base.current->width,
1428 output->base.current->height,
1429 GBM_FORMAT_XRGB8888,
1430 GBM_BO_USE_SCANOUT |
1431 GBM_BO_USE_RENDERING);
1432 if (!output->surface) {
1433 weston_log("failed to create gbm surface\n");
1434 return -1;
1435 }
1436
1437 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001438 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001439 gbm_surface_destroy(output->surface);
1440 return -1;
1441 }
1442
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001443 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1444
1445 for (i = 0; i < 2; i++) {
1446 if (output->cursor_bo[i])
1447 continue;
1448
1449 output->cursor_bo[i] =
1450 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1451 flags);
1452 }
1453
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001454 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1455 weston_log("cursor buffers unavailable, using gl cursors\n");
1456 ec->cursors_are_broken = 1;
1457 }
1458
1459 return 0;
1460}
1461
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001462static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001463drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1464{
1465 int w = output->base.current->width;
1466 int h = output->base.current->height;
1467 unsigned int i;
1468
1469 /* FIXME error checking */
1470
1471 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1472 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1473 if (!output->dumb[i])
1474 goto err;
1475
1476 output->image[i] =
1477 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1478 output->dumb[i]->map,
1479 output->dumb[i]->stride);
1480 if (!output->image[i])
1481 goto err;
1482 }
1483
1484 if (pixman_renderer_output_create(&output->base) < 0)
1485 goto err;
1486
1487 pixman_region32_init_rect(&output->previous_damage,
1488 output->base.x, output->base.y, w, h);
1489
1490 return 0;
1491
1492err:
1493 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1494 if (output->dumb[i])
1495 drm_fb_destroy_dumb(output->dumb[i]);
1496 if (output->image[i])
1497 pixman_image_unref(output->image[i]);
1498
1499 output->dumb[i] = NULL;
1500 output->image[i] = NULL;
1501 }
1502
1503 return -1;
1504}
1505
1506static void
1507drm_output_fini_pixman(struct drm_output *output)
1508{
1509 unsigned int i;
1510
1511 pixman_renderer_output_destroy(&output->base);
1512 pixman_region32_fini(&output->previous_damage);
1513
1514 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1515 drm_fb_destroy_dumb(output->dumb[i]);
1516 pixman_image_unref(output->image[i]);
1517 output->dumb[i] = NULL;
1518 output->image[i] = NULL;
1519 }
1520}
1521
Richard Hughes2b2092a2013-04-24 14:58:02 +01001522static void
1523edid_parse_string(const uint8_t *data, char text[])
1524{
1525 int i;
1526 int replaced = 0;
1527
1528 /* this is always 12 bytes, but we can't guarantee it's null
1529 * terminated or not junk. */
1530 strncpy(text, (const char *) data, 12);
1531
1532 /* remove insane chars */
1533 for (i = 0; text[i] != '\0'; i++) {
1534 if (text[i] == '\n' ||
1535 text[i] == '\r') {
1536 text[i] = '\0';
1537 break;
1538 }
1539 }
1540
1541 /* ensure string is printable */
1542 for (i = 0; text[i] != '\0'; i++) {
1543 if (!isprint(text[i])) {
1544 text[i] = '-';
1545 replaced++;
1546 }
1547 }
1548
1549 /* if the string is random junk, ignore the string */
1550 if (replaced > 4)
1551 text[0] = '\0';
1552}
1553
1554#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1555#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1556#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1557#define EDID_OFFSET_DATA_BLOCKS 0x36
1558#define EDID_OFFSET_LAST_BLOCK 0x6c
1559#define EDID_OFFSET_PNPID 0x08
1560#define EDID_OFFSET_SERIAL 0x0c
1561
1562static int
1563edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1564{
1565 int i;
1566 uint32_t serial_number;
1567
1568 /* check header */
1569 if (length < 128)
1570 return -1;
1571 if (data[0] != 0x00 || data[1] != 0xff)
1572 return -1;
1573
1574 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1575 * /--08--\/--09--\
1576 * 7654321076543210
1577 * |\---/\---/\---/
1578 * R C1 C2 C3 */
1579 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1580 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1581 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1582 edid->pnp_id[3] = '\0';
1583
1584 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1585 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1586 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1587 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1588 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1589 if (serial_number > 0)
1590 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1591
1592 /* parse EDID data */
1593 for (i = EDID_OFFSET_DATA_BLOCKS;
1594 i <= EDID_OFFSET_LAST_BLOCK;
1595 i += 18) {
1596 /* ignore pixel clock data */
1597 if (data[i] != 0)
1598 continue;
1599 if (data[i+2] != 0)
1600 continue;
1601
1602 /* any useful blocks? */
1603 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1604 edid_parse_string(&data[i+5],
1605 edid->monitor_name);
1606 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1607 edid_parse_string(&data[i+5],
1608 edid->serial_number);
1609 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1610 edid_parse_string(&data[i+5],
1611 edid->eisa_id);
1612 }
1613 }
1614 return 0;
1615}
1616
1617static void
1618find_and_parse_output_edid(struct drm_compositor *ec,
1619 struct drm_output *output,
1620 drmModeConnector *connector)
1621{
1622 drmModePropertyBlobPtr edid_blob = NULL;
1623 drmModePropertyPtr property;
1624 int i;
1625 int rc;
1626
1627 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1628 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1629 if (!property)
1630 continue;
1631 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1632 !strcmp(property->name, "EDID")) {
1633 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1634 connector->prop_values[i]);
1635 }
1636 drmModeFreeProperty(property);
1637 }
1638 if (!edid_blob)
1639 return;
1640
1641 rc = edid_parse(&output->edid,
1642 edid_blob->data,
1643 edid_blob->length);
1644 if (!rc) {
1645 weston_log("EDID data '%s', '%s', '%s'\n",
1646 output->edid.pnp_id,
1647 output->edid.monitor_name,
1648 output->edid.serial_number);
1649 if (output->edid.pnp_id[0] != '\0')
1650 output->base.make = output->edid.pnp_id;
1651 if (output->edid.monitor_name[0] != '\0')
1652 output->base.model = output->edid.monitor_name;
1653 if (output->edid.serial_number[0] != '\0')
1654 output->base.serial_number = output->edid.serial_number;
1655 }
1656 drmModeFreePropertyBlob(edid_blob);
1657}
1658
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001659static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001660create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001661 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001662 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001663 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001664{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001665 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001666 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1667 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001668 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001669 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001670 drmModeModeInfo crtc_mode;
1671 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001672 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001673 char name[32];
1674 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001675
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001676 i = find_crtc_for_connector(ec, resources, connector);
1677 if (i < 0) {
1678 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001679 return -1;
1680 }
1681
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001682 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001683 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001684 return -1;
1685
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001686 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001687 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1688 output->base.make = "unknown";
1689 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001690 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001691 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001692
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001693 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1694 type_name = connector_type_names[connector->connector_type];
1695 else
1696 type_name = "UNKNOWN";
1697 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1698 output->name = strdup(name);
1699
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001700 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001701 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001702 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001703 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001704 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001705
Matt Roper361d2ad2011-08-29 13:52:23 -07001706 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1707
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001708 /* Get the current mode on the crtc that's currently driving
1709 * this connector. */
1710 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001711 memset(&crtc_mode, 0, sizeof crtc_mode);
1712 if (encoder != NULL) {
1713 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1714 drmModeFreeEncoder(encoder);
1715 if (crtc == NULL)
1716 goto err_free;
1717 if (crtc->mode_valid)
1718 crtc_mode = crtc->mode;
1719 drmModeFreeCrtc(crtc);
1720 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001721
David Herrmann0f0d54e2011-12-08 17:05:45 +01001722 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001723 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1724 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001725 goto err_free;
1726 }
1727
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001728 preferred = NULL;
1729 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001730 configured = NULL;
1731
1732 wl_list_for_each(temp, &configured_output_list, link) {
1733 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001734 if (temp->mode)
1735 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001736 temp->name, temp->mode);
1737 o = temp;
1738 break;
1739 }
1740 }
1741
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001742 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001743 weston_log("Disabling output %s\n", o->name);
1744
1745 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1746 0, 0, 0, 0, 0, NULL);
1747 goto err_free;
1748 }
1749
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001750 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001751 if (o && o->config == OUTPUT_CONFIG_MODE &&
1752 o->width == drm_mode->base.width &&
1753 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001754 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001755 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001756 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001757 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001758 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001759 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001760
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001761 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001762 configured = drm_output_add_mode(output, &o->crtc_mode);
1763 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001764 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001765 current = configured;
1766 }
1767
Wang Quanxianacb805a2012-07-30 18:09:46 -04001768 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001769 current = drm_output_add_mode(output, &crtc_mode);
1770 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001771 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001772 }
1773
Scott Moreau8ab5d452012-07-30 19:51:08 -06001774 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1775 configured = current;
1776
Wang Quanxianacb805a2012-07-30 18:09:46 -04001777 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001778 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001779 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001780 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001781 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001782 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001783 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001784 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001785
1786 if (output->base.current == NULL) {
1787 weston_log("no available modes for %s\n", output->name);
1788 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001789 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001790
Wang Quanxianacb805a2012-07-30 18:09:46 -04001791 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1792
John Kåre Alsaker94659272012-11-13 19:10:18 +01001793 weston_output_init(&output->base, &ec->base, x, y,
1794 connector->mmWidth, connector->mmHeight,
1795 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1796
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001797 if (ec->use_pixman) {
1798 if (drm_output_init_pixman(output, ec) < 0) {
1799 weston_log("Failed to init output pixman state\n");
1800 goto err_output;
1801 }
1802 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001803 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001804 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001805 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001806
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001807 output->backlight = backlight_init(drm_device,
1808 connector->connector_type);
1809 if (output->backlight) {
1810 output->base.set_backlight = drm_set_backlight;
1811 output->base.backlight_current = drm_get_backlight(output);
1812 }
1813
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001814 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1815
Richard Hughes2b2092a2013-04-24 14:58:02 +01001816 find_and_parse_output_edid(ec, output, connector);
1817
Alex Wubd3354b2012-04-17 17:20:49 +08001818 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001819 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001820 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001821 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001822 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001823 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001824 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001825
Richard Hughese7299962013-05-01 21:52:12 +01001826 output->base.gamma_size = output->original_crtc->gamma_size;
1827 output->base.set_gamma = drm_output_set_gamma;
1828
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001829 weston_plane_init(&output->cursor_plane, 0, 0);
1830 weston_plane_init(&output->fb_plane, 0, 0);
1831
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001832 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1833 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1834 &ec->base.primary_plane);
1835
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001836 weston_log("Output %s, (connector %d, crtc %d)\n",
1837 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001838 wl_list_for_each(m, &output->base.mode_list, link)
1839 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1840 m->width, m->height, m->refresh / 1000.0,
1841 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1842 ", preferred" : "",
1843 m->flags & WL_OUTPUT_MODE_CURRENT ?
1844 ", current" : "",
1845 connector->count_modes == 0 ?
1846 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001847
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001848 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001849
John Kåre Alsaker94659272012-11-13 19:10:18 +01001850err_output:
1851 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001852err_free:
1853 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1854 base.link) {
1855 wl_list_remove(&drm_mode->base.link);
1856 free(drm_mode);
1857 }
1858
1859 drmModeFreeCrtc(output->original_crtc);
1860 ec->crtc_allocator &= ~(1 << output->crtc_id);
1861 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001862 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001863 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001864
David Herrmann0f0d54e2011-12-08 17:05:45 +01001865 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001866}
1867
Jesse Barnes58ef3792012-02-23 09:45:49 -05001868static void
1869create_sprites(struct drm_compositor *ec)
1870{
1871 struct drm_sprite *sprite;
1872 drmModePlaneRes *plane_res;
1873 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001874 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001875
1876 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1877 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001878 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001879 strerror(errno));
1880 return;
1881 }
1882
1883 for (i = 0; i < plane_res->count_planes; i++) {
1884 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1885 if (!plane)
1886 continue;
1887
1888 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1889 plane->count_formats));
1890 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001891 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001892 __func__);
1893 free(plane);
1894 continue;
1895 }
1896
1897 memset(sprite, 0, sizeof *sprite);
1898
1899 sprite->possible_crtcs = plane->possible_crtcs;
1900 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001901 sprite->current = NULL;
1902 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001903 sprite->compositor = ec;
1904 sprite->count_formats = plane->count_formats;
1905 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001906 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001907 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001908 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001909 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1910 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001911
1912 wl_list_insert(&ec->sprite_list, &sprite->link);
1913 }
1914
1915 free(plane_res->planes);
1916 free(plane_res);
1917}
1918
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001919static void
1920destroy_sprites(struct drm_compositor *compositor)
1921{
1922 struct drm_sprite *sprite, *next;
1923 struct drm_output *output;
1924
1925 output = container_of(compositor->base.output_list.next,
1926 struct drm_output, base.link);
1927
1928 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1929 drmModeSetPlane(compositor->drm.fd,
1930 sprite->plane_id,
1931 output->crtc_id, 0, 0,
1932 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001933 drm_output_release_fb(output, sprite->current);
1934 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001935 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001936 free(sprite);
1937 }
1938}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001939
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001940static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001941create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001942 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001943{
1944 drmModeConnector *connector;
1945 drmModeRes *resources;
1946 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001947 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001948
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001949 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001950 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001951 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001952 return -1;
1953 }
1954
Jesse Barnes58ef3792012-02-23 09:45:49 -05001955 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001956 if (!ec->crtcs) {
1957 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001958 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001959 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001960
Rob Clark4339add2012-08-09 14:18:28 -05001961 ec->min_width = resources->min_width;
1962 ec->max_width = resources->max_width;
1963 ec->min_height = resources->min_height;
1964 ec->max_height = resources->max_height;
1965
Jesse Barnes58ef3792012-02-23 09:45:49 -05001966 ec->num_crtcs = resources->count_crtcs;
1967 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1968
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001969 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001970 connector = drmModeGetConnector(ec->drm.fd,
1971 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001972 if (connector == NULL)
1973 continue;
1974
1975 if (connector->connection == DRM_MODE_CONNECTED &&
1976 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001977 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001978 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001979 connector, x, y,
1980 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001981 drmModeFreeConnector(connector);
1982 continue;
1983 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001984
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001985 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001986 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001987 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001988 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001989
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001990 drmModeFreeConnector(connector);
1991 }
1992
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001993 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001994 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001995 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001996 return -1;
1997 }
1998
1999 drmModeFreeResources(resources);
2000
2001 return 0;
2002}
2003
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002004static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002005update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002006{
2007 drmModeConnector *connector;
2008 drmModeRes *resources;
2009 struct drm_output *output, *next;
2010 int x = 0, y = 0;
2011 int x_offset = 0, y_offset = 0;
2012 uint32_t connected = 0, disconnects = 0;
2013 int i;
2014
2015 resources = drmModeGetResources(ec->drm.fd);
2016 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002017 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002018 return;
2019 }
2020
2021 /* collect new connects */
2022 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002023 int connector_id = resources->connectors[i];
2024
2025 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002026 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002027 continue;
2028
David Herrmann7551cff2011-12-08 17:05:43 +01002029 if (connector->connection != DRM_MODE_CONNECTED) {
2030 drmModeFreeConnector(connector);
2031 continue;
2032 }
2033
Benjamin Franzke117483d2011-08-30 11:38:26 +02002034 connected |= (1 << connector_id);
2035
2036 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002037 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002038 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002039 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002040
2041 /* XXX: not yet needed, we die with 0 outputs */
2042 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002043 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002044 else
2045 x = 0;
2046 y = 0;
2047 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002048 connector, x, y,
2049 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002050 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002051
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002052 }
2053 drmModeFreeConnector(connector);
2054 }
2055 drmModeFreeResources(resources);
2056
2057 disconnects = ec->connector_allocator & ~connected;
2058 if (disconnects) {
2059 wl_list_for_each_safe(output, next, &ec->base.output_list,
2060 base.link) {
2061 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002062 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002063 output->base.x - x_offset,
2064 output->base.y - y_offset);
2065 }
2066
2067 if (disconnects & (1 << output->connector_id)) {
2068 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002069 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002070 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002071 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002072 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002073 }
2074 }
2075 }
2076
2077 /* FIXME: handle zero outputs, without terminating */
2078 if (ec->connector_allocator == 0)
2079 wl_display_terminate(ec->base.wl_display);
2080}
2081
2082static int
David Herrmannd7488c22012-03-11 20:05:21 +01002083udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002084{
David Herrmannd7488c22012-03-11 20:05:21 +01002085 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002086 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002087
2088 sysnum = udev_device_get_sysnum(device);
2089 if (!sysnum || atoi(sysnum) != ec->drm.id)
2090 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002091
David Herrmann6ac52db2012-03-11 20:05:22 +01002092 val = udev_device_get_property_value(device, "HOTPLUG");
2093 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002094 return 0;
2095
David Herrmann6ac52db2012-03-11 20:05:22 +01002096 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002097}
2098
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002099static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002100udev_drm_event(int fd, uint32_t mask, void *data)
2101{
2102 struct drm_compositor *ec = data;
2103 struct udev_device *event;
2104
2105 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002106
David Herrmannd7488c22012-03-11 20:05:21 +01002107 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002108 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002109
2110 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002111
2112 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002113}
2114
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002115static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002116drm_restore(struct weston_compositor *ec)
2117{
2118 struct drm_compositor *d = (struct drm_compositor *) ec;
2119
2120 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2121 weston_log("failed to drop master: %m\n");
2122 tty_reset(d->tty);
2123}
2124
2125static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002126drm_free_configured_output(struct drm_configured_output *output)
2127{
2128 free(output->name);
2129 free(output->mode);
2130 free(output);
2131}
2132
2133static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002134drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002135{
2136 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002137 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002138 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002139
Kristian Høgsberge8091032013-02-18 15:43:29 -05002140 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2141 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002142 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002143 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002144
2145 wl_event_source_remove(d->udev_drm_source);
2146 wl_event_source_remove(d->drm_source);
2147
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002148 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002149
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002150 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002151
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002152 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002153
2154 if (d->gbm)
2155 gbm_device_destroy(d->gbm);
2156
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002157 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002158 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002159 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002160
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002161 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002162}
2163
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002164static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002165drm_compositor_set_modes(struct drm_compositor *compositor)
2166{
2167 struct drm_output *output;
2168 struct drm_mode *drm_mode;
2169 int ret;
2170
2171 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002172 if (!output->current) {
2173 /* If something that would cause the output to
2174 * switch mode happened while in another vt, we
2175 * might not have a current drm_fb. In that case,
2176 * schedule a repaint and let drm_output_repaint
2177 * handle setting the mode. */
2178 weston_output_schedule_repaint(&output->base);
2179 continue;
2180 }
2181
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002182 drm_mode = (struct drm_mode *) output->base.current;
2183 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002184 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002185 &output->connector_id, 1,
2186 &drm_mode->mode_info);
2187 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002188 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002189 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002190 drm_mode->base.width, drm_mode->base.height,
2191 output->base.x, output->base.y);
2192 }
2193 }
2194}
2195
2196static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002197vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002198{
2199 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002200 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002201 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002202 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002203
2204 switch (event) {
2205 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002206 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002207 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002208 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002209 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002210 wl_display_terminate(compositor->wl_display);
2211 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002212 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002213 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002214 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002215 wl_list_for_each(seat, &compositor->seat_list, base.link)
2216 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002217 break;
2218 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002219 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002220 wl_list_for_each(seat, &compositor->seat_list, base.link)
2221 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002222
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002223 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002224 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002225 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002226
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002227 /* If we have a repaint scheduled (either from a
2228 * pending pageflip or the idle handler), make sure we
2229 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002230 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002231 * further attemps at repainting. When we switch
2232 * back, we schedule a repaint, which will process
2233 * pending frame callbacks. */
2234
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002235 wl_list_for_each(output, &ec->base.output_list, base.link) {
2236 output->base.repaint_needed = 0;
2237 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002238 }
2239
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002240 output = container_of(ec->base.output_list.next,
2241 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002242
2243 wl_list_for_each(sprite, &ec->sprite_list, link)
2244 drmModeSetPlane(ec->drm.fd,
2245 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002246 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002247 0, 0, 0, 0, 0, 0, 0, 0);
2248
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002249 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002250 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002251
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002252 break;
2253 };
2254}
2255
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002256static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002257switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002258{
2259 struct drm_compositor *ec = data;
2260
Daniel Stone325fc2d2012-05-30 16:31:58 +01002261 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002262}
2263
David Herrmann0af066f2012-10-29 19:21:16 +01002264/*
2265 * Find primary GPU
2266 * Some systems may have multiple DRM devices attached to a single seat. This
2267 * function loops over all devices and tries to find a PCI device with the
2268 * boot_vga sysfs attribute set to 1.
2269 * If no such device is found, the first DRM device reported by udev is used.
2270 */
2271static struct udev_device*
2272find_primary_gpu(struct drm_compositor *ec, const char *seat)
2273{
2274 struct udev_enumerate *e;
2275 struct udev_list_entry *entry;
2276 const char *path, *device_seat, *id;
2277 struct udev_device *device, *drm_device, *pci;
2278
2279 e = udev_enumerate_new(ec->udev);
2280 udev_enumerate_add_match_subsystem(e, "drm");
2281 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2282
2283 udev_enumerate_scan_devices(e);
2284 drm_device = NULL;
2285 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2286 path = udev_list_entry_get_name(entry);
2287 device = udev_device_new_from_syspath(ec->udev, path);
2288 if (!device)
2289 continue;
2290 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2291 if (!device_seat)
2292 device_seat = default_seat;
2293 if (strcmp(device_seat, seat)) {
2294 udev_device_unref(device);
2295 continue;
2296 }
2297
2298 pci = udev_device_get_parent_with_subsystem_devtype(device,
2299 "pci", NULL);
2300 if (pci) {
2301 id = udev_device_get_sysattr_value(pci, "boot_vga");
2302 if (id && !strcmp(id, "1")) {
2303 if (drm_device)
2304 udev_device_unref(drm_device);
2305 drm_device = device;
2306 break;
2307 }
2308 }
2309
2310 if (!drm_device)
2311 drm_device = device;
2312 else
2313 udev_device_unref(device);
2314 }
2315
2316 udev_enumerate_unref(e);
2317 return drm_device;
2318}
2319
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002320static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002321planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002322{
2323 struct drm_compositor *c = data;
2324
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002325 switch (key) {
2326 case KEY_C:
2327 c->cursors_are_broken ^= 1;
2328 break;
2329 case KEY_V:
2330 c->sprites_are_broken ^= 1;
2331 break;
2332 case KEY_O:
2333 c->sprites_hidden ^= 1;
2334 break;
2335 default:
2336 break;
2337 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002338}
2339
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002340static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002341drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002342 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002343 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002344{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002345 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002346 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002347 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002348 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002349 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002350 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002351
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002352 weston_log("initializing drm backend\n");
2353
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002354 ec = malloc(sizeof *ec);
2355 if (ec == NULL)
2356 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002357 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002358
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002359 /* KMS support for sprites is not complete yet, so disable the
2360 * functionality for now. */
2361 ec->sprites_are_broken = 1;
2362
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002363 ec->use_pixman = pixman;
2364
Daniel Stone725c2c32012-06-22 14:04:36 +01002365 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002366 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002367 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002368 goto err_base;
2369 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002370
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002371 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002372 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002373 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002374 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002375 goto err_compositor;
2376 }
2377
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002378 ec->udev = udev_new();
2379 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002380 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002381 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002382 }
2383
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002384 ec->base.wl_display = display;
2385 ec->tty = tty_create(&ec->base, vt_func, tty);
2386 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002387 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002388 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002389 }
2390
David Herrmann0af066f2012-10-29 19:21:16 +01002391 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002392 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002393 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002394 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002395 }
David Herrmann0af066f2012-10-29 19:21:16 +01002396 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002397
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002398 if (init_drm(ec, drm_device) < 0) {
2399 weston_log("failed to initialize kms\n");
2400 goto err_udev_dev;
2401 }
2402
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002403 if (ec->use_pixman) {
2404 if (init_pixman(ec) < 0) {
2405 weston_log("failed to initialize pixman renderer\n");
2406 goto err_udev_dev;
2407 }
2408 } else {
2409 if (init_egl(ec) < 0) {
2410 weston_log("failed to initialize egl\n");
2411 goto err_udev_dev;
2412 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002413 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002414
2415 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002416 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002417
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002418 ec->base.focus = 1;
2419
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002420 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002421
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002422 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002423 weston_compositor_add_key_binding(&ec->base, key,
2424 MODIFIER_CTRL | MODIFIER_ALT,
2425 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002426
Jesse Barnes58ef3792012-02-23 09:45:49 -05002427 wl_list_init(&ec->sprite_list);
2428 create_sprites(ec);
2429
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002430 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002431 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002432 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002433 }
2434
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002435 path = NULL;
2436
Kristian Høgsberge8091032013-02-18 15:43:29 -05002437 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002438 weston_log("failed to create input devices\n");
2439 goto err_sprite;
2440 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002441
2442 loop = wl_display_get_event_loop(ec->base.wl_display);
2443 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002444 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002445 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002446
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002447 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2448 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002449 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002450 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002451 }
2452 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2453 "drm", NULL);
2454 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002455 wl_event_loop_add_fd(loop,
2456 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002457 WL_EVENT_READABLE, udev_drm_event, ec);
2458
2459 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002460 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002461 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002462 }
2463
Daniel Stonea96b93c2012-06-22 14:04:37 +01002464 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002465
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002466 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002467 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002468 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002469 planes_binding, ec);
2470 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2471 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002472
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002473 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002474
2475err_udev_monitor:
2476 wl_event_source_remove(ec->udev_drm_source);
2477 udev_monitor_unref(ec->udev_monitor);
2478err_drm_source:
2479 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002480 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2481 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002482err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002483 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002484 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002485 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002486err_udev_dev:
2487 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002488err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002489 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2490 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002491 tty_destroy(ec->tty);
2492err_udev:
2493 udev_unref(ec->udev);
2494err_compositor:
2495 weston_compositor_shutdown(&ec->base);
2496err_base:
2497 free(ec);
2498 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002499}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002500
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002501static int
2502set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2503{
2504 mode->flags = 0;
2505
2506 if (strcmp(hsync, "+hsync") == 0)
2507 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2508 else if (strcmp(hsync, "-hsync") == 0)
2509 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2510 else
2511 return -1;
2512
2513 if (strcmp(vsync, "+vsync") == 0)
2514 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2515 else if (strcmp(vsync, "-vsync") == 0)
2516 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2517 else
2518 return -1;
2519
2520 return 0;
2521}
2522
2523static int
2524check_for_modeline(struct drm_configured_output *output)
2525{
2526 drmModeModeInfo mode;
2527 char hsync[16];
2528 char vsync[16];
2529 char mode_name[16];
2530 float fclock;
2531
2532 mode.type = DRM_MODE_TYPE_USERDEF;
2533 mode.hskew = 0;
2534 mode.vscan = 0;
2535 mode.vrefresh = 0;
2536
2537 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2538 &fclock, &mode.hdisplay,
2539 &mode.hsync_start,
2540 &mode.hsync_end, &mode.htotal,
2541 &mode.vdisplay,
2542 &mode.vsync_start,
2543 &mode.vsync_end, &mode.vtotal,
2544 hsync, vsync) == 11) {
2545 if (set_sync_flags(&mode, hsync, vsync))
2546 return -1;
2547
2548 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2549 strcpy(mode.name, mode_name);
2550
2551 mode.clock = fclock * 1000;
2552 } else
2553 return -1;
2554
2555 output->crtc_mode = mode;
2556
2557 return 0;
2558}
2559
Scott Moreau8ab5d452012-07-30 19:51:08 -06002560static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002561drm_output_set_transform(struct drm_configured_output *output)
2562{
2563 if (!output_transform) {
2564 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2565 return;
2566 }
2567
2568 if (!strcmp(output_transform, "normal"))
2569 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2570 else if (!strcmp(output_transform, "90"))
2571 output->transform = WL_OUTPUT_TRANSFORM_90;
2572 else if (!strcmp(output_transform, "180"))
2573 output->transform = WL_OUTPUT_TRANSFORM_180;
2574 else if (!strcmp(output_transform, "270"))
2575 output->transform = WL_OUTPUT_TRANSFORM_270;
2576 else if (!strcmp(output_transform, "flipped"))
2577 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2578 else if (!strcmp(output_transform, "flipped-90"))
2579 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2580 else if (!strcmp(output_transform, "flipped-180"))
2581 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2582 else if (!strcmp(output_transform, "flipped-270"))
2583 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2584 else {
2585 weston_log("Invalid transform \"%s\" for output %s\n",
2586 output_transform, output_name);
2587 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2588 }
2589
2590 free(output_transform);
2591 output_transform = NULL;
2592}
2593
2594static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002595output_section_done(void *data)
2596{
2597 struct drm_configured_output *output;
2598
2599 output = malloc(sizeof *output);
2600
Scott Moreau1bad5db2012-08-18 01:04:05 -06002601 if (!output || !output_name || (output_name[0] == 'X') ||
2602 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002603 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002604 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002605 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002606 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002607 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002608 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002609 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002610 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002611 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002612
2613 output->config = OUTPUT_CONFIG_INVALID;
2614 output->name = output_name;
2615 output->mode = output_mode;
2616
Scott Moreau1bad5db2012-08-18 01:04:05 -06002617 if (output_mode) {
2618 if (strcmp(output_mode, "off") == 0)
2619 output->config = OUTPUT_CONFIG_OFF;
2620 else if (strcmp(output_mode, "preferred") == 0)
2621 output->config = OUTPUT_CONFIG_PREFERRED;
2622 else if (strcmp(output_mode, "current") == 0)
2623 output->config = OUTPUT_CONFIG_CURRENT;
2624 else if (sscanf(output_mode, "%dx%d",
2625 &output->width, &output->height) == 2)
2626 output->config = OUTPUT_CONFIG_MODE;
2627 else if (check_for_modeline(output) == 0)
2628 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002629
Scott Moreau1bad5db2012-08-18 01:04:05 -06002630 if (output->config == OUTPUT_CONFIG_INVALID)
2631 weston_log("Invalid mode \"%s\" for output %s\n",
2632 output_mode, output_name);
2633 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002634 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002635
2636 drm_output_set_transform(output);
2637
2638 wl_list_insert(&configured_output_list, &output->link);
2639
2640 if (output_transform)
2641 free(output_transform);
2642 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002643}
2644
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002645WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002646backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002647 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002648{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002649 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002650 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002651
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002652 const struct weston_option drm_options[] = {
2653 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2654 { WESTON_OPTION_STRING, "seat", 0, &seat },
2655 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002656 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002657 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002658 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002659
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002660 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002661
Scott Moreau8ab5d452012-07-30 19:51:08 -06002662 wl_list_init(&configured_output_list);
2663
2664 const struct config_key drm_config_keys[] = {
2665 { "name", CONFIG_KEY_STRING, &output_name },
2666 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002667 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002668 };
2669
2670 const struct config_section config_section[] = {
2671 { "output", drm_config_keys,
2672 ARRAY_LENGTH(drm_config_keys), output_section_done },
2673 };
2674
2675 parse_config_file(config_file, config_section,
2676 ARRAY_LENGTH(config_section), NULL);
2677
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002678 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2679 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002680}