blob: 1485c6cb0195f3f1be454181a10574983d5dc079 [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>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030040#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040041
Benjamin Franzkec649a922011-03-02 11:56:04 +010042#include <xf86drm.h>
43#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050044#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010045
Benjamin Franzke060cf802011-04-30 09:32:11 +020046#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020047#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040048#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020049
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040050#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010051#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020052#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050053#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010054#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040055
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030056#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
57#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
58#endif
59
Kristian Høgsberg061c4252012-06-28 11:28:15 -040060static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060061static char *output_name;
62static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060063static char *output_transform;
Alexander Larssond9a7bb72013-05-22 14:41:39 +020064static char *output_scale;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065static struct wl_list configured_output_list;
66
67enum output_config {
68 OUTPUT_CONFIG_INVALID = 0,
69 OUTPUT_CONFIG_OFF,
70 OUTPUT_CONFIG_PREFERRED,
71 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060072 OUTPUT_CONFIG_MODE,
73 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060074};
75
76struct drm_configured_output {
77 char *name;
78 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060079 uint32_t transform;
Alexander Larssond9a7bb72013-05-22 14:41:39 +020080 int32_t scale;
Scott Moreau8ab5d452012-07-30 19:51:08 -060081 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060082 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060083 enum output_config config;
84 struct wl_list link;
85};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040086
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040087struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050088 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040089
90 struct udev *udev;
91 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040092
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010093 struct udev_monitor *udev_monitor;
94 struct wl_event_source *udev_drm_source;
95
Benjamin Franzke2af7f102011-03-02 11:14:59 +010096 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010097 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010098 int fd;
99 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +0200100 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101 uint32_t *crtcs;
102 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -0500103 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +0100104 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -0500105 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106
Rob Clark4339add2012-08-09 14:18:28 -0500107 /* we need these parameters in order to not fail drmModeAddFB2()
108 * due to out of bounds dimensions, and then mistakenly set
109 * sprites_are_broken:
110 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200111 uint32_t min_width, max_width;
112 uint32_t min_height, max_height;
113 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500114
Jesse Barnes58ef3792012-02-23 09:45:49 -0500115 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500116 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200117 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500118
Rob Clarkab5b1e32012-08-09 13:24:45 -0500119 int cursors_are_broken;
120
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200121 int use_pixman;
122
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200123 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300124
125 clockid_t clock;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126};
127
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400128struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500129 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400130 drmModeModeInfo mode_info;
131};
132
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300133struct drm_output;
134
135struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300136 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200137 uint32_t fb_id, stride, handle, size;
138 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300139 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200140 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200141
142 /* Used by gbm fbs */
143 struct gbm_bo *bo;
144
145 /* Used by dumb fbs */
146 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300147};
148
Richard Hughes2b2092a2013-04-24 14:58:02 +0100149struct drm_edid {
150 char eisa_id[13];
151 char monitor_name[13];
152 char pnp_id[5];
153 char serial_number[13];
154};
155
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400156struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500157 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400158
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500160 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400161 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700162 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100163 struct drm_edid edid;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200164
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300165 int vblank_pending;
166 int page_flip_pending;
167
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400168 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400169 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400170 struct weston_plane cursor_plane;
171 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400172 struct weston_surface *cursor_surface;
173 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300174 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200175 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200176
177 struct drm_fb *dumb[2];
178 pixman_image_t *image[2];
179 int current_image;
180 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400181};
182
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183/*
184 * An output has a primary display plane plus zero or more sprites for
185 * blending display contents.
186 */
187struct drm_sprite {
188 struct wl_list link;
189
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400190 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500191
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200192 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300193 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500194 struct drm_compositor *compositor;
195
Jesse Barnes58ef3792012-02-23 09:45:49 -0500196 uint32_t possible_crtcs;
197 uint32_t plane_id;
198 uint32_t count_formats;
199
200 int32_t src_x, src_y;
201 uint32_t src_w, src_h;
202 uint32_t dest_x, dest_y;
203 uint32_t dest_w, dest_h;
204
205 uint32_t formats[];
206};
207
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500208static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400209
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400210static void
211drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400212
Jesse Barnes58ef3792012-02-23 09:45:49 -0500213static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500214drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
215{
216 struct weston_compositor *ec = output_base->compositor;
217 struct drm_compositor *c =(struct drm_compositor *) ec;
218 struct drm_output *output = (struct drm_output *) output_base;
219 int crtc;
220
221 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
222 if (c->crtcs[crtc] != output->crtc_id)
223 continue;
224
225 if (supported & (1 << crtc))
226 return -1;
227 }
228
229 return 0;
230}
231
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232static void
233drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
234{
235 struct drm_fb *fb = data;
236 struct gbm_device *gbm = gbm_bo_get_device(bo);
237
238 if (fb->fb_id)
239 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
240
Pekka Paalanende685b82012-12-04 15:58:12 +0200241 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300242
243 free(data);
244}
245
246static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200247drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
248{
249 struct drm_fb *fb;
250 int ret;
251
252 struct drm_mode_create_dumb create_arg;
253 struct drm_mode_destroy_dumb destroy_arg;
254 struct drm_mode_map_dumb map_arg;
255
256 fb = calloc(1, sizeof *fb);
257 if (!fb)
258 return NULL;
259
260 create_arg.bpp = 32;
261 create_arg.width = width;
262 create_arg.height = height;
263
264 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
265 if (ret)
266 goto err_fb;
267
268 fb->handle = create_arg.handle;
269 fb->stride = create_arg.pitch;
270 fb->size = create_arg.size;
271 fb->fd = ec->drm.fd;
272
273 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
274 fb->stride, fb->handle, &fb->fb_id);
275 if (ret)
276 goto err_bo;
277
278 memset(&map_arg, 0, sizeof(map_arg));
279 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400280 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200281 if (ret)
282 goto err_add_fb;
283
284 fb->map = mmap(0, fb->size, PROT_WRITE,
285 MAP_SHARED, ec->drm.fd, map_arg.offset);
286 if (fb->map == MAP_FAILED)
287 goto err_add_fb;
288
289 return fb;
290
291err_add_fb:
292 drmModeRmFB(ec->drm.fd, fb->fb_id);
293err_bo:
294 memset(&destroy_arg, 0, sizeof(destroy_arg));
295 destroy_arg.handle = create_arg.handle;
296 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
297err_fb:
298 free(fb);
299 return NULL;
300}
301
302static void
303drm_fb_destroy_dumb(struct drm_fb *fb)
304{
305 struct drm_mode_destroy_dumb destroy_arg;
306
307 if (!fb->map)
308 return;
309
310 if (fb->fb_id)
311 drmModeRmFB(fb->fd, fb->fb_id);
312
313 weston_buffer_reference(&fb->buffer_ref, NULL);
314
315 munmap(fb->map, fb->size);
316
317 memset(&destroy_arg, 0, sizeof(destroy_arg));
318 destroy_arg.handle = fb->handle;
319 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
320
321 free(fb);
322}
323
324static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500325drm_fb_get_from_bo(struct gbm_bo *bo,
326 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327{
328 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200330 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 int ret;
332
333 if (fb)
334 return fb;
335
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200336 fb = calloc(1, sizeof *fb);
337 if (!fb)
338 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
340 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341
342 width = gbm_bo_get_width(bo);
343 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 fb->stride = gbm_bo_get_stride(bo);
345 fb->handle = gbm_bo_get_handle(bo).u32;
346 fb->size = fb->stride * height;
347 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300348
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 if (compositor->min_width > width || width > compositor->max_width ||
350 compositor->min_height > height ||
351 height > compositor->max_height) {
352 weston_log("bo geometry out of bounds\n");
353 goto err_free;
354 }
355
356 ret = -1;
357
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 handles[0] = fb->handle;
360 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361 offsets[0] = 0;
362
363 ret = drmModeAddFB2(compositor->drm.fd, width, height,
364 format, handles, pitches, offsets,
365 &fb->fb_id, 0);
366 if (ret) {
367 weston_log("addfb2 failed: %m\n");
368 compositor->no_addfb2 = 1;
369 compositor->sprites_are_broken = 1;
370 }
371 }
372
373 if (ret)
374 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200375 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200378 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380 }
381
382 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
383
384 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
386err_free:
387 free(fb);
388 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300389}
390
391static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200392drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
393{
Pekka Paalanende685b82012-12-04 15:58:12 +0200394 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395
396 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397
Pekka Paalanende685b82012-12-04 15:58:12 +0200398 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200399}
400
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200401static void
402drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
403{
404 if (!fb)
405 return;
406
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200407 if (fb->map &&
408 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200409 drm_fb_destroy_dumb(fb);
410 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200411 if (fb->is_client_buffer)
412 gbm_bo_destroy(fb->bo);
413 else
414 gbm_surface_release_buffer(output->surface,
415 output->current->bo);
416 }
417}
418
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500419static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420drm_output_check_scanout_format(struct drm_output *output,
421 struct weston_surface *es, struct gbm_bo *bo)
422{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200423 uint32_t format;
424 pixman_region32_t r;
425
426 format = gbm_bo_get_format(bo);
427
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500428 switch (format) {
429 case GBM_FORMAT_XRGB8888:
430 return format;
431 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200432 /* We can only scanout an ARGB buffer if the surface's
433 * opaque region covers the whole output */
434 pixman_region32_init(&r);
435 pixman_region32_subtract(&r, &output->base.region,
436 &es->opaque);
437
438 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500439 format = GBM_FORMAT_XRGB8888;
440 else
441 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200442
443 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200444
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500445 return format;
446 default:
447 return 0;
448 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200449}
450
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400451static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400452drm_output_prepare_scanout_surface(struct weston_output *_output,
453 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500454{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400455 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500456 struct drm_compositor *c =
457 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200458 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300459 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500460 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500461
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500462 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200463 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200464 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200465 buffer->width != output->base.current->width ||
466 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200467 output->base.transform != es->buffer_transform ||
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200468 output->base.scale != es->buffer_scale ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200469 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400470 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500471
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400472 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200473 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474
Rob Bradford9b101872012-09-14 23:25:41 +0100475 /* Unable to use the buffer for scanout */
476 if (!bo)
477 return NULL;
478
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500479 format = drm_output_check_scanout_format(output, es, bo);
480 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300481 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400482 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300483 }
484
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500485 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300486 if (!output->next) {
487 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400488 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300489 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500490
Pekka Paalanende685b82012-12-04 15:58:12 +0200491 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500492
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400493 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500494}
495
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500496static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200497drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400498{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200499 struct drm_compositor *c =
500 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200503 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400504
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300505 bo = gbm_surface_lock_front_buffer(output->surface);
506 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200507 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400508 return;
509 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500511 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300512 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200513 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300514 gbm_surface_release_buffer(output->surface, bo);
515 return;
516 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517}
518
519static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200520drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
521{
522 struct weston_compositor *ec = output->base.compositor;
523 pixman_region32_t total_damage, previous_damage;
524
525 pixman_region32_init(&total_damage);
526 pixman_region32_init(&previous_damage);
527
528 pixman_region32_copy(&previous_damage, damage);
529
530 pixman_region32_union(&total_damage, damage, &output->previous_damage);
531 pixman_region32_copy(&output->previous_damage, &previous_damage);
532
533 output->current_image ^= 1;
534
535 output->next = output->dumb[output->current_image];
536 pixman_renderer_output_set_buffer(&output->base,
537 output->image[output->current_image]);
538
539 ec->renderer->repaint_output(&output->base, &total_damage);
540
541 pixman_region32_fini(&total_damage);
542 pixman_region32_fini(&previous_damage);
543}
544
545static void
546drm_output_render(struct drm_output *output, pixman_region32_t *damage)
547{
548 struct drm_compositor *c =
549 (struct drm_compositor *) output->base.compositor;
550
551 if (c->use_pixman)
552 drm_output_render_pixman(output, damage);
553 else
554 drm_output_render_gl(output, damage);
555
556 pixman_region32_subtract(&c->base.primary_plane.damage,
557 &c->base.primary_plane.damage, damage);
558}
559
560static void
Richard Hughese7299962013-05-01 21:52:12 +0100561drm_output_set_gamma(struct weston_output *output_base,
562 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
563{
564 int rc;
565 struct drm_output *output = (struct drm_output *) output_base;
566 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
567
568 /* check */
569 if (output_base->gamma_size != size)
570 return;
571 if (!output->original_crtc)
572 return;
573
574 rc = drmModeCrtcSetGamma(compositor->drm.fd,
575 output->crtc_id,
576 size, r, g, b);
577 if (rc)
578 weston_log("set gamma failed: %m\n");
579}
580
581static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500582drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400583 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100584{
585 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500586 struct drm_compositor *compositor =
587 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400589 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500590 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100591
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300592 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400593 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300594 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400595 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100596
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400597 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300598 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400599 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300600 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400601 &output->connector_id, 1,
602 &mode->mode_info);
603 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200604 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400605 return;
606 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200607 }
608
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500609 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300610 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500611 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200612 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500613 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500614 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100615
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300616 output->page_flip_pending = 1;
617
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400618 drm_output_set_cursor(output);
619
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 /*
621 * Now, update all the sprite surfaces
622 */
623 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200624 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500625 drmVBlank vbl = {
626 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
627 .request.sequence = 1,
628 };
629
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200630 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200631 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 continue;
633
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200634 if (s->next && !compositor->sprites_hidden)
635 fb_id = s->next->fb_id;
636
Jesse Barnes58ef3792012-02-23 09:45:49 -0500637 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200638 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 s->dest_x, s->dest_y,
640 s->dest_w, s->dest_h,
641 s->src_x, s->src_y,
642 s->src_w, s->src_h);
643 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200644 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 ret, strerror(errno));
646
Rob Clark5ca1a472012-08-08 20:27:37 -0500647 if (output->pipe > 0)
648 vbl.request.type |= DRM_VBLANK_SECONDARY;
649
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 /*
651 * Queue a vblank signal so we know when the surface
652 * becomes active on the display or has been replaced.
653 */
654 vbl.request.signal = (unsigned long)s;
655 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
656 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200657 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 ret, strerror(errno));
659 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300660
661 s->output = output;
662 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663 }
664
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500665 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400666}
667
668static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200669drm_output_start_repaint_loop(struct weston_output *output_base)
670{
671 struct drm_output *output = (struct drm_output *) output_base;
672 struct drm_compositor *compositor = (struct drm_compositor *)
673 output_base->compositor;
674 uint32_t fb_id;
675
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300676 struct timespec ts;
677
678 if (!output->current) {
679 /* We can't page flip if there's no mode set */
680 uint32_t msec;
681
682 clock_gettime(compositor->clock, &ts);
683 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
684 weston_output_finish_frame(output_base, msec);
685 return;
686 }
687
688 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200689
690 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
691 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
692 weston_log("queueing pageflip failed: %m\n");
693 return;
694 }
695}
696
697static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500698vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
699 void *data)
700{
701 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300702 struct drm_output *output = s->output;
703 uint32_t msecs;
704
705 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200707 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200708 s->current = s->next;
709 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300710
711 if (!output->page_flip_pending) {
712 msecs = sec * 1000 + usec / 1000;
713 weston_output_finish_frame(&output->base, msecs);
714 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500715}
716
717static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400718page_flip_handler(int fd, unsigned int frame,
719 unsigned int sec, unsigned int usec, void *data)
720{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200721 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400722 uint32_t msecs;
723
Jonas Ådahle5a12252013-04-05 23:07:11 +0200724 /* We don't set page_flip_pending on start_repaint_loop, in that case
725 * we just want to page flip to the current buffer to get an accurate
726 * timestamp */
727 if (output->page_flip_pending) {
728 drm_output_release_fb(output, output->current);
729 output->current = output->next;
730 output->next = NULL;
731 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300732
Jonas Ådahle5a12252013-04-05 23:07:11 +0200733 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400734
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300735 if (!output->vblank_pending) {
736 msecs = sec * 1000 + usec / 1000;
737 weston_output_finish_frame(&output->base, msecs);
738 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200739}
740
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500741static uint32_t
742drm_output_check_sprite_format(struct drm_sprite *s,
743 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500744{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500745 uint32_t i, format;
746
747 format = gbm_bo_get_format(bo);
748
749 if (format == GBM_FORMAT_ARGB8888) {
750 pixman_region32_t r;
751
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500752 pixman_region32_init_rect(&r, 0, 0,
753 es->geometry.width,
754 es->geometry.height);
755 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500756
757 if (!pixman_region32_not_empty(&r))
758 format = GBM_FORMAT_XRGB8888;
759
760 pixman_region32_fini(&r);
761 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762
763 for (i = 0; i < s->count_formats; i++)
764 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500765 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766
767 return 0;
768}
769
770static int
771drm_surface_transform_supported(struct weston_surface *es)
772{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500773 return !es->transform.enabled ||
774 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775}
776
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400777static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500778drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400779 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780{
781 struct weston_compositor *ec = output_base->compositor;
782 struct drm_compositor *c =(struct drm_compositor *) ec;
783 struct drm_sprite *s;
784 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500786 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200787 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500788 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400789 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500790
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200791 if (c->gbm == NULL)
792 return NULL;
793
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200794 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200795 return NULL;
796
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200797 if (es->buffer_scale != output_base->scale)
798 return NULL;
799
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500800 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400801 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500802
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300803 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400804 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300805
Pekka Paalanende685b82012-12-04 15:58:12 +0200806 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400807 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200809 if (es->alpha != 1.0f)
810 return NULL;
811
Pekka Paalanende685b82012-12-04 15:58:12 +0200812 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500813 return NULL;
814
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400816 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818 wl_list_for_each(s, &c->sprite_list, link) {
819 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
820 continue;
821
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200822 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823 found = 1;
824 break;
825 }
826 }
827
828 /* No sprites available */
829 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400832 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200833 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400834 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400836
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500837 format = drm_output_check_sprite_format(s, es, bo);
838 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200839 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400840 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 }
842
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200843 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200844 if (!s->next) {
845 gbm_bo_destroy(bo);
846 return NULL;
847 }
848
Pekka Paalanende685b82012-12-04 15:58:12 +0200849 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400851 box = pixman_region32_extents(&es->transform.boundingbox);
852 s->plane.x = box->x1;
853 s->plane.y = box->y1;
854
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855 /*
856 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200857 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500858 * for us already).
859 */
860 pixman_region32_init(&dest_rect);
861 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
862 &output_base->region);
863 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
864 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200865 tbox = weston_transformed_rect(output_base->width,
866 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200867 output_base->transform,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200868 output_base->scale,
869 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200870 s->dest_x = tbox.x1;
871 s->dest_y = tbox.y1;
872 s->dest_w = tbox.x2 - tbox.x1;
873 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500874 pixman_region32_fini(&dest_rect);
875
876 pixman_region32_init(&src_rect);
877 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
878 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500879 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400880
881 weston_surface_from_global_fixed(es,
882 wl_fixed_from_int(box->x1),
883 wl_fixed_from_int(box->y1),
884 &sx1, &sy1);
885 weston_surface_from_global_fixed(es,
886 wl_fixed_from_int(box->x2),
887 wl_fixed_from_int(box->y2),
888 &sx2, &sy2);
889
890 if (sx1 < 0)
891 sx1 = 0;
892 if (sy1 < 0)
893 sy1 = 0;
894 if (sx2 > wl_fixed_from_int(es->geometry.width))
895 sx2 = wl_fixed_from_int(es->geometry.width);
896 if (sy2 > wl_fixed_from_int(es->geometry.height))
897 sy2 = wl_fixed_from_int(es->geometry.height);
898
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200899 tbox.x1 = sx1;
900 tbox.y1 = sy1;
901 tbox.x2 = sx2;
902 tbox.y2 = sy2;
903
904 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
905 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200906 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200907
908 s->src_x = tbox.x1 << 8;
909 s->src_y = tbox.y1 << 8;
910 s->src_w = (tbox.x2 - tbox.x1) << 8;
911 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500912 pixman_region32_fini(&src_rect);
913
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400914 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500915}
916
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400917static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400918drm_output_prepare_cursor_surface(struct weston_output *output_base,
919 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500920{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400921 struct drm_compositor *c =
922 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400923 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400924
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200925 if (c->gbm == NULL)
926 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200927 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
928 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400929 if (output->cursor_surface)
930 return NULL;
931 if (es->output_mask != (1u << output_base->id))
932 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500933 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400934 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200935 if (es->buffer_ref.buffer == NULL ||
936 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400937 es->geometry.width > 64 || es->geometry.height > 64)
938 return NULL;
939
940 output->cursor_surface = es;
941
942 return &output->cursor_plane;
943}
944
945static void
946drm_output_set_cursor(struct drm_output *output)
947{
948 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400949 struct drm_compositor *c =
950 (struct drm_compositor *) output->base.compositor;
951 EGLint handle, stride;
952 struct gbm_bo *bo;
953 uint32_t buf[64 * 64];
954 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400955 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500956
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400957 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400958 if (es == NULL) {
959 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
960 return;
961 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500962
Pekka Paalanende685b82012-12-04 15:58:12 +0200963 if (es->buffer_ref.buffer &&
964 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400965 pixman_region32_fini(&output->cursor_plane.damage);
966 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400967 output->current_cursor ^= 1;
968 bo = output->cursor_bo[output->current_cursor];
969 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200970 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
971 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400972 for (i = 0; i < es->geometry.height; i++)
973 memcpy(buf + i * 64, s + i * stride,
974 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500975
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400976 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300977 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400978
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400979 handle = gbm_bo_get_handle(bo).s32;
980 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500981 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300982 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500983 c->cursors_are_broken = 1;
984 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400985 }
986
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200987 x = (es->geometry.x - output->base.x) * output->base.scale;
988 y = (es->geometry.y - output->base.y) * output->base.scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400989 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500990 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400991 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500992 c->cursors_are_broken = 1;
993 }
994
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400995 output->cursor_plane.x = x;
996 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400997 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500998}
999
Jesse Barnes58ef3792012-02-23 09:45:49 -05001000static void
1001drm_assign_planes(struct weston_output *output)
1002{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001003 struct drm_compositor *c =
1004 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001005 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001006 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001007 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001008
1009 /*
1010 * Find a surface for each sprite in the output using some heuristics:
1011 * 1) size
1012 * 2) frequency of update
1013 * 3) opacity (though some hw might support alpha blending)
1014 * 4) clipping (this can be fixed with color keys)
1015 *
1016 * The idea is to save on blitting since this should save power.
1017 * If we can get a large video surface on the sprite for example,
1018 * the main display surface may not need to update at all, and
1019 * the client buffer can be used directly for the sprite surface
1020 * as we do for flipping full screen surfaces.
1021 */
1022 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001023 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001024 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001025 /* test whether this buffer can ever go into a plane:
1026 * non-shm, or small enough to be a cursor
1027 */
1028 if ((es->buffer_ref.buffer &&
1029 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1030 (es->geometry.width <= 64 && es->geometry.height <= 64))
1031 es->keep_buffer = 1;
1032 else
1033 es->keep_buffer = 0;
1034
Jesse Barnes58ef3792012-02-23 09:45:49 -05001035 pixman_region32_init(&surface_overlap);
1036 pixman_region32_intersect(&surface_overlap, &overlap,
1037 &es->transform.boundingbox);
1038
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001039 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001040 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001041 next_plane = primary;
1042 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001043 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001044 if (next_plane == NULL)
1045 next_plane = drm_output_prepare_scanout_surface(output, es);
1046 if (next_plane == NULL)
1047 next_plane = drm_output_prepare_overlay_surface(output, es);
1048 if (next_plane == NULL)
1049 next_plane = primary;
1050 weston_surface_move_to_plane(es, next_plane);
1051 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001052 pixman_region32_union(&overlap, &overlap,
1053 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001054
Jesse Barnes58ef3792012-02-23 09:45:49 -05001055 pixman_region32_fini(&surface_overlap);
1056 }
1057 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001058}
1059
Matt Roper361d2ad2011-08-29 13:52:23 -07001060static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001061drm_output_fini_pixman(struct drm_output *output);
1062
1063static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001064drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001065{
1066 struct drm_output *output = (struct drm_output *) output_base;
1067 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001068 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001069 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001070
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001071 if (output->backlight)
1072 backlight_destroy(output->backlight);
1073
Matt Roper361d2ad2011-08-29 13:52:23 -07001074 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001075 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001076
1077 /* Restore original CRTC state */
1078 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001079 origcrtc->x, origcrtc->y,
1080 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001081 drmModeFreeCrtc(origcrtc);
1082
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001083 c->crtc_allocator &= ~(1 << output->crtc_id);
1084 c->connector_allocator &= ~(1 << output->connector_id);
1085
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001086 if (c->use_pixman) {
1087 drm_output_fini_pixman(output);
1088 } else {
1089 gl_renderer_output_destroy(output_base);
1090 gbm_surface_destroy(output->surface);
1091 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001092
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001093 weston_plane_release(&output->fb_plane);
1094 weston_plane_release(&output->cursor_plane);
1095
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001096 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001097 wl_list_remove(&output->base.link);
1098
Matt Roper361d2ad2011-08-29 13:52:23 -07001099 free(output);
1100}
1101
Alex Wub7b8bda2012-04-17 17:20:48 +08001102static struct drm_mode *
1103choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1104{
1105 struct drm_mode *tmp_mode = NULL, *mode;
1106
1107 if (output->base.current->width == target_mode->width &&
1108 output->base.current->height == target_mode->height &&
1109 (output->base.current->refresh == target_mode->refresh ||
1110 target_mode->refresh == 0))
1111 return (struct drm_mode *)output->base.current;
1112
1113 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1114 if (mode->mode_info.hdisplay == target_mode->width &&
1115 mode->mode_info.vdisplay == target_mode->height) {
1116 if (mode->mode_info.vrefresh == target_mode->refresh ||
1117 target_mode->refresh == 0) {
1118 return mode;
1119 } else if (!tmp_mode)
1120 tmp_mode = mode;
1121 }
1122 }
1123
1124 return tmp_mode;
1125}
1126
1127static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001128drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001129static int
1130drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001131
1132static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001133drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1134{
1135 struct drm_output *output;
1136 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001137 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001138
1139 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001140 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001141 return -1;
1142 }
1143
1144 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001145 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001146 return -1;
1147 }
1148
1149 ec = (struct drm_compositor *)output_base->compositor;
1150 output = (struct drm_output *)output_base;
1151 drm_mode = choose_mode (output, mode);
1152
1153 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001154 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001155 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001156 }
1157
1158 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001159 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001160
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001161 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001162
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001163 output->base.current = &drm_mode->base;
1164 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001165 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1166
Alex Wub7b8bda2012-04-17 17:20:48 +08001167 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001168 drm_output_release_fb(output, output->current);
1169 drm_output_release_fb(output, output->next);
1170 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001171
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001172 if (ec->use_pixman) {
1173 drm_output_fini_pixman(output);
1174 if (drm_output_init_pixman(output, ec) < 0) {
1175 weston_log("failed to init output pixman state with "
1176 "new mode\n");
1177 return -1;
1178 }
1179 } else {
1180 gl_renderer_output_destroy(&output->base);
1181 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001182
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001183 if (drm_output_init_egl(output, ec) < 0) {
1184 weston_log("failed to init output egl state with "
1185 "new mode");
1186 return -1;
1187 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001188 }
1189
Alex Wub7b8bda2012-04-17 17:20:48 +08001190 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001191}
1192
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001193static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001194on_drm_input(int fd, uint32_t mask, void *data)
1195{
1196 drmEventContext evctx;
1197
1198 memset(&evctx, 0, sizeof evctx);
1199 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1200 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001201 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001202 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001203
1204 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001205}
1206
1207static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001208init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001209{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001210 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001211 uint64_t cap;
1212 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001213
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001214 sysnum = udev_device_get_sysnum(device);
1215 if (sysnum)
1216 ec->drm.id = atoi(sysnum);
1217 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001218 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001219 return -1;
1220 }
1221
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001222 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001223 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001224 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001225 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001226 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001227 udev_device_get_devnode(device));
1228 return -1;
1229 }
1230
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001231 weston_log("using %s\n", filename);
1232
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001233 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001234
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001235 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1236 if (ret == 0 && cap == 1)
1237 ec->clock = CLOCK_MONOTONIC;
1238 else
1239 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001240
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001241 return 0;
1242}
1243
1244static int
1245init_egl(struct drm_compositor *ec)
1246{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001247 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001248
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001249 if (!ec->gbm)
1250 return -1;
1251
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001252 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001253 NULL) < 0) {
1254 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001255 return -1;
1256 }
1257
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001258 return 0;
1259}
1260
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001261static int
1262init_pixman(struct drm_compositor *ec)
1263{
1264 return pixman_renderer_init(&ec->base);
1265}
1266
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001267static struct drm_mode *
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001268drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info, struct drm_configured_output *config)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001269{
1270 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001271 uint64_t refresh;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001272 int scale;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001273
1274 mode = malloc(sizeof *mode);
1275 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001276 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001277
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001278 scale = 1;
1279 if (config)
1280 scale = config->scale;
1281
1282 if (info->hdisplay % scale != 0 ||
1283 info->vdisplay % scale) {
1284 weston_log("Mode %dx%d not multiple of scale %d\n", info->hdisplay, info->vdisplay, scale);
1285 return NULL;
1286 }
1287
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001288 mode->base.flags = 0;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001289 mode->base.width = info->hdisplay / scale;
1290 mode->base.height = info->vdisplay / scale;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001291
1292 /* Calculate higher precision (mHz) refresh rate */
1293 refresh = (info->clock * 1000000LL / info->htotal +
1294 info->vtotal / 2) / info->vtotal;
1295
1296 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1297 refresh *= 2;
1298 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1299 refresh /= 2;
1300 if (info->vscan > 1)
1301 refresh /= info->vscan;
1302
1303 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001304 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001305
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001306 if (scale != 1)
1307 mode->base.flags |= WL_OUTPUT_MODE_SCALED;
1308
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001309 if (info->type & DRM_MODE_TYPE_PREFERRED)
1310 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1311
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1313
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001314 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001315}
1316
1317static int
1318drm_subpixel_to_wayland(int drm_value)
1319{
1320 switch (drm_value) {
1321 default:
1322 case DRM_MODE_SUBPIXEL_UNKNOWN:
1323 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1324 case DRM_MODE_SUBPIXEL_NONE:
1325 return WL_OUTPUT_SUBPIXEL_NONE;
1326 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1327 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1328 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1329 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1330 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1331 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1332 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1333 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1334 }
1335}
1336
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001337/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001338static uint32_t
1339drm_get_backlight(struct drm_output *output)
1340{
1341 long brightness, max_brightness, norm;
1342
1343 brightness = backlight_get_brightness(output->backlight);
1344 max_brightness = backlight_get_max_brightness(output->backlight);
1345
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001346 /* convert it on a scale of 0 to 255 */
1347 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001348
1349 return (uint32_t) norm;
1350}
1351
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001352/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001353static void
1354drm_set_backlight(struct weston_output *output_base, uint32_t value)
1355{
1356 struct drm_output *output = (struct drm_output *) output_base;
1357 long max_brightness, new_brightness;
1358
1359 if (!output->backlight)
1360 return;
1361
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001362 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001363 return;
1364
1365 max_brightness = backlight_get_max_brightness(output->backlight);
1366
1367 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001368 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001369
1370 backlight_set_brightness(output->backlight, new_brightness);
1371}
1372
1373static drmModePropertyPtr
1374drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1375{
1376 drmModePropertyPtr props;
1377 int i;
1378
1379 for (i = 0; i < connector->count_props; i++) {
1380 props = drmModeGetProperty(fd, connector->props[i]);
1381 if (!props)
1382 continue;
1383
1384 if (!strcmp(props->name, name))
1385 return props;
1386
1387 drmModeFreeProperty(props);
1388 }
1389
1390 return NULL;
1391}
1392
1393static void
1394drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1395{
1396 struct drm_output *output = (struct drm_output *) output_base;
1397 struct weston_compositor *ec = output_base->compositor;
1398 struct drm_compositor *c = (struct drm_compositor *) ec;
1399 drmModeConnectorPtr connector;
1400 drmModePropertyPtr prop;
1401
1402 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1403 if (!connector)
1404 return;
1405
1406 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1407 if (!prop) {
1408 drmModeFreeConnector(connector);
1409 return;
1410 }
1411
1412 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1413 prop->prop_id, level);
1414 drmModeFreeProperty(prop);
1415 drmModeFreeConnector(connector);
1416}
1417
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001418static const char *connector_type_names[] = {
1419 "None",
1420 "VGA",
1421 "DVI",
1422 "DVI",
1423 "DVI",
1424 "Composite",
1425 "TV",
1426 "LVDS",
1427 "CTV",
1428 "DIN",
1429 "DP",
1430 "HDMI",
1431 "HDMI",
1432 "TV",
1433 "eDP",
1434};
1435
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001436static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001437find_crtc_for_connector(struct drm_compositor *ec,
1438 drmModeRes *resources, drmModeConnector *connector)
1439{
1440 drmModeEncoder *encoder;
1441 uint32_t possible_crtcs;
1442 int i, j;
1443
1444 for (j = 0; j < connector->count_encoders; j++) {
1445 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1446 if (encoder == NULL) {
1447 weston_log("Failed to get encoder.\n");
1448 return -1;
1449 }
1450 possible_crtcs = encoder->possible_crtcs;
1451 drmModeFreeEncoder(encoder);
1452
1453 for (i = 0; i < resources->count_crtcs; i++) {
1454 if (possible_crtcs & (1 << i) &&
1455 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1456 return i;
1457 }
1458 }
1459
1460 return -1;
1461}
1462
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001463/* Init output state that depends on gl or gbm */
1464static int
1465drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1466{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001467 int i, flags;
1468
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001469 output->surface = gbm_surface_create(ec->gbm,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001470 output->base.current->width * output->base.scale,
1471 output->base.current->height * output->base.scale,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001472 GBM_FORMAT_XRGB8888,
1473 GBM_BO_USE_SCANOUT |
1474 GBM_BO_USE_RENDERING);
1475 if (!output->surface) {
1476 weston_log("failed to create gbm surface\n");
1477 return -1;
1478 }
1479
1480 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001481 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001482 gbm_surface_destroy(output->surface);
1483 return -1;
1484 }
1485
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001486 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1487
1488 for (i = 0; i < 2; i++) {
1489 if (output->cursor_bo[i])
1490 continue;
1491
1492 output->cursor_bo[i] =
1493 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1494 flags);
1495 }
1496
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001497 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1498 weston_log("cursor buffers unavailable, using gl cursors\n");
1499 ec->cursors_are_broken = 1;
1500 }
1501
1502 return 0;
1503}
1504
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001505static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001506drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1507{
1508 int w = output->base.current->width;
1509 int h = output->base.current->height;
1510 unsigned int i;
1511
1512 /* FIXME error checking */
1513
1514 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001515 output->dumb[i] = drm_fb_create_dumb(c, w * output->base.scale, h * output->base.scale);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001516 if (!output->dumb[i])
1517 goto err;
1518
1519 output->image[i] =
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001520 pixman_image_create_bits(PIXMAN_x8r8g8b8, w * output->base.scale, h * output->base.scale,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001521 output->dumb[i]->map,
1522 output->dumb[i]->stride);
1523 if (!output->image[i])
1524 goto err;
1525 }
1526
1527 if (pixman_renderer_output_create(&output->base) < 0)
1528 goto err;
1529
1530 pixman_region32_init_rect(&output->previous_damage,
1531 output->base.x, output->base.y, w, h);
1532
1533 return 0;
1534
1535err:
1536 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1537 if (output->dumb[i])
1538 drm_fb_destroy_dumb(output->dumb[i]);
1539 if (output->image[i])
1540 pixman_image_unref(output->image[i]);
1541
1542 output->dumb[i] = NULL;
1543 output->image[i] = NULL;
1544 }
1545
1546 return -1;
1547}
1548
1549static void
1550drm_output_fini_pixman(struct drm_output *output)
1551{
1552 unsigned int i;
1553
1554 pixman_renderer_output_destroy(&output->base);
1555 pixman_region32_fini(&output->previous_damage);
1556
1557 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1558 drm_fb_destroy_dumb(output->dumb[i]);
1559 pixman_image_unref(output->image[i]);
1560 output->dumb[i] = NULL;
1561 output->image[i] = NULL;
1562 }
1563}
1564
Richard Hughes2b2092a2013-04-24 14:58:02 +01001565static void
1566edid_parse_string(const uint8_t *data, char text[])
1567{
1568 int i;
1569 int replaced = 0;
1570
1571 /* this is always 12 bytes, but we can't guarantee it's null
1572 * terminated or not junk. */
1573 strncpy(text, (const char *) data, 12);
1574
1575 /* remove insane chars */
1576 for (i = 0; text[i] != '\0'; i++) {
1577 if (text[i] == '\n' ||
1578 text[i] == '\r') {
1579 text[i] = '\0';
1580 break;
1581 }
1582 }
1583
1584 /* ensure string is printable */
1585 for (i = 0; text[i] != '\0'; i++) {
1586 if (!isprint(text[i])) {
1587 text[i] = '-';
1588 replaced++;
1589 }
1590 }
1591
1592 /* if the string is random junk, ignore the string */
1593 if (replaced > 4)
1594 text[0] = '\0';
1595}
1596
1597#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1598#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1599#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1600#define EDID_OFFSET_DATA_BLOCKS 0x36
1601#define EDID_OFFSET_LAST_BLOCK 0x6c
1602#define EDID_OFFSET_PNPID 0x08
1603#define EDID_OFFSET_SERIAL 0x0c
1604
1605static int
1606edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1607{
1608 int i;
1609 uint32_t serial_number;
1610
1611 /* check header */
1612 if (length < 128)
1613 return -1;
1614 if (data[0] != 0x00 || data[1] != 0xff)
1615 return -1;
1616
1617 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1618 * /--08--\/--09--\
1619 * 7654321076543210
1620 * |\---/\---/\---/
1621 * R C1 C2 C3 */
1622 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1623 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1624 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1625 edid->pnp_id[3] = '\0';
1626
1627 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1628 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1629 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1630 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1631 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1632 if (serial_number > 0)
1633 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1634
1635 /* parse EDID data */
1636 for (i = EDID_OFFSET_DATA_BLOCKS;
1637 i <= EDID_OFFSET_LAST_BLOCK;
1638 i += 18) {
1639 /* ignore pixel clock data */
1640 if (data[i] != 0)
1641 continue;
1642 if (data[i+2] != 0)
1643 continue;
1644
1645 /* any useful blocks? */
1646 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1647 edid_parse_string(&data[i+5],
1648 edid->monitor_name);
1649 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1650 edid_parse_string(&data[i+5],
1651 edid->serial_number);
1652 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1653 edid_parse_string(&data[i+5],
1654 edid->eisa_id);
1655 }
1656 }
1657 return 0;
1658}
1659
1660static void
1661find_and_parse_output_edid(struct drm_compositor *ec,
1662 struct drm_output *output,
1663 drmModeConnector *connector)
1664{
1665 drmModePropertyBlobPtr edid_blob = NULL;
1666 drmModePropertyPtr property;
1667 int i;
1668 int rc;
1669
1670 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1671 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1672 if (!property)
1673 continue;
1674 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1675 !strcmp(property->name, "EDID")) {
1676 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1677 connector->prop_values[i]);
1678 }
1679 drmModeFreeProperty(property);
1680 }
1681 if (!edid_blob)
1682 return;
1683
1684 rc = edid_parse(&output->edid,
1685 edid_blob->data,
1686 edid_blob->length);
1687 if (!rc) {
1688 weston_log("EDID data '%s', '%s', '%s'\n",
1689 output->edid.pnp_id,
1690 output->edid.monitor_name,
1691 output->edid.serial_number);
1692 if (output->edid.pnp_id[0] != '\0')
1693 output->base.make = output->edid.pnp_id;
1694 if (output->edid.monitor_name[0] != '\0')
1695 output->base.model = output->edid.monitor_name;
1696 if (output->edid.serial_number[0] != '\0')
1697 output->base.serial_number = output->edid.serial_number;
1698 }
1699 drmModeFreePropertyBlob(edid_blob);
1700}
1701
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001702static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001703create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001704 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001705 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001706 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001707{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001708 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001709 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1710 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001711 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001712 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001713 drmModeModeInfo crtc_mode;
1714 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001715 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001716 char name[32];
1717 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001718
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001719 i = find_crtc_for_connector(ec, resources, connector);
1720 if (i < 0) {
1721 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001722 return -1;
1723 }
1724
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001725 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001726 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001727 return -1;
1728
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001729 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001730 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1731 output->base.make = "unknown";
1732 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001733 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001734 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001735
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001736 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1737 type_name = connector_type_names[connector->connector_type];
1738 else
1739 type_name = "UNKNOWN";
1740 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001741 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001742
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001743 wl_list_for_each(temp, &configured_output_list, link) {
1744 if (strcmp(temp->name, output->base.name) == 0) {
1745 if (temp->mode)
1746 weston_log("%s mode \"%s\" in config\n",
1747 temp->name, temp->mode);
1748 o = temp;
1749 break;
1750 }
1751 }
1752
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001753 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001754 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001755 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001756 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001757 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001758
Matt Roper361d2ad2011-08-29 13:52:23 -07001759 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1760
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001761 /* Get the current mode on the crtc that's currently driving
1762 * this connector. */
1763 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001764 memset(&crtc_mode, 0, sizeof crtc_mode);
1765 if (encoder != NULL) {
1766 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1767 drmModeFreeEncoder(encoder);
1768 if (crtc == NULL)
1769 goto err_free;
1770 if (crtc->mode_valid)
1771 crtc_mode = crtc->mode;
1772 drmModeFreeCrtc(crtc);
1773 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001774
David Herrmann0f0d54e2011-12-08 17:05:45 +01001775 for (i = 0; i < connector->count_modes; i++) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001776 drm_mode = drm_output_add_mode(output, &connector->modes[i], o);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001777 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001778 goto err_free;
1779 }
1780
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001781 preferred = NULL;
1782 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001783 configured = NULL;
1784
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001785 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001786 weston_log("Disabling output %s\n", o->name);
1787
1788 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1789 0, 0, 0, 0, 0, NULL);
1790 goto err_free;
1791 }
1792
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001793 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001794 if (o && o->config == OUTPUT_CONFIG_MODE &&
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001795 o->width == drm_mode->base.width * o->scale &&
1796 o->height == drm_mode->base.height * o->scale)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001797 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001798 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001799 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001800 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001801 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001802 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001803
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001804 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001805 configured = drm_output_add_mode(output, &o->crtc_mode, 0);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001806 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001807 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001808 current = configured;
1809 }
1810
Wang Quanxianacb805a2012-07-30 18:09:46 -04001811 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001812 current = drm_output_add_mode(output, &crtc_mode, 0);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001813 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001814 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001815 }
1816
Scott Moreau8ab5d452012-07-30 19:51:08 -06001817 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1818 configured = current;
1819
Wang Quanxianacb805a2012-07-30 18:09:46 -04001820 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001821 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001822 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001823 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001824 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001825 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001826 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001827 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001828
1829 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001830 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001831 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001832 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001833
Wang Quanxianacb805a2012-07-30 18:09:46 -04001834 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1835
John Kåre Alsaker94659272012-11-13 19:10:18 +01001836 weston_output_init(&output->base, &ec->base, x, y,
1837 connector->mmWidth, connector->mmHeight,
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001838 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL,
1839 o ? o->scale : 1);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001840
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001841 if (ec->use_pixman) {
1842 if (drm_output_init_pixman(output, ec) < 0) {
1843 weston_log("Failed to init output pixman state\n");
1844 goto err_output;
1845 }
1846 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001847 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001848 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001849 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001850
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001851 output->backlight = backlight_init(drm_device,
1852 connector->connector_type);
1853 if (output->backlight) {
1854 output->base.set_backlight = drm_set_backlight;
1855 output->base.backlight_current = drm_get_backlight(output);
1856 }
1857
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001858 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1859
Richard Hughes2b2092a2013-04-24 14:58:02 +01001860 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001861 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1862 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001863
Alex Wubd3354b2012-04-17 17:20:49 +08001864 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001865 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001866 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001867 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001868 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001869 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001870 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001871
Richard Hughese7299962013-05-01 21:52:12 +01001872 output->base.gamma_size = output->original_crtc->gamma_size;
1873 output->base.set_gamma = drm_output_set_gamma;
1874
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001875 weston_plane_init(&output->cursor_plane, 0, 0);
1876 weston_plane_init(&output->fb_plane, 0, 0);
1877
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001878 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1879 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1880 &ec->base.primary_plane);
1881
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001882 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001883 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001884 wl_list_for_each(m, &output->base.mode_list, link)
1885 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1886 m->width, m->height, m->refresh / 1000.0,
1887 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1888 ", preferred" : "",
1889 m->flags & WL_OUTPUT_MODE_CURRENT ?
1890 ", current" : "",
1891 connector->count_modes == 0 ?
1892 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001893
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001894 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001895
John Kåre Alsaker94659272012-11-13 19:10:18 +01001896err_output:
1897 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001898err_free:
1899 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1900 base.link) {
1901 wl_list_remove(&drm_mode->base.link);
1902 free(drm_mode);
1903 }
1904
1905 drmModeFreeCrtc(output->original_crtc);
1906 ec->crtc_allocator &= ~(1 << output->crtc_id);
1907 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001908 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001909
David Herrmann0f0d54e2011-12-08 17:05:45 +01001910 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001911}
1912
Jesse Barnes58ef3792012-02-23 09:45:49 -05001913static void
1914create_sprites(struct drm_compositor *ec)
1915{
1916 struct drm_sprite *sprite;
1917 drmModePlaneRes *plane_res;
1918 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001919 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001920
1921 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1922 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001923 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001924 strerror(errno));
1925 return;
1926 }
1927
1928 for (i = 0; i < plane_res->count_planes; i++) {
1929 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1930 if (!plane)
1931 continue;
1932
1933 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1934 plane->count_formats));
1935 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001936 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001937 __func__);
1938 free(plane);
1939 continue;
1940 }
1941
1942 memset(sprite, 0, sizeof *sprite);
1943
1944 sprite->possible_crtcs = plane->possible_crtcs;
1945 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001946 sprite->current = NULL;
1947 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001948 sprite->compositor = ec;
1949 sprite->count_formats = plane->count_formats;
1950 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001951 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001952 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001953 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001954 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1955 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001956
1957 wl_list_insert(&ec->sprite_list, &sprite->link);
1958 }
1959
1960 free(plane_res->planes);
1961 free(plane_res);
1962}
1963
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001964static void
1965destroy_sprites(struct drm_compositor *compositor)
1966{
1967 struct drm_sprite *sprite, *next;
1968 struct drm_output *output;
1969
1970 output = container_of(compositor->base.output_list.next,
1971 struct drm_output, base.link);
1972
1973 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1974 drmModeSetPlane(compositor->drm.fd,
1975 sprite->plane_id,
1976 output->crtc_id, 0, 0,
1977 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001978 drm_output_release_fb(output, sprite->current);
1979 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001980 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001981 free(sprite);
1982 }
1983}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001984
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001985static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001986create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001987 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001988{
1989 drmModeConnector *connector;
1990 drmModeRes *resources;
1991 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001992 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001993
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001994 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001995 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001996 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001997 return -1;
1998 }
1999
Jesse Barnes58ef3792012-02-23 09:45:49 -05002000 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002001 if (!ec->crtcs) {
2002 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002003 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002004 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002005
Rob Clark4339add2012-08-09 14:18:28 -05002006 ec->min_width = resources->min_width;
2007 ec->max_width = resources->max_width;
2008 ec->min_height = resources->min_height;
2009 ec->max_height = resources->max_height;
2010
Jesse Barnes58ef3792012-02-23 09:45:49 -05002011 ec->num_crtcs = resources->count_crtcs;
2012 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2013
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002014 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002015 connector = drmModeGetConnector(ec->drm.fd,
2016 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002017 if (connector == NULL)
2018 continue;
2019
2020 if (connector->connection == DRM_MODE_CONNECTED &&
2021 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002022 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002023 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002024 connector, x, y,
2025 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002026 drmModeFreeConnector(connector);
2027 continue;
2028 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002029
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002030 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002031 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002032 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002033 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002034
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002035 drmModeFreeConnector(connector);
2036 }
2037
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002038 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002039 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002040 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002041 return -1;
2042 }
2043
2044 drmModeFreeResources(resources);
2045
2046 return 0;
2047}
2048
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002049static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002050update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002051{
2052 drmModeConnector *connector;
2053 drmModeRes *resources;
2054 struct drm_output *output, *next;
2055 int x = 0, y = 0;
2056 int x_offset = 0, y_offset = 0;
2057 uint32_t connected = 0, disconnects = 0;
2058 int i;
2059
2060 resources = drmModeGetResources(ec->drm.fd);
2061 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002062 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002063 return;
2064 }
2065
2066 /* collect new connects */
2067 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002068 int connector_id = resources->connectors[i];
2069
2070 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002071 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002072 continue;
2073
David Herrmann7551cff2011-12-08 17:05:43 +01002074 if (connector->connection != DRM_MODE_CONNECTED) {
2075 drmModeFreeConnector(connector);
2076 continue;
2077 }
2078
Benjamin Franzke117483d2011-08-30 11:38:26 +02002079 connected |= (1 << connector_id);
2080
2081 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002082 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002083 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002084 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002085
2086 /* XXX: not yet needed, we die with 0 outputs */
2087 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002088 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002089 else
2090 x = 0;
2091 y = 0;
2092 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002093 connector, x, y,
2094 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002095 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002096
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002097 }
2098 drmModeFreeConnector(connector);
2099 }
2100 drmModeFreeResources(resources);
2101
2102 disconnects = ec->connector_allocator & ~connected;
2103 if (disconnects) {
2104 wl_list_for_each_safe(output, next, &ec->base.output_list,
2105 base.link) {
2106 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002107 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002108 output->base.x - x_offset,
2109 output->base.y - y_offset);
2110 }
2111
2112 if (disconnects & (1 << output->connector_id)) {
2113 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002114 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002115 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002116 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002117 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002118 }
2119 }
2120 }
2121
2122 /* FIXME: handle zero outputs, without terminating */
2123 if (ec->connector_allocator == 0)
2124 wl_display_terminate(ec->base.wl_display);
2125}
2126
2127static int
David Herrmannd7488c22012-03-11 20:05:21 +01002128udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002129{
David Herrmannd7488c22012-03-11 20:05:21 +01002130 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002131 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002132
2133 sysnum = udev_device_get_sysnum(device);
2134 if (!sysnum || atoi(sysnum) != ec->drm.id)
2135 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002136
David Herrmann6ac52db2012-03-11 20:05:22 +01002137 val = udev_device_get_property_value(device, "HOTPLUG");
2138 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002139 return 0;
2140
David Herrmann6ac52db2012-03-11 20:05:22 +01002141 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002142}
2143
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002144static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002145udev_drm_event(int fd, uint32_t mask, void *data)
2146{
2147 struct drm_compositor *ec = data;
2148 struct udev_device *event;
2149
2150 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002151
David Herrmannd7488c22012-03-11 20:05:21 +01002152 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002153 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002154
2155 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002156
2157 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002158}
2159
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002160static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002161drm_restore(struct weston_compositor *ec)
2162{
2163 struct drm_compositor *d = (struct drm_compositor *) ec;
2164
2165 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2166 weston_log("failed to drop master: %m\n");
2167 tty_reset(d->tty);
2168}
2169
2170static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002171drm_free_configured_output(struct drm_configured_output *output)
2172{
2173 free(output->name);
2174 free(output->mode);
2175 free(output);
2176}
2177
2178static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002179drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002180{
2181 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002182 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002183 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002184
Kristian Høgsberge8091032013-02-18 15:43:29 -05002185 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2186 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002187 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002188 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002189
2190 wl_event_source_remove(d->udev_drm_source);
2191 wl_event_source_remove(d->drm_source);
2192
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002193 destroy_sprites(d);
2194
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002195 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002196
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002197 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002198
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002199 if (d->gbm)
2200 gbm_device_destroy(d->gbm);
2201
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002202 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002203 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002204 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002205
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002206 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002207}
2208
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002209static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002210drm_compositor_set_modes(struct drm_compositor *compositor)
2211{
2212 struct drm_output *output;
2213 struct drm_mode *drm_mode;
2214 int ret;
2215
2216 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002217 if (!output->current) {
2218 /* If something that would cause the output to
2219 * switch mode happened while in another vt, we
2220 * might not have a current drm_fb. In that case,
2221 * schedule a repaint and let drm_output_repaint
2222 * handle setting the mode. */
2223 weston_output_schedule_repaint(&output->base);
2224 continue;
2225 }
2226
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002227 drm_mode = (struct drm_mode *) output->base.current;
2228 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002229 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002230 &output->connector_id, 1,
2231 &drm_mode->mode_info);
2232 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002233 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002234 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002235 drm_mode->base.width, drm_mode->base.height,
2236 output->base.x, output->base.y);
2237 }
2238 }
2239}
2240
2241static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002242vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002243{
2244 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002245 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002246 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002247 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002248
2249 switch (event) {
2250 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002251 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002252 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002253 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002254 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002255 wl_display_terminate(compositor->wl_display);
2256 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002257 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002258 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002259 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002260 wl_list_for_each(seat, &compositor->seat_list, base.link)
2261 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002262 break;
2263 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002264 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002265 wl_list_for_each(seat, &compositor->seat_list, base.link)
2266 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002267
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002268 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002269 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002270 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002271
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002272 /* If we have a repaint scheduled (either from a
2273 * pending pageflip or the idle handler), make sure we
2274 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002275 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002276 * further attemps at repainting. When we switch
2277 * back, we schedule a repaint, which will process
2278 * pending frame callbacks. */
2279
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002280 wl_list_for_each(output, &ec->base.output_list, base.link) {
2281 output->base.repaint_needed = 0;
2282 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002283 }
2284
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002285 output = container_of(ec->base.output_list.next,
2286 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002287
2288 wl_list_for_each(sprite, &ec->sprite_list, link)
2289 drmModeSetPlane(ec->drm.fd,
2290 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002291 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002292 0, 0, 0, 0, 0, 0, 0, 0);
2293
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002294 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002295 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002296
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002297 break;
2298 };
2299}
2300
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002301static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002302switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002303{
2304 struct drm_compositor *ec = data;
2305
Daniel Stone325fc2d2012-05-30 16:31:58 +01002306 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002307}
2308
David Herrmann0af066f2012-10-29 19:21:16 +01002309/*
2310 * Find primary GPU
2311 * Some systems may have multiple DRM devices attached to a single seat. This
2312 * function loops over all devices and tries to find a PCI device with the
2313 * boot_vga sysfs attribute set to 1.
2314 * If no such device is found, the first DRM device reported by udev is used.
2315 */
2316static struct udev_device*
2317find_primary_gpu(struct drm_compositor *ec, const char *seat)
2318{
2319 struct udev_enumerate *e;
2320 struct udev_list_entry *entry;
2321 const char *path, *device_seat, *id;
2322 struct udev_device *device, *drm_device, *pci;
2323
2324 e = udev_enumerate_new(ec->udev);
2325 udev_enumerate_add_match_subsystem(e, "drm");
2326 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2327
2328 udev_enumerate_scan_devices(e);
2329 drm_device = NULL;
2330 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2331 path = udev_list_entry_get_name(entry);
2332 device = udev_device_new_from_syspath(ec->udev, path);
2333 if (!device)
2334 continue;
2335 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2336 if (!device_seat)
2337 device_seat = default_seat;
2338 if (strcmp(device_seat, seat)) {
2339 udev_device_unref(device);
2340 continue;
2341 }
2342
2343 pci = udev_device_get_parent_with_subsystem_devtype(device,
2344 "pci", NULL);
2345 if (pci) {
2346 id = udev_device_get_sysattr_value(pci, "boot_vga");
2347 if (id && !strcmp(id, "1")) {
2348 if (drm_device)
2349 udev_device_unref(drm_device);
2350 drm_device = device;
2351 break;
2352 }
2353 }
2354
2355 if (!drm_device)
2356 drm_device = device;
2357 else
2358 udev_device_unref(device);
2359 }
2360
2361 udev_enumerate_unref(e);
2362 return drm_device;
2363}
2364
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002365static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002366planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002367{
2368 struct drm_compositor *c = data;
2369
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002370 switch (key) {
2371 case KEY_C:
2372 c->cursors_are_broken ^= 1;
2373 break;
2374 case KEY_V:
2375 c->sprites_are_broken ^= 1;
2376 break;
2377 case KEY_O:
2378 c->sprites_hidden ^= 1;
2379 break;
2380 default:
2381 break;
2382 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002383}
2384
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002385static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002386drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002387 int connector, const char *seat, int tty, int pixman,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002388 int *argc, char *argv[], int config_fd)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002389{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002390 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002391 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002392 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002393 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002394 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002395 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002396
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002397 weston_log("initializing drm backend\n");
2398
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002399 ec = malloc(sizeof *ec);
2400 if (ec == NULL)
2401 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002402 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002403
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002404 /* KMS support for sprites is not complete yet, so disable the
2405 * functionality for now. */
2406 ec->sprites_are_broken = 1;
2407
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002408 ec->use_pixman = pixman;
2409
Daniel Stone725c2c32012-06-22 14:04:36 +01002410 if (weston_compositor_init(&ec->base, display, argc, argv,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002411 config_fd) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002412 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002413 goto err_base;
2414 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002415
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002416 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002417 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002418 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002419 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002420 goto err_compositor;
2421 }
2422
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002423 ec->udev = udev_new();
2424 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002425 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002426 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002427 }
2428
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002429 ec->base.wl_display = display;
2430 ec->tty = tty_create(&ec->base, vt_func, tty);
2431 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002432 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002433 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002434 }
2435
David Herrmann0af066f2012-10-29 19:21:16 +01002436 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002437 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002438 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002439 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002440 }
David Herrmann0af066f2012-10-29 19:21:16 +01002441 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002442
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002443 if (init_drm(ec, drm_device) < 0) {
2444 weston_log("failed to initialize kms\n");
2445 goto err_udev_dev;
2446 }
2447
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002448 if (ec->use_pixman) {
2449 if (init_pixman(ec) < 0) {
2450 weston_log("failed to initialize pixman renderer\n");
2451 goto err_udev_dev;
2452 }
2453 } else {
2454 if (init_egl(ec) < 0) {
2455 weston_log("failed to initialize egl\n");
2456 goto err_udev_dev;
2457 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002458 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002459
2460 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002461 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002462
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002463 ec->base.focus = 1;
2464
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002465 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002466
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002467 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002468 weston_compositor_add_key_binding(&ec->base, key,
2469 MODIFIER_CTRL | MODIFIER_ALT,
2470 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002471
Jesse Barnes58ef3792012-02-23 09:45:49 -05002472 wl_list_init(&ec->sprite_list);
2473 create_sprites(ec);
2474
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002475 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002476 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002477 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002478 }
2479
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002480 path = NULL;
2481
Kristian Høgsberge8091032013-02-18 15:43:29 -05002482 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002483 weston_log("failed to create input devices\n");
2484 goto err_sprite;
2485 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002486
2487 loop = wl_display_get_event_loop(ec->base.wl_display);
2488 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002489 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002490 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002491
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002492 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2493 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002494 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002495 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002496 }
2497 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2498 "drm", NULL);
2499 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002500 wl_event_loop_add_fd(loop,
2501 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002502 WL_EVENT_READABLE, udev_drm_event, ec);
2503
2504 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002505 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002506 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002507 }
2508
Daniel Stonea96b93c2012-06-22 14:04:37 +01002509 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002510
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002511 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002512 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002513 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002514 planes_binding, ec);
2515 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2516 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002517
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002518 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002519
2520err_udev_monitor:
2521 wl_event_source_remove(ec->udev_drm_source);
2522 udev_monitor_unref(ec->udev_monitor);
2523err_drm_source:
2524 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002525 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2526 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002527err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002528 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002529 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002530 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002531err_udev_dev:
2532 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002533err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002534 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2535 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002536 tty_destroy(ec->tty);
2537err_udev:
2538 udev_unref(ec->udev);
2539err_compositor:
2540 weston_compositor_shutdown(&ec->base);
2541err_base:
2542 free(ec);
2543 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002544}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002545
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002546static int
2547set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2548{
2549 mode->flags = 0;
2550
2551 if (strcmp(hsync, "+hsync") == 0)
2552 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2553 else if (strcmp(hsync, "-hsync") == 0)
2554 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2555 else
2556 return -1;
2557
2558 if (strcmp(vsync, "+vsync") == 0)
2559 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2560 else if (strcmp(vsync, "-vsync") == 0)
2561 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2562 else
2563 return -1;
2564
2565 return 0;
2566}
2567
2568static int
2569check_for_modeline(struct drm_configured_output *output)
2570{
2571 drmModeModeInfo mode;
2572 char hsync[16];
2573 char vsync[16];
2574 char mode_name[16];
2575 float fclock;
2576
2577 mode.type = DRM_MODE_TYPE_USERDEF;
2578 mode.hskew = 0;
2579 mode.vscan = 0;
2580 mode.vrefresh = 0;
2581
2582 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2583 &fclock, &mode.hdisplay,
2584 &mode.hsync_start,
2585 &mode.hsync_end, &mode.htotal,
2586 &mode.vdisplay,
2587 &mode.vsync_start,
2588 &mode.vsync_end, &mode.vtotal,
2589 hsync, vsync) == 11) {
2590 if (set_sync_flags(&mode, hsync, vsync))
2591 return -1;
2592
2593 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2594 strcpy(mode.name, mode_name);
2595
2596 mode.clock = fclock * 1000;
2597 } else
2598 return -1;
2599
2600 output->crtc_mode = mode;
2601
2602 return 0;
2603}
2604
Scott Moreau8ab5d452012-07-30 19:51:08 -06002605static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002606drm_output_set_transform(struct drm_configured_output *output)
2607{
2608 if (!output_transform) {
2609 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2610 return;
2611 }
2612
2613 if (!strcmp(output_transform, "normal"))
2614 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2615 else if (!strcmp(output_transform, "90"))
2616 output->transform = WL_OUTPUT_TRANSFORM_90;
2617 else if (!strcmp(output_transform, "180"))
2618 output->transform = WL_OUTPUT_TRANSFORM_180;
2619 else if (!strcmp(output_transform, "270"))
2620 output->transform = WL_OUTPUT_TRANSFORM_270;
2621 else if (!strcmp(output_transform, "flipped"))
2622 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2623 else if (!strcmp(output_transform, "flipped-90"))
2624 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2625 else if (!strcmp(output_transform, "flipped-180"))
2626 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2627 else if (!strcmp(output_transform, "flipped-270"))
2628 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2629 else {
2630 weston_log("Invalid transform \"%s\" for output %s\n",
2631 output_transform, output_name);
2632 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2633 }
2634
2635 free(output_transform);
2636 output_transform = NULL;
2637}
2638
2639static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002640output_section_done(void *data)
2641{
2642 struct drm_configured_output *output;
2643
2644 output = malloc(sizeof *output);
2645
Scott Moreau1bad5db2012-08-18 01:04:05 -06002646 if (!output || !output_name || (output_name[0] == 'X') ||
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002647 (!output_mode && !output_transform && !output_scale)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002648 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002649 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002650 free(output_transform);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002651 free(output_scale);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002652 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002653 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002654 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002655 output_transform = NULL;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002656 output_scale = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002657 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002658 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002659
2660 output->config = OUTPUT_CONFIG_INVALID;
2661 output->name = output_name;
2662 output->mode = output_mode;
2663
Scott Moreau1bad5db2012-08-18 01:04:05 -06002664 if (output_mode) {
2665 if (strcmp(output_mode, "off") == 0)
2666 output->config = OUTPUT_CONFIG_OFF;
2667 else if (strcmp(output_mode, "preferred") == 0)
2668 output->config = OUTPUT_CONFIG_PREFERRED;
2669 else if (strcmp(output_mode, "current") == 0)
2670 output->config = OUTPUT_CONFIG_CURRENT;
2671 else if (sscanf(output_mode, "%dx%d",
2672 &output->width, &output->height) == 2)
2673 output->config = OUTPUT_CONFIG_MODE;
2674 else if (check_for_modeline(output) == 0)
2675 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002676
Scott Moreau1bad5db2012-08-18 01:04:05 -06002677 if (output->config == OUTPUT_CONFIG_INVALID)
2678 weston_log("Invalid mode \"%s\" for output %s\n",
2679 output_mode, output_name);
2680 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002681 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002682
2683 drm_output_set_transform(output);
2684
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002685 if (!output_scale || sscanf(output_scale, "%d", &output->scale) != 1)
2686 output->scale = 1;
2687
Scott Moreau1bad5db2012-08-18 01:04:05 -06002688 wl_list_insert(&configured_output_list, &output->link);
2689
2690 if (output_transform)
2691 free(output_transform);
2692 output_transform = NULL;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002693 if (output_scale)
2694 free(output_scale);
2695 output_scale = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002696}
2697
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002698WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002699backend_init(struct wl_display *display, int *argc, char *argv[],
Ossama Othmana50e6e42013-05-14 09:48:26 -07002700 int config_fd)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002701{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002702 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002703 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002704
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002705 const struct weston_option drm_options[] = {
2706 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2707 { WESTON_OPTION_STRING, "seat", 0, &seat },
2708 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002709 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002710 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002711 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002712
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002713 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002714
Scott Moreau8ab5d452012-07-30 19:51:08 -06002715 wl_list_init(&configured_output_list);
2716
2717 const struct config_key drm_config_keys[] = {
2718 { "name", CONFIG_KEY_STRING, &output_name },
2719 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002720 { "transform", CONFIG_KEY_STRING, &output_transform },
Alexander Larssond9a7bb72013-05-22 14:41:39 +02002721 { "scale", CONFIG_KEY_STRING, &output_scale },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002722 };
2723
2724 const struct config_section config_section[] = {
2725 { "output", drm_config_keys,
2726 ARRAY_LENGTH(drm_config_keys), output_section_done },
2727 };
2728
Ossama Othmana50e6e42013-05-14 09:48:26 -07002729 parse_config_file(config_fd, config_section,
Scott Moreau8ab5d452012-07-30 19:51:08 -06002730 ARRAY_LENGTH(config_section), NULL);
2731
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002732 return drm_compositor_create(display, connector, seat, tty, use_pixman,
Ossama Othmana50e6e42013-05-14 09:48:26 -07002733 argc, argv, config_fd);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002734}