blob: bb8ea46cea630a82cbc1410f254c9062f37cd78b [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 Hughesb24e48e2013-05-09 20:31:09 +010032#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010033#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034#include <string.h>
35#include <fcntl.h>
36#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040037#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030038#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020039#include <sys/mman.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040040
Benjamin Franzkec649a922011-03-02 11:56:04 +010041#include <xf86drm.h>
42#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050043#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010044
Benjamin Franzke060cf802011-04-30 09:32:11 +020045#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020046#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040047#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020048
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040049#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010050#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020051#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050052#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010053#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040054
Kristian Høgsberg061c4252012-06-28 11:28:15 -040055static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060056static char *output_name;
57static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060058static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060059static struct wl_list configured_output_list;
60
61enum output_config {
62 OUTPUT_CONFIG_INVALID = 0,
63 OUTPUT_CONFIG_OFF,
64 OUTPUT_CONFIG_PREFERRED,
65 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060066 OUTPUT_CONFIG_MODE,
67 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060068};
69
70struct drm_configured_output {
71 char *name;
72 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060073 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060074 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060075 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060076 enum output_config config;
77 struct wl_list link;
78};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040079
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040080struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050081 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040082
83 struct udev *udev;
84 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040085
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010086 struct udev_monitor *udev_monitor;
87 struct wl_event_source *udev_drm_source;
88
Benjamin Franzke2af7f102011-03-02 11:14:59 +010089 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010090 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010091 int fd;
92 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020093 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050094 uint32_t *crtcs;
95 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050096 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010097 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050098 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020099
Rob Clark4339add2012-08-09 14:18:28 -0500100 /* we need these parameters in order to not fail drmModeAddFB2()
101 * due to out of bounds dimensions, and then mistakenly set
102 * sprites_are_broken:
103 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200104 uint32_t min_width, max_width;
105 uint32_t min_height, max_height;
106 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500107
Jesse Barnes58ef3792012-02-23 09:45:49 -0500108 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500109 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200110 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500111
Rob Clarkab5b1e32012-08-09 13:24:45 -0500112 int cursors_are_broken;
113
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200114 int use_pixman;
115
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200116 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400117};
118
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400119struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500120 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400121 drmModeModeInfo mode_info;
122};
123
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124struct drm_output;
125
126struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300127 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200128 uint32_t fb_id, stride, handle, size;
129 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300130 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200131 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200132
133 /* Used by gbm fbs */
134 struct gbm_bo *bo;
135
136 /* Used by dumb fbs */
137 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300138};
139
Richard Hughes2b2092a2013-04-24 14:58:02 +0100140struct drm_edid {
141 char eisa_id[13];
142 char monitor_name[13];
143 char pnp_id[5];
144 char serial_number[13];
145};
146
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400147struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500148 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400149
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
Matt Roper361d2ad2011-08-29 13:52:23 -07001075 free(output);
1076}
1077
Alex Wub7b8bda2012-04-17 17:20:48 +08001078static struct drm_mode *
1079choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1080{
1081 struct drm_mode *tmp_mode = NULL, *mode;
1082
1083 if (output->base.current->width == target_mode->width &&
1084 output->base.current->height == target_mode->height &&
1085 (output->base.current->refresh == target_mode->refresh ||
1086 target_mode->refresh == 0))
1087 return (struct drm_mode *)output->base.current;
1088
1089 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1090 if (mode->mode_info.hdisplay == target_mode->width &&
1091 mode->mode_info.vdisplay == target_mode->height) {
1092 if (mode->mode_info.vrefresh == target_mode->refresh ||
1093 target_mode->refresh == 0) {
1094 return mode;
1095 } else if (!tmp_mode)
1096 tmp_mode = mode;
1097 }
1098 }
1099
1100 return tmp_mode;
1101}
1102
1103static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001104drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001105static int
1106drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001107
1108static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001109drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1110{
1111 struct drm_output *output;
1112 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001113 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001114
1115 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001116 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001117 return -1;
1118 }
1119
1120 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001121 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001122 return -1;
1123 }
1124
1125 ec = (struct drm_compositor *)output_base->compositor;
1126 output = (struct drm_output *)output_base;
1127 drm_mode = choose_mode (output, mode);
1128
1129 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001130 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001131 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001132 }
1133
1134 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001135 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001136
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001137 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001138
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001139 output->base.current = &drm_mode->base;
1140 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001141 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1142
Alex Wub7b8bda2012-04-17 17:20:48 +08001143 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001144 drm_output_release_fb(output, output->current);
1145 drm_output_release_fb(output, output->next);
1146 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001147
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001148 if (ec->use_pixman) {
1149 drm_output_fini_pixman(output);
1150 if (drm_output_init_pixman(output, ec) < 0) {
1151 weston_log("failed to init output pixman state with "
1152 "new mode\n");
1153 return -1;
1154 }
1155 } else {
1156 gl_renderer_output_destroy(&output->base);
1157 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001158
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001159 if (drm_output_init_egl(output, ec) < 0) {
1160 weston_log("failed to init output egl state with "
1161 "new mode");
1162 return -1;
1163 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001164 }
1165
Alex Wub7b8bda2012-04-17 17:20:48 +08001166 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001167}
1168
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001169static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001170on_drm_input(int fd, uint32_t mask, void *data)
1171{
1172 drmEventContext evctx;
1173
1174 memset(&evctx, 0, sizeof evctx);
1175 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1176 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001177 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001178 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001179
1180 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001181}
1182
1183static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001184init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001185{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001186 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001187 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001188
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001189 sysnum = udev_device_get_sysnum(device);
1190 if (sysnum)
1191 ec->drm.id = atoi(sysnum);
1192 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001193 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001194 return -1;
1195 }
1196
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001197 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001198 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001199 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001200 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001201 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001202 udev_device_get_devnode(device));
1203 return -1;
1204 }
1205
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001206 weston_log("using %s\n", filename);
1207
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001208 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001209
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001210
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001211 return 0;
1212}
1213
1214static int
1215init_egl(struct drm_compositor *ec)
1216{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001217 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001218
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001219 if (!ec->gbm)
1220 return -1;
1221
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001222 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001223 NULL) < 0) {
1224 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001225 return -1;
1226 }
1227
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001228 return 0;
1229}
1230
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001231static int
1232init_pixman(struct drm_compositor *ec)
1233{
1234 return pixman_renderer_init(&ec->base);
1235}
1236
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001237static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001238drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1239{
1240 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001241 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001242
1243 mode = malloc(sizeof *mode);
1244 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001245 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001246
1247 mode->base.flags = 0;
1248 mode->base.width = info->hdisplay;
1249 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001250
1251 /* Calculate higher precision (mHz) refresh rate */
1252 refresh = (info->clock * 1000000LL / info->htotal +
1253 info->vtotal / 2) / info->vtotal;
1254
1255 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1256 refresh *= 2;
1257 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1258 refresh /= 2;
1259 if (info->vscan > 1)
1260 refresh /= info->vscan;
1261
1262 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001263 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001264
1265 if (info->type & DRM_MODE_TYPE_PREFERRED)
1266 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1267
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001268 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1269
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001270 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001271}
1272
1273static int
1274drm_subpixel_to_wayland(int drm_value)
1275{
1276 switch (drm_value) {
1277 default:
1278 case DRM_MODE_SUBPIXEL_UNKNOWN:
1279 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1280 case DRM_MODE_SUBPIXEL_NONE:
1281 return WL_OUTPUT_SUBPIXEL_NONE;
1282 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1283 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1284 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1285 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1286 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1287 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1288 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1289 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1290 }
1291}
1292
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001293/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001294static uint32_t
1295drm_get_backlight(struct drm_output *output)
1296{
1297 long brightness, max_brightness, norm;
1298
1299 brightness = backlight_get_brightness(output->backlight);
1300 max_brightness = backlight_get_max_brightness(output->backlight);
1301
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001302 /* convert it on a scale of 0 to 255 */
1303 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001304
1305 return (uint32_t) norm;
1306}
1307
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001308/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001309static void
1310drm_set_backlight(struct weston_output *output_base, uint32_t value)
1311{
1312 struct drm_output *output = (struct drm_output *) output_base;
1313 long max_brightness, new_brightness;
1314
1315 if (!output->backlight)
1316 return;
1317
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001318 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001319 return;
1320
1321 max_brightness = backlight_get_max_brightness(output->backlight);
1322
1323 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001324 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001325
1326 backlight_set_brightness(output->backlight, new_brightness);
1327}
1328
1329static drmModePropertyPtr
1330drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1331{
1332 drmModePropertyPtr props;
1333 int i;
1334
1335 for (i = 0; i < connector->count_props; i++) {
1336 props = drmModeGetProperty(fd, connector->props[i]);
1337 if (!props)
1338 continue;
1339
1340 if (!strcmp(props->name, name))
1341 return props;
1342
1343 drmModeFreeProperty(props);
1344 }
1345
1346 return NULL;
1347}
1348
1349static void
1350drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1351{
1352 struct drm_output *output = (struct drm_output *) output_base;
1353 struct weston_compositor *ec = output_base->compositor;
1354 struct drm_compositor *c = (struct drm_compositor *) ec;
1355 drmModeConnectorPtr connector;
1356 drmModePropertyPtr prop;
1357
1358 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1359 if (!connector)
1360 return;
1361
1362 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1363 if (!prop) {
1364 drmModeFreeConnector(connector);
1365 return;
1366 }
1367
1368 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1369 prop->prop_id, level);
1370 drmModeFreeProperty(prop);
1371 drmModeFreeConnector(connector);
1372}
1373
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001374static const char *connector_type_names[] = {
1375 "None",
1376 "VGA",
1377 "DVI",
1378 "DVI",
1379 "DVI",
1380 "Composite",
1381 "TV",
1382 "LVDS",
1383 "CTV",
1384 "DIN",
1385 "DP",
1386 "HDMI",
1387 "HDMI",
1388 "TV",
1389 "eDP",
1390};
1391
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001392static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001393find_crtc_for_connector(struct drm_compositor *ec,
1394 drmModeRes *resources, drmModeConnector *connector)
1395{
1396 drmModeEncoder *encoder;
1397 uint32_t possible_crtcs;
1398 int i, j;
1399
1400 for (j = 0; j < connector->count_encoders; j++) {
1401 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1402 if (encoder == NULL) {
1403 weston_log("Failed to get encoder.\n");
1404 return -1;
1405 }
1406 possible_crtcs = encoder->possible_crtcs;
1407 drmModeFreeEncoder(encoder);
1408
1409 for (i = 0; i < resources->count_crtcs; i++) {
1410 if (possible_crtcs & (1 << i) &&
1411 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1412 return i;
1413 }
1414 }
1415
1416 return -1;
1417}
1418
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001419/* Init output state that depends on gl or gbm */
1420static int
1421drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1422{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001423 int i, flags;
1424
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001425 output->surface = gbm_surface_create(ec->gbm,
1426 output->base.current->width,
1427 output->base.current->height,
1428 GBM_FORMAT_XRGB8888,
1429 GBM_BO_USE_SCANOUT |
1430 GBM_BO_USE_RENDERING);
1431 if (!output->surface) {
1432 weston_log("failed to create gbm surface\n");
1433 return -1;
1434 }
1435
1436 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001437 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001438 gbm_surface_destroy(output->surface);
1439 return -1;
1440 }
1441
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001442 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1443
1444 for (i = 0; i < 2; i++) {
1445 if (output->cursor_bo[i])
1446 continue;
1447
1448 output->cursor_bo[i] =
1449 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1450 flags);
1451 }
1452
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001453 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1454 weston_log("cursor buffers unavailable, using gl cursors\n");
1455 ec->cursors_are_broken = 1;
1456 }
1457
1458 return 0;
1459}
1460
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001461static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001462drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1463{
1464 int w = output->base.current->width;
1465 int h = output->base.current->height;
1466 unsigned int i;
1467
1468 /* FIXME error checking */
1469
1470 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1471 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1472 if (!output->dumb[i])
1473 goto err;
1474
1475 output->image[i] =
1476 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1477 output->dumb[i]->map,
1478 output->dumb[i]->stride);
1479 if (!output->image[i])
1480 goto err;
1481 }
1482
1483 if (pixman_renderer_output_create(&output->base) < 0)
1484 goto err;
1485
1486 pixman_region32_init_rect(&output->previous_damage,
1487 output->base.x, output->base.y, w, h);
1488
1489 return 0;
1490
1491err:
1492 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1493 if (output->dumb[i])
1494 drm_fb_destroy_dumb(output->dumb[i]);
1495 if (output->image[i])
1496 pixman_image_unref(output->image[i]);
1497
1498 output->dumb[i] = NULL;
1499 output->image[i] = NULL;
1500 }
1501
1502 return -1;
1503}
1504
1505static void
1506drm_output_fini_pixman(struct drm_output *output)
1507{
1508 unsigned int i;
1509
1510 pixman_renderer_output_destroy(&output->base);
1511 pixman_region32_fini(&output->previous_damage);
1512
1513 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1514 drm_fb_destroy_dumb(output->dumb[i]);
1515 pixman_image_unref(output->image[i]);
1516 output->dumb[i] = NULL;
1517 output->image[i] = NULL;
1518 }
1519}
1520
Richard Hughes2b2092a2013-04-24 14:58:02 +01001521static void
1522edid_parse_string(const uint8_t *data, char text[])
1523{
1524 int i;
1525 int replaced = 0;
1526
1527 /* this is always 12 bytes, but we can't guarantee it's null
1528 * terminated or not junk. */
1529 strncpy(text, (const char *) data, 12);
1530
1531 /* remove insane chars */
1532 for (i = 0; text[i] != '\0'; i++) {
1533 if (text[i] == '\n' ||
1534 text[i] == '\r') {
1535 text[i] = '\0';
1536 break;
1537 }
1538 }
1539
1540 /* ensure string is printable */
1541 for (i = 0; text[i] != '\0'; i++) {
1542 if (!isprint(text[i])) {
1543 text[i] = '-';
1544 replaced++;
1545 }
1546 }
1547
1548 /* if the string is random junk, ignore the string */
1549 if (replaced > 4)
1550 text[0] = '\0';
1551}
1552
1553#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1554#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1555#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1556#define EDID_OFFSET_DATA_BLOCKS 0x36
1557#define EDID_OFFSET_LAST_BLOCK 0x6c
1558#define EDID_OFFSET_PNPID 0x08
1559#define EDID_OFFSET_SERIAL 0x0c
1560
1561static int
1562edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1563{
1564 int i;
1565 uint32_t serial_number;
1566
1567 /* check header */
1568 if (length < 128)
1569 return -1;
1570 if (data[0] != 0x00 || data[1] != 0xff)
1571 return -1;
1572
1573 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1574 * /--08--\/--09--\
1575 * 7654321076543210
1576 * |\---/\---/\---/
1577 * R C1 C2 C3 */
1578 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1579 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1580 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1581 edid->pnp_id[3] = '\0';
1582
1583 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1584 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1585 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1586 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1587 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1588 if (serial_number > 0)
1589 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1590
1591 /* parse EDID data */
1592 for (i = EDID_OFFSET_DATA_BLOCKS;
1593 i <= EDID_OFFSET_LAST_BLOCK;
1594 i += 18) {
1595 /* ignore pixel clock data */
1596 if (data[i] != 0)
1597 continue;
1598 if (data[i+2] != 0)
1599 continue;
1600
1601 /* any useful blocks? */
1602 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1603 edid_parse_string(&data[i+5],
1604 edid->monitor_name);
1605 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1606 edid_parse_string(&data[i+5],
1607 edid->serial_number);
1608 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1609 edid_parse_string(&data[i+5],
1610 edid->eisa_id);
1611 }
1612 }
1613 return 0;
1614}
1615
1616static void
1617find_and_parse_output_edid(struct drm_compositor *ec,
1618 struct drm_output *output,
1619 drmModeConnector *connector)
1620{
1621 drmModePropertyBlobPtr edid_blob = NULL;
1622 drmModePropertyPtr property;
1623 int i;
1624 int rc;
1625
1626 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1627 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1628 if (!property)
1629 continue;
1630 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1631 !strcmp(property->name, "EDID")) {
1632 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1633 connector->prop_values[i]);
1634 }
1635 drmModeFreeProperty(property);
1636 }
1637 if (!edid_blob)
1638 return;
1639
1640 rc = edid_parse(&output->edid,
1641 edid_blob->data,
1642 edid_blob->length);
1643 if (!rc) {
1644 weston_log("EDID data '%s', '%s', '%s'\n",
1645 output->edid.pnp_id,
1646 output->edid.monitor_name,
1647 output->edid.serial_number);
1648 if (output->edid.pnp_id[0] != '\0')
1649 output->base.make = output->edid.pnp_id;
1650 if (output->edid.monitor_name[0] != '\0')
1651 output->base.model = output->edid.monitor_name;
1652 if (output->edid.serial_number[0] != '\0')
1653 output->base.serial_number = output->edid.serial_number;
1654 }
1655 drmModeFreePropertyBlob(edid_blob);
1656}
1657
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001658static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001659create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001660 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001661 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001662 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001663{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001664 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001665 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1666 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001667 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001668 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001669 drmModeModeInfo crtc_mode;
1670 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001671 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001672 char name[32];
1673 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001674
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001675 i = find_crtc_for_connector(ec, resources, connector);
1676 if (i < 0) {
1677 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001678 return -1;
1679 }
1680
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001681 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001682 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001683 return -1;
1684
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001685 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001686 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1687 output->base.make = "unknown";
1688 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001689 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001690 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001691
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001692 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1693 type_name = connector_type_names[connector->connector_type];
1694 else
1695 type_name = "UNKNOWN";
1696 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001697 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001698
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001699 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001700 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001701 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001702 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001703 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001704
Matt Roper361d2ad2011-08-29 13:52:23 -07001705 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1706
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001707 /* Get the current mode on the crtc that's currently driving
1708 * this connector. */
1709 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001710 memset(&crtc_mode, 0, sizeof crtc_mode);
1711 if (encoder != NULL) {
1712 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1713 drmModeFreeEncoder(encoder);
1714 if (crtc == NULL)
1715 goto err_free;
1716 if (crtc->mode_valid)
1717 crtc_mode = crtc->mode;
1718 drmModeFreeCrtc(crtc);
1719 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001720
David Herrmann0f0d54e2011-12-08 17:05:45 +01001721 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001722 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1723 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001724 goto err_free;
1725 }
1726
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001727 preferred = NULL;
1728 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001729 configured = NULL;
1730
1731 wl_list_for_each(temp, &configured_output_list, link) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001732 if (strcmp(temp->name, output->base.name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001733 if (temp->mode)
1734 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001735 temp->name, temp->mode);
1736 o = temp;
1737 break;
1738 }
1739 }
1740
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001741 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001742 weston_log("Disabling output %s\n", o->name);
1743
1744 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1745 0, 0, 0, 0, 0, NULL);
1746 goto err_free;
1747 }
1748
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001749 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001750 if (o && o->config == OUTPUT_CONFIG_MODE &&
1751 o->width == drm_mode->base.width &&
1752 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001753 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001754 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001755 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001756 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001757 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001758 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001759
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001760 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001761 configured = drm_output_add_mode(output, &o->crtc_mode);
1762 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001763 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001764 current = configured;
1765 }
1766
Wang Quanxianacb805a2012-07-30 18:09:46 -04001767 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001768 current = drm_output_add_mode(output, &crtc_mode);
1769 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001770 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001771 }
1772
Scott Moreau8ab5d452012-07-30 19:51:08 -06001773 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1774 configured = current;
1775
Wang Quanxianacb805a2012-07-30 18:09:46 -04001776 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001777 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001778 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001779 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001780 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001781 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001782 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001783 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001784
1785 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001786 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001787 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001788 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001789
Wang Quanxianacb805a2012-07-30 18:09:46 -04001790 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1791
John Kåre Alsaker94659272012-11-13 19:10:18 +01001792 weston_output_init(&output->base, &ec->base, x, y,
1793 connector->mmWidth, connector->mmHeight,
1794 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1795
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001796 if (ec->use_pixman) {
1797 if (drm_output_init_pixman(output, ec) < 0) {
1798 weston_log("Failed to init output pixman state\n");
1799 goto err_output;
1800 }
1801 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001802 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001803 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001804 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001805
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001806 output->backlight = backlight_init(drm_device,
1807 connector->connector_type);
1808 if (output->backlight) {
1809 output->base.set_backlight = drm_set_backlight;
1810 output->base.backlight_current = drm_get_backlight(output);
1811 }
1812
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001813 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1814
Richard Hughes2b2092a2013-04-24 14:58:02 +01001815 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001816 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1817 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001818
Alex Wubd3354b2012-04-17 17:20:49 +08001819 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001820 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001821 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001822 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001823 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001824 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001825 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001826
Richard Hughese7299962013-05-01 21:52:12 +01001827 output->base.gamma_size = output->original_crtc->gamma_size;
1828 output->base.set_gamma = drm_output_set_gamma;
1829
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001830 weston_plane_init(&output->cursor_plane, 0, 0);
1831 weston_plane_init(&output->fb_plane, 0, 0);
1832
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001833 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1834 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1835 &ec->base.primary_plane);
1836
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001837 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001838 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001839 wl_list_for_each(m, &output->base.mode_list, link)
1840 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1841 m->width, m->height, m->refresh / 1000.0,
1842 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1843 ", preferred" : "",
1844 m->flags & WL_OUTPUT_MODE_CURRENT ?
1845 ", current" : "",
1846 connector->count_modes == 0 ?
1847 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001848
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001849 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001850
John Kåre Alsaker94659272012-11-13 19:10:18 +01001851err_output:
1852 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001853err_free:
1854 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1855 base.link) {
1856 wl_list_remove(&drm_mode->base.link);
1857 free(drm_mode);
1858 }
1859
1860 drmModeFreeCrtc(output->original_crtc);
1861 ec->crtc_allocator &= ~(1 << output->crtc_id);
1862 ec->connector_allocator &= ~(1 << output->connector_id);
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øgsberg3d64a3e2013-05-10 12:36:04 -04002148 destroy_sprites(d);
2149
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002150 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002151
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002152 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002153
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002154 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
Kristian Høgsberge3148752013-05-06 23:19:49 -04002257switch_vt_binding(struct weston_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
Kristian Høgsberge3148752013-05-06 23:19:49 -04002321planes_binding(struct weston_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}