blob: 82090f0eebe835bd13307f8d3f5a4828a5d4a881 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020033#include <sys/mman.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034
Benjamin Franzkec649a922011-03-02 11:56:04 +010035#include <xf86drm.h>
36#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050037#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010038
Benjamin Franzke060cf802011-04-30 09:32:11 +020039#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020040#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040041#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020042
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040043#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010044#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020045#include "pixman-renderer.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020046#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010047#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040048
Kristian Høgsberg061c4252012-06-28 11:28:15 -040049static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060050static char *output_name;
51static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060052static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060053static struct wl_list configured_output_list;
54
55enum output_config {
56 OUTPUT_CONFIG_INVALID = 0,
57 OUTPUT_CONFIG_OFF,
58 OUTPUT_CONFIG_PREFERRED,
59 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060060 OUTPUT_CONFIG_MODE,
61 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060062};
63
64struct drm_configured_output {
65 char *name;
66 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060067 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060068 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060069 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060070 enum output_config config;
71 struct wl_list link;
72};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040073
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050075 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
77 struct udev *udev;
78 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040079
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010080 struct udev_monitor *udev_monitor;
81 struct wl_event_source *udev_drm_source;
82
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010084 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010085 int fd;
86 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020087 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050088 uint32_t *crtcs;
89 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050090 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010091 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050092 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020093
Rob Clark4339add2012-08-09 14:18:28 -050094 /* we need these parameters in order to not fail drmModeAddFB2()
95 * due to out of bounds dimensions, and then mistakenly set
96 * sprites_are_broken:
97 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020098 uint32_t min_width, max_width;
99 uint32_t min_height, max_height;
100 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500101
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500103 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200104 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500105
Rob Clarkab5b1e32012-08-09 13:24:45 -0500106 int cursors_are_broken;
107
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200108 int use_pixman;
109
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200110 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400111};
112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400115 drmModeModeInfo mode_info;
116};
117
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118struct drm_output;
119
120struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122 uint32_t fb_id, stride, handle, size;
123 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200125 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200126
127 /* Used by gbm fbs */
128 struct gbm_bo *bo;
129
130 /* Used by dumb fbs */
131 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132};
133
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400134struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500135 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400136
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400137 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400138 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500139 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400140 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700141 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200142
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300143 int vblank_pending;
144 int page_flip_pending;
145
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400146 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400147 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400148 struct weston_plane cursor_plane;
149 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400150 struct weston_surface *cursor_surface;
151 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300152 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200153 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200154
155 struct drm_fb *dumb[2];
156 pixman_image_t *image[2];
157 int current_image;
158 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159};
160
Jesse Barnes58ef3792012-02-23 09:45:49 -0500161/*
162 * An output has a primary display plane plus zero or more sprites for
163 * blending display contents.
164 */
165struct drm_sprite {
166 struct wl_list link;
167
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400168 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500169
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200170 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300171 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500172 struct drm_compositor *compositor;
173
Jesse Barnes58ef3792012-02-23 09:45:49 -0500174 uint32_t possible_crtcs;
175 uint32_t plane_id;
176 uint32_t count_formats;
177
178 int32_t src_x, src_y;
179 uint32_t src_w, src_h;
180 uint32_t dest_x, dest_y;
181 uint32_t dest_w, dest_h;
182
183 uint32_t formats[];
184};
185
Pekka Paalanen33156972012-08-03 13:30:30 -0400186struct drm_seat {
187 struct weston_seat base;
188 struct wl_list devices_list;
189 struct udev_monitor *udev_monitor;
190 struct wl_event_source *udev_monitor_source;
191 char *seat_id;
192};
193
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400194static void
195drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400196
Jesse Barnes58ef3792012-02-23 09:45:49 -0500197static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500198drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
199{
200 struct weston_compositor *ec = output_base->compositor;
201 struct drm_compositor *c =(struct drm_compositor *) ec;
202 struct drm_output *output = (struct drm_output *) output_base;
203 int crtc;
204
205 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
206 if (c->crtcs[crtc] != output->crtc_id)
207 continue;
208
209 if (supported & (1 << crtc))
210 return -1;
211 }
212
213 return 0;
214}
215
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300216static void
217drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
218{
219 struct drm_fb *fb = data;
220 struct gbm_device *gbm = gbm_bo_get_device(bo);
221
222 if (fb->fb_id)
223 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
224
Pekka Paalanende685b82012-12-04 15:58:12 +0200225 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300226
227 free(data);
228}
229
230static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200231drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
232{
233 struct drm_fb *fb;
234 int ret;
235
236 struct drm_mode_create_dumb create_arg;
237 struct drm_mode_destroy_dumb destroy_arg;
238 struct drm_mode_map_dumb map_arg;
239
240 fb = calloc(1, sizeof *fb);
241 if (!fb)
242 return NULL;
243
244 create_arg.bpp = 32;
245 create_arg.width = width;
246 create_arg.height = height;
247
248 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
249 if (ret)
250 goto err_fb;
251
252 fb->handle = create_arg.handle;
253 fb->stride = create_arg.pitch;
254 fb->size = create_arg.size;
255 fb->fd = ec->drm.fd;
256
257 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
258 fb->stride, fb->handle, &fb->fb_id);
259 if (ret)
260 goto err_bo;
261
262 memset(&map_arg, 0, sizeof(map_arg));
263 map_arg.handle = fb->handle;
264 drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
265
266 if (ret)
267 goto err_add_fb;
268
269 fb->map = mmap(0, fb->size, PROT_WRITE,
270 MAP_SHARED, ec->drm.fd, map_arg.offset);
271 if (fb->map == MAP_FAILED)
272 goto err_add_fb;
273
274 return fb;
275
276err_add_fb:
277 drmModeRmFB(ec->drm.fd, fb->fb_id);
278err_bo:
279 memset(&destroy_arg, 0, sizeof(destroy_arg));
280 destroy_arg.handle = create_arg.handle;
281 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
282err_fb:
283 free(fb);
284 return NULL;
285}
286
287static void
288drm_fb_destroy_dumb(struct drm_fb *fb)
289{
290 struct drm_mode_destroy_dumb destroy_arg;
291
292 if (!fb->map)
293 return;
294
295 if (fb->fb_id)
296 drmModeRmFB(fb->fd, fb->fb_id);
297
298 weston_buffer_reference(&fb->buffer_ref, NULL);
299
300 munmap(fb->map, fb->size);
301
302 memset(&destroy_arg, 0, sizeof(destroy_arg));
303 destroy_arg.handle = fb->handle;
304 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
305
306 free(fb);
307}
308
309static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500310drm_fb_get_from_bo(struct gbm_bo *bo,
311 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300312{
313 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200314 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200315 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300316 int ret;
317
318 if (fb)
319 return fb;
320
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200321 fb = calloc(1, sizeof *fb);
322 if (!fb)
323 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300324
325 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300326
327 width = gbm_bo_get_width(bo);
328 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 fb->stride = gbm_bo_get_stride(bo);
330 fb->handle = gbm_bo_get_handle(bo).u32;
331 fb->size = fb->stride * height;
332 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300333
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200334 if (compositor->min_width > width || width > compositor->max_width ||
335 compositor->min_height > height ||
336 height > compositor->max_height) {
337 weston_log("bo geometry out of bounds\n");
338 goto err_free;
339 }
340
341 ret = -1;
342
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200343 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 handles[0] = fb->handle;
345 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200346 offsets[0] = 0;
347
348 ret = drmModeAddFB2(compositor->drm.fd, width, height,
349 format, handles, pitches, offsets,
350 &fb->fb_id, 0);
351 if (ret) {
352 weston_log("addfb2 failed: %m\n");
353 compositor->no_addfb2 = 1;
354 compositor->sprites_are_broken = 1;
355 }
356 }
357
358 if (ret)
359 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200360 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200363 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365 }
366
367 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
368
369 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200370
371err_free:
372 free(fb);
373 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300374}
375
376static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
378{
Pekka Paalanende685b82012-12-04 15:58:12 +0200379 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380
381 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200382
Pekka Paalanende685b82012-12-04 15:58:12 +0200383 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200384}
385
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200386static void
387drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
388{
389 if (!fb)
390 return;
391
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200392 if (fb->map &&
393 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200394 drm_fb_destroy_dumb(fb);
395 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200396 if (fb->is_client_buffer)
397 gbm_bo_destroy(fb->bo);
398 else
399 gbm_surface_release_buffer(output->surface,
400 output->current->bo);
401 }
402}
403
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500404static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200405drm_output_check_scanout_format(struct drm_output *output,
406 struct weston_surface *es, struct gbm_bo *bo)
407{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200408 uint32_t format;
409 pixman_region32_t r;
410
411 format = gbm_bo_get_format(bo);
412
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500413 switch (format) {
414 case GBM_FORMAT_XRGB8888:
415 return format;
416 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200417 /* We can only scanout an ARGB buffer if the surface's
418 * opaque region covers the whole output */
419 pixman_region32_init(&r);
420 pixman_region32_subtract(&r, &output->base.region,
421 &es->opaque);
422
423 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500424 format = GBM_FORMAT_XRGB8888;
425 else
426 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200427
428 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200429
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500430 return format;
431 default:
432 return 0;
433 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434}
435
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400436static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400437drm_output_prepare_scanout_surface(struct weston_output *_output,
438 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500439{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400440 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500441 struct drm_compositor *c =
442 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200443 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300444 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500445 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500446
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500447 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200448 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200449 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200450 buffer->width != output->base.current->width ||
451 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200452 output->base.transform != es->buffer_transform ||
453 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400454 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500455
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400456 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200457 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500458
Rob Bradford9b101872012-09-14 23:25:41 +0100459 /* Unable to use the buffer for scanout */
460 if (!bo)
461 return NULL;
462
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500463 format = drm_output_check_scanout_format(output, es, bo);
464 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300465 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400466 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300467 }
468
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500469 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300470 if (!output->next) {
471 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400472 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474
Pekka Paalanende685b82012-12-04 15:58:12 +0200475 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500476
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400477 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500478}
479
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500480static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200481drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400482{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200483 struct drm_compositor *c =
484 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300485 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400486
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200487 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300489 bo = gbm_surface_lock_front_buffer(output->surface);
490 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200491 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400492 return;
493 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300494
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500495 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300496 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200497 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300498 gbm_surface_release_buffer(output->surface, bo);
499 return;
500 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501}
502
503static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200504drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
505{
506 struct weston_compositor *ec = output->base.compositor;
507 pixman_region32_t total_damage, previous_damage;
508
509 pixman_region32_init(&total_damage);
510 pixman_region32_init(&previous_damage);
511
512 pixman_region32_copy(&previous_damage, damage);
513
514 pixman_region32_union(&total_damage, damage, &output->previous_damage);
515 pixman_region32_copy(&output->previous_damage, &previous_damage);
516
517 output->current_image ^= 1;
518
519 output->next = output->dumb[output->current_image];
520 pixman_renderer_output_set_buffer(&output->base,
521 output->image[output->current_image]);
522
523 ec->renderer->repaint_output(&output->base, &total_damage);
524
525 pixman_region32_fini(&total_damage);
526 pixman_region32_fini(&previous_damage);
527}
528
529static void
530drm_output_render(struct drm_output *output, pixman_region32_t *damage)
531{
532 struct drm_compositor *c =
533 (struct drm_compositor *) output->base.compositor;
534
535 if (c->use_pixman)
536 drm_output_render_pixman(output, damage);
537 else
538 drm_output_render_gl(output, damage);
539
540 pixman_region32_subtract(&c->base.primary_plane.damage,
541 &c->base.primary_plane.damage, damage);
542}
543
544static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500545drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400546 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100547{
548 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500549 struct drm_compositor *compositor =
550 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500551 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400552 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500553 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100554
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300555 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400556 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300557 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400558 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100559
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400560 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300561 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400562 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300563 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400564 &output->connector_id, 1,
565 &mode->mode_info);
566 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200567 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400568 return;
569 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200570 }
571
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500572 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300573 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500574 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200575 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500576 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500577 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100578
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300579 output->page_flip_pending = 1;
580
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400581 drm_output_set_cursor(output);
582
Jesse Barnes58ef3792012-02-23 09:45:49 -0500583 /*
584 * Now, update all the sprite surfaces
585 */
586 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200587 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 drmVBlank vbl = {
589 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
590 .request.sequence = 1,
591 };
592
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200593 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200594 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500595 continue;
596
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200597 if (s->next && !compositor->sprites_hidden)
598 fb_id = s->next->fb_id;
599
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200601 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602 s->dest_x, s->dest_y,
603 s->dest_w, s->dest_h,
604 s->src_x, s->src_y,
605 s->src_w, s->src_h);
606 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200607 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 ret, strerror(errno));
609
Rob Clark5ca1a472012-08-08 20:27:37 -0500610 if (output->pipe > 0)
611 vbl.request.type |= DRM_VBLANK_SECONDARY;
612
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613 /*
614 * Queue a vblank signal so we know when the surface
615 * becomes active on the display or has been replaced.
616 */
617 vbl.request.signal = (unsigned long)s;
618 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
619 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200620 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 ret, strerror(errno));
622 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300623
624 s->output = output;
625 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 }
627
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500628 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400629}
630
631static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
633 void *data)
634{
635 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300636 struct drm_output *output = s->output;
637 uint32_t msecs;
638
639 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200641 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 s->current = s->next;
643 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300644
645 if (!output->page_flip_pending) {
646 msecs = sec * 1000 + usec / 1000;
647 weston_output_finish_frame(&output->base, msecs);
648 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649}
650
651static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400652page_flip_handler(int fd, unsigned int frame,
653 unsigned int sec, unsigned int usec, void *data)
654{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200655 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400656 uint32_t msecs;
657
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300658 output->page_flip_pending = 0;
659
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200660 drm_output_release_fb(output, output->current);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300661 output->current = output->next;
662 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400663
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300664 if (!output->vblank_pending) {
665 msecs = sec * 1000 + usec / 1000;
666 weston_output_finish_frame(&output->base, msecs);
667 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200668}
669
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500670static uint32_t
671drm_output_check_sprite_format(struct drm_sprite *s,
672 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500673{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500674 uint32_t i, format;
675
676 format = gbm_bo_get_format(bo);
677
678 if (format == GBM_FORMAT_ARGB8888) {
679 pixman_region32_t r;
680
681 pixman_region32_init(&r);
682 pixman_region32_subtract(&r, &es->transform.boundingbox,
683 &es->transform.opaque);
684
685 if (!pixman_region32_not_empty(&r))
686 format = GBM_FORMAT_XRGB8888;
687
688 pixman_region32_fini(&r);
689 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500690
691 for (i = 0; i < s->count_formats; i++)
692 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500693 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500694
695 return 0;
696}
697
698static int
699drm_surface_transform_supported(struct weston_surface *es)
700{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400701 struct weston_matrix *matrix = &es->transform.matrix;
702 int i;
703
704 if (!es->transform.enabled)
705 return 1;
706
707 for (i = 0; i < 16; i++) {
708 switch (i) {
709 case 10:
710 case 15:
711 if (matrix->d[i] != 1.0)
712 return 0;
713 break;
714 case 0:
715 case 5:
716 case 12:
717 case 13:
718 break;
719 default:
720 if (matrix->d[i] != 0.0)
721 return 0;
722 break;
723 }
724 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500725
726 return 1;
727}
728
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400729static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500730drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400731 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500732{
733 struct weston_compositor *ec = output_base->compositor;
734 struct drm_compositor *c =(struct drm_compositor *) ec;
735 struct drm_sprite *s;
736 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500737 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500738 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200739 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500740 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400741 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500742
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200743 if (c->gbm == NULL)
744 return NULL;
745
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200746 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200747 return NULL;
748
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500749 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400750 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500751
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300752 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400753 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300754
Pekka Paalanende685b82012-12-04 15:58:12 +0200755 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400756 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500757
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200758 if (es->alpha != 1.0f)
759 return NULL;
760
Pekka Paalanende685b82012-12-04 15:58:12 +0200761 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500762 return NULL;
763
Jesse Barnes58ef3792012-02-23 09:45:49 -0500764 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400765 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766
Jesse Barnes58ef3792012-02-23 09:45:49 -0500767 wl_list_for_each(s, &c->sprite_list, link) {
768 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
769 continue;
770
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200771 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772 found = 1;
773 break;
774 }
775 }
776
777 /* No sprites available */
778 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400779 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400781 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200782 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400783 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400784 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400785
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500786 format = drm_output_check_sprite_format(s, es, bo);
787 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200788 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400789 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500790 }
791
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200792 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200793 if (!s->next) {
794 gbm_bo_destroy(bo);
795 return NULL;
796 }
797
Pekka Paalanende685b82012-12-04 15:58:12 +0200798 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400800 box = pixman_region32_extents(&es->transform.boundingbox);
801 s->plane.x = box->x1;
802 s->plane.y = box->y1;
803
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804 /*
805 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200806 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807 * for us already).
808 */
809 pixman_region32_init(&dest_rect);
810 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
811 &output_base->region);
812 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
813 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200814 tbox = weston_transformed_rect(output_base->width,
815 output_base->height,
816 output_base->transform, *box);
817 s->dest_x = tbox.x1;
818 s->dest_y = tbox.y1;
819 s->dest_w = tbox.x2 - tbox.x1;
820 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821 pixman_region32_fini(&dest_rect);
822
823 pixman_region32_init(&src_rect);
824 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
825 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500826 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400827
828 weston_surface_from_global_fixed(es,
829 wl_fixed_from_int(box->x1),
830 wl_fixed_from_int(box->y1),
831 &sx1, &sy1);
832 weston_surface_from_global_fixed(es,
833 wl_fixed_from_int(box->x2),
834 wl_fixed_from_int(box->y2),
835 &sx2, &sy2);
836
837 if (sx1 < 0)
838 sx1 = 0;
839 if (sy1 < 0)
840 sy1 = 0;
841 if (sx2 > wl_fixed_from_int(es->geometry.width))
842 sx2 = wl_fixed_from_int(es->geometry.width);
843 if (sy2 > wl_fixed_from_int(es->geometry.height))
844 sy2 = wl_fixed_from_int(es->geometry.height);
845
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200846 tbox.x1 = sx1;
847 tbox.y1 = sy1;
848 tbox.x2 = sx2;
849 tbox.y2 = sy2;
850
851 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
852 wl_fixed_from_int(es->geometry.height),
853 es->buffer_transform, tbox);
854
855 s->src_x = tbox.x1 << 8;
856 s->src_y = tbox.y1 << 8;
857 s->src_w = (tbox.x2 - tbox.x1) << 8;
858 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500859 pixman_region32_fini(&src_rect);
860
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400861 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500862}
863
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400864static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400865drm_output_prepare_cursor_surface(struct weston_output *output_base,
866 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500867{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400868 struct drm_compositor *c =
869 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400870 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400871
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200872 if (c->gbm == NULL)
873 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200874 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
875 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400876 if (output->cursor_surface)
877 return NULL;
878 if (es->output_mask != (1u << output_base->id))
879 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500880 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400881 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200882 if (es->buffer_ref.buffer == NULL ||
883 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400884 es->geometry.width > 64 || es->geometry.height > 64)
885 return NULL;
886
887 output->cursor_surface = es;
888
889 return &output->cursor_plane;
890}
891
892static void
893drm_output_set_cursor(struct drm_output *output)
894{
895 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400896 struct drm_compositor *c =
897 (struct drm_compositor *) output->base.compositor;
898 EGLint handle, stride;
899 struct gbm_bo *bo;
900 uint32_t buf[64 * 64];
901 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400902 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500903
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400904 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400905 if (es == NULL) {
906 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
907 return;
908 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500909
Pekka Paalanende685b82012-12-04 15:58:12 +0200910 if (es->buffer_ref.buffer &&
911 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400912 pixman_region32_fini(&output->cursor_plane.damage);
913 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400914 output->current_cursor ^= 1;
915 bo = output->cursor_bo[output->current_cursor];
916 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200917 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
918 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400919 for (i = 0; i < es->geometry.height; i++)
920 memcpy(buf + i * 64, s + i * stride,
921 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500922
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400923 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300924 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400925
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400926 handle = gbm_bo_get_handle(bo).s32;
927 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500928 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300929 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500930 c->cursors_are_broken = 1;
931 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400932 }
933
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400934 x = es->geometry.x - output->base.x;
935 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400936 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500937 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400938 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500939 c->cursors_are_broken = 1;
940 }
941
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400942 output->cursor_plane.x = x;
943 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400944 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500945}
946
Jesse Barnes58ef3792012-02-23 09:45:49 -0500947static void
948drm_assign_planes(struct weston_output *output)
949{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400950 struct drm_compositor *c =
951 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200952 struct drm_output *drm_output = (struct drm_output *) output;
953 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400954 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500955 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400956 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500957
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200958 /* Reset the opaque region of the planes */
959 pixman_region32_fini(&drm_output->cursor_plane.opaque);
960 pixman_region32_init(&drm_output->cursor_plane.opaque);
961 pixman_region32_fini(&drm_output->fb_plane.opaque);
962 pixman_region32_init(&drm_output->fb_plane.opaque);
963
964 wl_list_for_each (s, &c->sprite_list, link) {
965 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
966 continue;
967
968 pixman_region32_fini(&s->plane.opaque);
969 pixman_region32_init(&s->plane.opaque);
970 }
971
Jesse Barnes58ef3792012-02-23 09:45:49 -0500972 /*
973 * Find a surface for each sprite in the output using some heuristics:
974 * 1) size
975 * 2) frequency of update
976 * 3) opacity (though some hw might support alpha blending)
977 * 4) clipping (this can be fixed with color keys)
978 *
979 * The idea is to save on blitting since this should save power.
980 * If we can get a large video surface on the sprite for example,
981 * the main display surface may not need to update at all, and
982 * the client buffer can be used directly for the sprite surface
983 * as we do for flipping full screen surfaces.
984 */
985 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400986 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400987 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200988 /* test whether this buffer can ever go into a plane:
989 * non-shm, or small enough to be a cursor
990 */
991 if ((es->buffer_ref.buffer &&
992 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
993 (es->geometry.width <= 64 && es->geometry.height <= 64))
994 es->keep_buffer = 1;
995 else
996 es->keep_buffer = 0;
997
Jesse Barnes58ef3792012-02-23 09:45:49 -0500998 pixman_region32_init(&surface_overlap);
999 pixman_region32_intersect(&surface_overlap, &overlap,
1000 &es->transform.boundingbox);
1001
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001002 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001003 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001004 next_plane = primary;
1005 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001006 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001007 if (next_plane == NULL)
1008 next_plane = drm_output_prepare_scanout_surface(output, es);
1009 if (next_plane == NULL)
1010 next_plane = drm_output_prepare_overlay_surface(output, es);
1011 if (next_plane == NULL)
1012 next_plane = primary;
1013 weston_surface_move_to_plane(es, next_plane);
1014 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001015 pixman_region32_union(&overlap, &overlap,
1016 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001017
Jesse Barnes58ef3792012-02-23 09:45:49 -05001018 pixman_region32_fini(&surface_overlap);
1019 }
1020 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001021}
1022
Matt Roper361d2ad2011-08-29 13:52:23 -07001023static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001024drm_output_fini_pixman(struct drm_output *output);
1025
1026static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001027drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001028{
1029 struct drm_output *output = (struct drm_output *) output_base;
1030 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001031 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001032 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001033
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001034 if (output->backlight)
1035 backlight_destroy(output->backlight);
1036
Matt Roper361d2ad2011-08-29 13:52:23 -07001037 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001038 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001039
1040 /* Restore original CRTC state */
1041 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001042 origcrtc->x, origcrtc->y,
1043 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001044 drmModeFreeCrtc(origcrtc);
1045
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001046 c->crtc_allocator &= ~(1 << output->crtc_id);
1047 c->connector_allocator &= ~(1 << output->connector_id);
1048
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001049 if (c->use_pixman) {
1050 drm_output_fini_pixman(output);
1051 } else {
1052 gl_renderer_output_destroy(output_base);
1053 gbm_surface_destroy(output->surface);
1054 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001055
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001056 weston_plane_release(&output->fb_plane);
1057 weston_plane_release(&output->cursor_plane);
1058
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001059 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001060 wl_list_remove(&output->base.link);
1061
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001062 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001063 free(output);
1064}
1065
Alex Wub7b8bda2012-04-17 17:20:48 +08001066static struct drm_mode *
1067choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1068{
1069 struct drm_mode *tmp_mode = NULL, *mode;
1070
1071 if (output->base.current->width == target_mode->width &&
1072 output->base.current->height == target_mode->height &&
1073 (output->base.current->refresh == target_mode->refresh ||
1074 target_mode->refresh == 0))
1075 return (struct drm_mode *)output->base.current;
1076
1077 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1078 if (mode->mode_info.hdisplay == target_mode->width &&
1079 mode->mode_info.vdisplay == target_mode->height) {
1080 if (mode->mode_info.vrefresh == target_mode->refresh ||
1081 target_mode->refresh == 0) {
1082 return mode;
1083 } else if (!tmp_mode)
1084 tmp_mode = mode;
1085 }
1086 }
1087
1088 return tmp_mode;
1089}
1090
1091static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001092drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001093static int
1094drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001095
1096static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001097drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1098{
1099 struct drm_output *output;
1100 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001101 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001102
1103 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001104 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001105 return -1;
1106 }
1107
1108 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001109 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001110 return -1;
1111 }
1112
1113 ec = (struct drm_compositor *)output_base->compositor;
1114 output = (struct drm_output *)output_base;
1115 drm_mode = choose_mode (output, mode);
1116
1117 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001118 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001119 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001120 }
1121
1122 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001123 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001124
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001125 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001126
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001127 output->base.current = &drm_mode->base;
1128 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001129 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1130
Alex Wub7b8bda2012-04-17 17:20:48 +08001131 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001132 drm_output_release_fb(output, output->current);
1133 drm_output_release_fb(output, output->next);
1134 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001135
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001136 if (ec->use_pixman) {
1137 drm_output_fini_pixman(output);
1138 if (drm_output_init_pixman(output, ec) < 0) {
1139 weston_log("failed to init output pixman state with "
1140 "new mode\n");
1141 return -1;
1142 }
1143 } else {
1144 gl_renderer_output_destroy(&output->base);
1145 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001146
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001147 if (drm_output_init_egl(output, ec) < 0) {
1148 weston_log("failed to init output egl state with "
1149 "new mode");
1150 return -1;
1151 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001152 }
1153
Alex Wub7b8bda2012-04-17 17:20:48 +08001154 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001155}
1156
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001157static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001158on_drm_input(int fd, uint32_t mask, void *data)
1159{
1160 drmEventContext evctx;
1161
1162 memset(&evctx, 0, sizeof evctx);
1163 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1164 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001165 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001166 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001167
1168 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001169}
1170
1171static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001172init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001173{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001174 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001175 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001176
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001177 sysnum = udev_device_get_sysnum(device);
1178 if (sysnum)
1179 ec->drm.id = atoi(sysnum);
1180 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001181 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001182 return -1;
1183 }
1184
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001185 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001186 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001187 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001188 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001189 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001190 udev_device_get_devnode(device));
1191 return -1;
1192 }
1193
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001194 weston_log("using %s\n", filename);
1195
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001196 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001197
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001198
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001199 return 0;
1200}
1201
1202static int
1203init_egl(struct drm_compositor *ec)
1204{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001205 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001206
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001207 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001208 NULL) < 0) {
1209 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001210 return -1;
1211 }
1212
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001213 return 0;
1214}
1215
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001216static int
1217init_pixman(struct drm_compositor *ec)
1218{
1219 return pixman_renderer_init(&ec->base);
1220}
1221
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001222static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001223drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1224{
1225 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001226 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001227
1228 mode = malloc(sizeof *mode);
1229 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001230 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001231
1232 mode->base.flags = 0;
1233 mode->base.width = info->hdisplay;
1234 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001235
1236 /* Calculate higher precision (mHz) refresh rate */
1237 refresh = (info->clock * 1000000LL / info->htotal +
1238 info->vtotal / 2) / info->vtotal;
1239
1240 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1241 refresh *= 2;
1242 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1243 refresh /= 2;
1244 if (info->vscan > 1)
1245 refresh /= info->vscan;
1246
1247 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001248 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001249
1250 if (info->type & DRM_MODE_TYPE_PREFERRED)
1251 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1252
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001253 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1254
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001255 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001256}
1257
1258static int
1259drm_subpixel_to_wayland(int drm_value)
1260{
1261 switch (drm_value) {
1262 default:
1263 case DRM_MODE_SUBPIXEL_UNKNOWN:
1264 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1265 case DRM_MODE_SUBPIXEL_NONE:
1266 return WL_OUTPUT_SUBPIXEL_NONE;
1267 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1268 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1269 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1270 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1271 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1272 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1273 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1274 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1275 }
1276}
1277
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001278/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001279static uint32_t
1280drm_get_backlight(struct drm_output *output)
1281{
1282 long brightness, max_brightness, norm;
1283
1284 brightness = backlight_get_brightness(output->backlight);
1285 max_brightness = backlight_get_max_brightness(output->backlight);
1286
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001287 /* convert it on a scale of 0 to 255 */
1288 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001289
1290 return (uint32_t) norm;
1291}
1292
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001293/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001294static void
1295drm_set_backlight(struct weston_output *output_base, uint32_t value)
1296{
1297 struct drm_output *output = (struct drm_output *) output_base;
1298 long max_brightness, new_brightness;
1299
1300 if (!output->backlight)
1301 return;
1302
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001303 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001304 return;
1305
1306 max_brightness = backlight_get_max_brightness(output->backlight);
1307
1308 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001309 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001310
1311 backlight_set_brightness(output->backlight, new_brightness);
1312}
1313
1314static drmModePropertyPtr
1315drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1316{
1317 drmModePropertyPtr props;
1318 int i;
1319
1320 for (i = 0; i < connector->count_props; i++) {
1321 props = drmModeGetProperty(fd, connector->props[i]);
1322 if (!props)
1323 continue;
1324
1325 if (!strcmp(props->name, name))
1326 return props;
1327
1328 drmModeFreeProperty(props);
1329 }
1330
1331 return NULL;
1332}
1333
1334static void
1335drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1336{
1337 struct drm_output *output = (struct drm_output *) output_base;
1338 struct weston_compositor *ec = output_base->compositor;
1339 struct drm_compositor *c = (struct drm_compositor *) ec;
1340 drmModeConnectorPtr connector;
1341 drmModePropertyPtr prop;
1342
1343 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1344 if (!connector)
1345 return;
1346
1347 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1348 if (!prop) {
1349 drmModeFreeConnector(connector);
1350 return;
1351 }
1352
1353 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1354 prop->prop_id, level);
1355 drmModeFreeProperty(prop);
1356 drmModeFreeConnector(connector);
1357}
1358
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001359static const char *connector_type_names[] = {
1360 "None",
1361 "VGA",
1362 "DVI",
1363 "DVI",
1364 "DVI",
1365 "Composite",
1366 "TV",
1367 "LVDS",
1368 "CTV",
1369 "DIN",
1370 "DP",
1371 "HDMI",
1372 "HDMI",
1373 "TV",
1374 "eDP",
1375};
1376
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001377static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001378find_crtc_for_connector(struct drm_compositor *ec,
1379 drmModeRes *resources, drmModeConnector *connector)
1380{
1381 drmModeEncoder *encoder;
1382 uint32_t possible_crtcs;
1383 int i, j;
1384
1385 for (j = 0; j < connector->count_encoders; j++) {
1386 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1387 if (encoder == NULL) {
1388 weston_log("Failed to get encoder.\n");
1389 return -1;
1390 }
1391 possible_crtcs = encoder->possible_crtcs;
1392 drmModeFreeEncoder(encoder);
1393
1394 for (i = 0; i < resources->count_crtcs; i++) {
1395 if (possible_crtcs & (1 << i) &&
1396 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1397 return i;
1398 }
1399 }
1400
1401 return -1;
1402}
1403
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001404/* Init output state that depends on gl or gbm */
1405static int
1406drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1407{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001408 int i, flags;
1409
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001410 output->surface = gbm_surface_create(ec->gbm,
1411 output->base.current->width,
1412 output->base.current->height,
1413 GBM_FORMAT_XRGB8888,
1414 GBM_BO_USE_SCANOUT |
1415 GBM_BO_USE_RENDERING);
1416 if (!output->surface) {
1417 weston_log("failed to create gbm surface\n");
1418 return -1;
1419 }
1420
1421 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001422 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001423 gbm_surface_destroy(output->surface);
1424 return -1;
1425 }
1426
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001427 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1428
1429 for (i = 0; i < 2; i++) {
1430 if (output->cursor_bo[i])
1431 continue;
1432
1433 output->cursor_bo[i] =
1434 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1435 flags);
1436 }
1437
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001438 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1439 weston_log("cursor buffers unavailable, using gl cursors\n");
1440 ec->cursors_are_broken = 1;
1441 }
1442
1443 return 0;
1444}
1445
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001446static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001447drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1448{
1449 int w = output->base.current->width;
1450 int h = output->base.current->height;
1451 unsigned int i;
1452
1453 /* FIXME error checking */
1454
1455 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1456 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1457 if (!output->dumb[i])
1458 goto err;
1459
1460 output->image[i] =
1461 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1462 output->dumb[i]->map,
1463 output->dumb[i]->stride);
1464 if (!output->image[i])
1465 goto err;
1466 }
1467
1468 if (pixman_renderer_output_create(&output->base) < 0)
1469 goto err;
1470
1471 pixman_region32_init_rect(&output->previous_damage,
1472 output->base.x, output->base.y, w, h);
1473
1474 return 0;
1475
1476err:
1477 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1478 if (output->dumb[i])
1479 drm_fb_destroy_dumb(output->dumb[i]);
1480 if (output->image[i])
1481 pixman_image_unref(output->image[i]);
1482
1483 output->dumb[i] = NULL;
1484 output->image[i] = NULL;
1485 }
1486
1487 return -1;
1488}
1489
1490static void
1491drm_output_fini_pixman(struct drm_output *output)
1492{
1493 unsigned int i;
1494
1495 pixman_renderer_output_destroy(&output->base);
1496 pixman_region32_fini(&output->previous_damage);
1497
1498 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1499 drm_fb_destroy_dumb(output->dumb[i]);
1500 pixman_image_unref(output->image[i]);
1501 output->dumb[i] = NULL;
1502 output->image[i] = NULL;
1503 }
1504}
1505
1506static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001507create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001508 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001509 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001510 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001511{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001512 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001513 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1514 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001515 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001516 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001517 drmModeModeInfo crtc_mode;
1518 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001519 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001520 char name[32];
1521 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001522
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001523 i = find_crtc_for_connector(ec, resources, connector);
1524 if (i < 0) {
1525 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001526 return -1;
1527 }
1528
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001529 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001530 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001531 return -1;
1532
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001533 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001534 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1535 output->base.make = "unknown";
1536 output->base.model = "unknown";
1537 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001538
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001539 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1540 type_name = connector_type_names[connector->connector_type];
1541 else
1542 type_name = "UNKNOWN";
1543 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1544 output->name = strdup(name);
1545
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001546 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001547 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001548 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001549 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001550 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001551
Matt Roper361d2ad2011-08-29 13:52:23 -07001552 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1553
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001554 /* Get the current mode on the crtc that's currently driving
1555 * this connector. */
1556 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001557 memset(&crtc_mode, 0, sizeof crtc_mode);
1558 if (encoder != NULL) {
1559 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1560 drmModeFreeEncoder(encoder);
1561 if (crtc == NULL)
1562 goto err_free;
1563 if (crtc->mode_valid)
1564 crtc_mode = crtc->mode;
1565 drmModeFreeCrtc(crtc);
1566 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001567
David Herrmann0f0d54e2011-12-08 17:05:45 +01001568 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001569 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1570 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001571 goto err_free;
1572 }
1573
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001574 preferred = NULL;
1575 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001576 configured = NULL;
1577
1578 wl_list_for_each(temp, &configured_output_list, link) {
1579 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001580 if (temp->mode)
1581 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001582 temp->name, temp->mode);
1583 o = temp;
1584 break;
1585 }
1586 }
1587
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001588 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001589 weston_log("Disabling output %s\n", o->name);
1590
1591 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1592 0, 0, 0, 0, 0, NULL);
1593 goto err_free;
1594 }
1595
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001596 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001597 if (o && o->config == OUTPUT_CONFIG_MODE &&
1598 o->width == drm_mode->base.width &&
1599 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001600 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001601 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001602 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001603 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001604 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001605 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001606
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001607 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001608 configured = drm_output_add_mode(output, &o->crtc_mode);
1609 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001610 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001611 current = configured;
1612 }
1613
Wang Quanxianacb805a2012-07-30 18:09:46 -04001614 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001615 current = drm_output_add_mode(output, &crtc_mode);
1616 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001617 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001618 }
1619
Scott Moreau8ab5d452012-07-30 19:51:08 -06001620 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1621 configured = current;
1622
Wang Quanxianacb805a2012-07-30 18:09:46 -04001623 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001624 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001625 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001626 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001627 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001628 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001629 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001630 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001631
1632 if (output->base.current == NULL) {
1633 weston_log("no available modes for %s\n", output->name);
1634 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001635 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001636
Wang Quanxianacb805a2012-07-30 18:09:46 -04001637 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1638
John Kåre Alsaker94659272012-11-13 19:10:18 +01001639 weston_output_init(&output->base, &ec->base, x, y,
1640 connector->mmWidth, connector->mmHeight,
1641 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1642
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001643 if (ec->use_pixman) {
1644 if (drm_output_init_pixman(output, ec) < 0) {
1645 weston_log("Failed to init output pixman state\n");
1646 goto err_output;
1647 }
1648 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001649 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001650 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001651 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001652
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001653 output->backlight = backlight_init(drm_device,
1654 connector->connector_type);
1655 if (output->backlight) {
1656 output->base.set_backlight = drm_set_backlight;
1657 output->base.backlight_current = drm_get_backlight(output);
1658 }
1659
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001660 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1661
Alex Wubd3354b2012-04-17 17:20:49 +08001662 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001663 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001664 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001665 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001666 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001667 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001668
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001669 weston_plane_init(&output->cursor_plane, 0, 0);
1670 weston_plane_init(&output->fb_plane, 0, 0);
1671
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001672 weston_log("Output %s, (connector %d, crtc %d)\n",
1673 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001674 wl_list_for_each(m, &output->base.mode_list, link)
1675 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1676 m->width, m->height, m->refresh / 1000.0,
1677 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1678 ", preferred" : "",
1679 m->flags & WL_OUTPUT_MODE_CURRENT ?
1680 ", current" : "",
1681 connector->count_modes == 0 ?
1682 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001683
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001684 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001685
John Kåre Alsaker94659272012-11-13 19:10:18 +01001686err_output:
1687 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001688err_free:
1689 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1690 base.link) {
1691 wl_list_remove(&drm_mode->base.link);
1692 free(drm_mode);
1693 }
1694
1695 drmModeFreeCrtc(output->original_crtc);
1696 ec->crtc_allocator &= ~(1 << output->crtc_id);
1697 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001698 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001699 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001700
David Herrmann0f0d54e2011-12-08 17:05:45 +01001701 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001702}
1703
Jesse Barnes58ef3792012-02-23 09:45:49 -05001704static void
1705create_sprites(struct drm_compositor *ec)
1706{
1707 struct drm_sprite *sprite;
1708 drmModePlaneRes *plane_res;
1709 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001710 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001711
1712 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1713 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001714 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001715 strerror(errno));
1716 return;
1717 }
1718
1719 for (i = 0; i < plane_res->count_planes; i++) {
1720 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1721 if (!plane)
1722 continue;
1723
1724 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1725 plane->count_formats));
1726 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001727 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001728 __func__);
1729 free(plane);
1730 continue;
1731 }
1732
1733 memset(sprite, 0, sizeof *sprite);
1734
1735 sprite->possible_crtcs = plane->possible_crtcs;
1736 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001737 sprite->current = NULL;
1738 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001739 sprite->compositor = ec;
1740 sprite->count_formats = plane->count_formats;
1741 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001742 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001743 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001744 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001745
1746 wl_list_insert(&ec->sprite_list, &sprite->link);
1747 }
1748
1749 free(plane_res->planes);
1750 free(plane_res);
1751}
1752
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001753static void
1754destroy_sprites(struct drm_compositor *compositor)
1755{
1756 struct drm_sprite *sprite, *next;
1757 struct drm_output *output;
1758
1759 output = container_of(compositor->base.output_list.next,
1760 struct drm_output, base.link);
1761
1762 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1763 drmModeSetPlane(compositor->drm.fd,
1764 sprite->plane_id,
1765 output->crtc_id, 0, 0,
1766 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001767 drm_output_release_fb(output, sprite->current);
1768 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001769 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001770 free(sprite);
1771 }
1772}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001773
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001774static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001775create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001776 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001777{
1778 drmModeConnector *connector;
1779 drmModeRes *resources;
1780 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001781 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001782
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001783 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001784 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001785 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001786 return -1;
1787 }
1788
Jesse Barnes58ef3792012-02-23 09:45:49 -05001789 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001790 if (!ec->crtcs) {
1791 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001792 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001793 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001794
Rob Clark4339add2012-08-09 14:18:28 -05001795 ec->min_width = resources->min_width;
1796 ec->max_width = resources->max_width;
1797 ec->min_height = resources->min_height;
1798 ec->max_height = resources->max_height;
1799
Jesse Barnes58ef3792012-02-23 09:45:49 -05001800 ec->num_crtcs = resources->count_crtcs;
1801 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1802
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001803 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001804 connector = drmModeGetConnector(ec->drm.fd,
1805 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001806 if (connector == NULL)
1807 continue;
1808
1809 if (connector->connection == DRM_MODE_CONNECTED &&
1810 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001811 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001812 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001813 connector, x, y,
1814 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001815 drmModeFreeConnector(connector);
1816 continue;
1817 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001818
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001819 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001820 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001821 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001822 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001823
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001824 drmModeFreeConnector(connector);
1825 }
1826
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001827 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001828 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001829 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001830 return -1;
1831 }
1832
1833 drmModeFreeResources(resources);
1834
1835 return 0;
1836}
1837
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001838static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001839update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001840{
1841 drmModeConnector *connector;
1842 drmModeRes *resources;
1843 struct drm_output *output, *next;
1844 int x = 0, y = 0;
1845 int x_offset = 0, y_offset = 0;
1846 uint32_t connected = 0, disconnects = 0;
1847 int i;
1848
1849 resources = drmModeGetResources(ec->drm.fd);
1850 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001851 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001852 return;
1853 }
1854
1855 /* collect new connects */
1856 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001857 int connector_id = resources->connectors[i];
1858
1859 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001860 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001861 continue;
1862
David Herrmann7551cff2011-12-08 17:05:43 +01001863 if (connector->connection != DRM_MODE_CONNECTED) {
1864 drmModeFreeConnector(connector);
1865 continue;
1866 }
1867
Benjamin Franzke117483d2011-08-30 11:38:26 +02001868 connected |= (1 << connector_id);
1869
1870 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001871 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001872 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001873 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001874
1875 /* XXX: not yet needed, we die with 0 outputs */
1876 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001877 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001878 else
1879 x = 0;
1880 y = 0;
1881 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001882 connector, x, y,
1883 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001884 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001885
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001886 }
1887 drmModeFreeConnector(connector);
1888 }
1889 drmModeFreeResources(resources);
1890
1891 disconnects = ec->connector_allocator & ~connected;
1892 if (disconnects) {
1893 wl_list_for_each_safe(output, next, &ec->base.output_list,
1894 base.link) {
1895 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001896 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001897 output->base.x - x_offset,
1898 output->base.y - y_offset);
1899 }
1900
1901 if (disconnects & (1 << output->connector_id)) {
1902 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001903 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001904 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001905 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001906 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001907 }
1908 }
1909 }
1910
1911 /* FIXME: handle zero outputs, without terminating */
1912 if (ec->connector_allocator == 0)
1913 wl_display_terminate(ec->base.wl_display);
1914}
1915
1916static int
David Herrmannd7488c22012-03-11 20:05:21 +01001917udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001918{
David Herrmannd7488c22012-03-11 20:05:21 +01001919 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001920 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001921
1922 sysnum = udev_device_get_sysnum(device);
1923 if (!sysnum || atoi(sysnum) != ec->drm.id)
1924 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001925
David Herrmann6ac52db2012-03-11 20:05:22 +01001926 val = udev_device_get_property_value(device, "HOTPLUG");
1927 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001928 return 0;
1929
David Herrmann6ac52db2012-03-11 20:05:22 +01001930 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001931}
1932
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001933static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001934udev_drm_event(int fd, uint32_t mask, void *data)
1935{
1936 struct drm_compositor *ec = data;
1937 struct udev_device *event;
1938
1939 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001940
David Herrmannd7488c22012-03-11 20:05:21 +01001941 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001942 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001943
1944 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001945
1946 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001947}
1948
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001949static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001950drm_restore(struct weston_compositor *ec)
1951{
1952 struct drm_compositor *d = (struct drm_compositor *) ec;
1953
1954 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1955 weston_log("failed to drop master: %m\n");
1956 tty_reset(d->tty);
1957}
1958
Pekka Paalanen33156972012-08-03 13:30:30 -04001959static const char default_seat[] = "seat0";
1960
1961static void
1962device_added(struct udev_device *udev_device, struct drm_seat *master)
1963{
1964 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001965 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001966 const char *devnode;
1967 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001968 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001969 int fd;
1970
1971 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1972 if (!device_seat)
1973 device_seat = default_seat;
1974
1975 if (strcmp(device_seat, master->seat_id))
1976 return;
1977
1978 c = master->base.compositor;
1979 devnode = udev_device_get_devnode(udev_device);
1980
1981 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001982 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001983 * read. mtdev_get() also expects this. */
1984 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1985 if (fd < 0) {
1986 weston_log("opening input device '%s' failed.\n", devnode);
1987 return;
1988 }
1989
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001990 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001991 if (!device) {
1992 close(fd);
1993 weston_log("not using input device '%s'.\n", devnode);
1994 return;
1995 }
1996
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001997 calibration_values =
1998 udev_device_get_property_value(udev_device,
1999 "WL_CALIBRATION");
2000
2001 if (calibration_values && sscanf(calibration_values,
2002 "%f %f %f %f %f %f",
2003 &device->abs.calibration[0],
2004 &device->abs.calibration[1],
2005 &device->abs.calibration[2],
2006 &device->abs.calibration[3],
2007 &device->abs.calibration[4],
2008 &device->abs.calibration[5]) == 6) {
2009 device->abs.apply_calibration = 1;
2010 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
2011 device->abs.calibration[0],
2012 device->abs.calibration[1],
2013 device->abs.calibration[2],
2014 device->abs.calibration[3],
2015 device->abs.calibration[4],
2016 device->abs.calibration[5]);
2017 }
2018
Pekka Paalanen33156972012-08-03 13:30:30 -04002019 wl_list_insert(master->devices_list.prev, &device->link);
2020}
2021
2022static void
2023evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
2024{
2025 struct drm_seat *seat = (struct drm_seat *) seat_base;
2026 struct udev_enumerate *e;
2027 struct udev_list_entry *entry;
2028 struct udev_device *device;
2029 const char *path, *sysname;
2030
2031 e = udev_enumerate_new(udev);
2032 udev_enumerate_add_match_subsystem(e, "input");
2033 udev_enumerate_scan_devices(e);
2034 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2035 path = udev_list_entry_get_name(entry);
2036 device = udev_device_new_from_syspath(udev, path);
2037
2038 sysname = udev_device_get_sysname(device);
2039 if (strncmp("event", sysname, 5) != 0) {
2040 udev_device_unref(device);
2041 continue;
2042 }
2043
2044 device_added(device, seat);
2045
2046 udev_device_unref(device);
2047 }
2048 udev_enumerate_unref(e);
2049
2050 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
2051
2052 if (wl_list_empty(&seat->devices_list)) {
2053 weston_log(
2054 "warning: no input devices on entering Weston. "
2055 "Possible causes:\n"
2056 "\t- no permissions to read /dev/input/event*\n"
2057 "\t- seats misconfigured "
2058 "(Weston backend option 'seat', "
2059 "udev device property ID_SEAT)\n");
2060 }
2061}
2062
2063static int
2064evdev_udev_handler(int fd, uint32_t mask, void *data)
2065{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002066 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04002067 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002068 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002069 const char *action;
2070 const char *devnode;
2071
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002072 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04002073 if (!udev_device)
2074 return 1;
2075
2076 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002077 if (!action)
2078 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04002079
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002080 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
2081 goto out;
2082
2083 if (!strcmp(action, "add")) {
2084 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002085 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002086 else if (!strcmp(action, "remove")) {
2087 devnode = udev_device_get_devnode(udev_device);
2088 wl_list_for_each_safe(device, next, &seat->devices_list, link)
2089 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03002090 weston_log("input device %s, %s removed\n",
2091 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002092 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002093 break;
2094 }
2095 }
2096
2097out:
Pekka Paalanen33156972012-08-03 13:30:30 -04002098 udev_device_unref(udev_device);
2099
2100 return 0;
2101}
2102
2103static int
2104evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
2105{
2106 struct drm_seat *master = (struct drm_seat *) seat_base;
2107 struct wl_event_loop *loop;
2108 struct weston_compositor *c = master->base.compositor;
2109 int fd;
2110
2111 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
2112 if (!master->udev_monitor) {
2113 weston_log("udev: failed to create the udev monitor\n");
2114 return 0;
2115 }
2116
2117 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
2118 "input", NULL);
2119
2120 if (udev_monitor_enable_receiving(master->udev_monitor)) {
2121 weston_log("udev: failed to bind the udev monitor\n");
2122 udev_monitor_unref(master->udev_monitor);
2123 return 0;
2124 }
2125
2126 loop = wl_display_get_event_loop(c->wl_display);
2127 fd = udev_monitor_get_fd(master->udev_monitor);
2128 master->udev_monitor_source =
2129 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
2130 evdev_udev_handler, master);
2131 if (!master->udev_monitor_source) {
2132 udev_monitor_unref(master->udev_monitor);
2133 return 0;
2134 }
2135
2136 return 1;
2137}
2138
2139static void
2140evdev_disable_udev_monitor(struct weston_seat *seat_base)
2141{
2142 struct drm_seat *seat = (struct drm_seat *) seat_base;
2143
2144 if (!seat->udev_monitor)
2145 return;
2146
2147 udev_monitor_unref(seat->udev_monitor);
2148 seat->udev_monitor = NULL;
2149 wl_event_source_remove(seat->udev_monitor_source);
2150 seat->udev_monitor_source = NULL;
2151}
2152
2153static void
2154drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
2155{
2156 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002157 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002158
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002159 wl_list_for_each(device, &seat->devices_list, link)
2160 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002161}
2162
2163static void
2164evdev_input_create(struct weston_compositor *c, struct udev *udev,
2165 const char *seat_id)
2166{
2167 struct drm_seat *seat;
2168
2169 seat = malloc(sizeof *seat);
2170 if (seat == NULL)
2171 return;
2172
2173 memset(seat, 0, sizeof *seat);
2174 weston_seat_init(&seat->base, c);
2175 seat->base.led_update = drm_led_update;
2176
2177 wl_list_init(&seat->devices_list);
2178 seat->seat_id = strdup(seat_id);
2179 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2180 free(seat->seat_id);
2181 free(seat);
2182 return;
2183 }
2184
2185 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002186}
2187
2188static void
2189evdev_remove_devices(struct weston_seat *seat_base)
2190{
2191 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002192 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002193
2194 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002195 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002196
Pekka Paalanend8583512012-08-03 14:39:11 +03002197 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002198 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002199}
2200
2201static void
2202evdev_input_destroy(struct weston_seat *seat_base)
2203{
2204 struct drm_seat *seat = (struct drm_seat *) seat_base;
2205
2206 evdev_remove_devices(seat_base);
2207 evdev_disable_udev_monitor(&seat->base);
2208
2209 weston_seat_release(seat_base);
2210 free(seat->seat_id);
2211 free(seat);
2212}
2213
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002214static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002215drm_free_configured_output(struct drm_configured_output *output)
2216{
2217 free(output->name);
2218 free(output->mode);
2219 free(output);
2220}
2221
2222static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002223drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002224{
2225 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002226 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002227 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002228
Daniel Stone37816df2012-05-16 18:45:18 +01002229 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2230 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002231 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002232 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002233
2234 wl_event_source_remove(d->udev_drm_source);
2235 wl_event_source_remove(d->drm_source);
2236
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002237 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002238
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002239 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002240
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002241 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002242
2243 if (d->gbm)
2244 gbm_device_destroy(d->gbm);
2245
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002246 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002247 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002248 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002249
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002250 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002251}
2252
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002253static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002254drm_compositor_set_modes(struct drm_compositor *compositor)
2255{
2256 struct drm_output *output;
2257 struct drm_mode *drm_mode;
2258 int ret;
2259
2260 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2261 drm_mode = (struct drm_mode *) output->base.current;
2262 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002263 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002264 &output->connector_id, 1,
2265 &drm_mode->mode_info);
2266 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002267 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002268 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002269 drm_mode->base.width, drm_mode->base.height,
2270 output->base.x, output->base.y);
2271 }
2272 }
2273}
2274
2275static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002276vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002277{
2278 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002279 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002280 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002281 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002282
2283 switch (event) {
2284 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002285 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002286 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002287 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002288 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002289 wl_display_terminate(compositor->wl_display);
2290 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002291 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002292 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002293 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002294 wl_list_for_each(seat, &compositor->seat_list, link) {
2295 evdev_add_devices(ec->udev, seat);
2296 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002297 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002298 break;
2299 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002300 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002301 wl_list_for_each(seat, &compositor->seat_list, link) {
2302 evdev_disable_udev_monitor(seat);
2303 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002304 }
2305
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002306 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002307 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002308 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002309
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002310 /* If we have a repaint scheduled (either from a
2311 * pending pageflip or the idle handler), make sure we
2312 * cancel that so we don't try to pageflip when we're
2313 * vt switched away. The SLEEPING state will prevent
2314 * further attemps at repainting. When we switch
2315 * back, we schedule a repaint, which will process
2316 * pending frame callbacks. */
2317
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002318 wl_list_for_each(output, &ec->base.output_list, base.link) {
2319 output->base.repaint_needed = 0;
2320 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002321 }
2322
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002323 output = container_of(ec->base.output_list.next,
2324 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002325
2326 wl_list_for_each(sprite, &ec->sprite_list, link)
2327 drmModeSetPlane(ec->drm.fd,
2328 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002329 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002330 0, 0, 0, 0, 0, 0, 0, 0);
2331
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002332 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002333 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002334
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002335 break;
2336 };
2337}
2338
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002339static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002340switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002341{
2342 struct drm_compositor *ec = data;
2343
Daniel Stone325fc2d2012-05-30 16:31:58 +01002344 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002345}
2346
David Herrmann0af066f2012-10-29 19:21:16 +01002347/*
2348 * Find primary GPU
2349 * Some systems may have multiple DRM devices attached to a single seat. This
2350 * function loops over all devices and tries to find a PCI device with the
2351 * boot_vga sysfs attribute set to 1.
2352 * If no such device is found, the first DRM device reported by udev is used.
2353 */
2354static struct udev_device*
2355find_primary_gpu(struct drm_compositor *ec, const char *seat)
2356{
2357 struct udev_enumerate *e;
2358 struct udev_list_entry *entry;
2359 const char *path, *device_seat, *id;
2360 struct udev_device *device, *drm_device, *pci;
2361
2362 e = udev_enumerate_new(ec->udev);
2363 udev_enumerate_add_match_subsystem(e, "drm");
2364 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2365
2366 udev_enumerate_scan_devices(e);
2367 drm_device = NULL;
2368 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2369 path = udev_list_entry_get_name(entry);
2370 device = udev_device_new_from_syspath(ec->udev, path);
2371 if (!device)
2372 continue;
2373 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2374 if (!device_seat)
2375 device_seat = default_seat;
2376 if (strcmp(device_seat, seat)) {
2377 udev_device_unref(device);
2378 continue;
2379 }
2380
2381 pci = udev_device_get_parent_with_subsystem_devtype(device,
2382 "pci", NULL);
2383 if (pci) {
2384 id = udev_device_get_sysattr_value(pci, "boot_vga");
2385 if (id && !strcmp(id, "1")) {
2386 if (drm_device)
2387 udev_device_unref(drm_device);
2388 drm_device = device;
2389 break;
2390 }
2391 }
2392
2393 if (!drm_device)
2394 drm_device = device;
2395 else
2396 udev_device_unref(device);
2397 }
2398
2399 udev_enumerate_unref(e);
2400 return drm_device;
2401}
2402
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002403static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002404planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002405{
2406 struct drm_compositor *c = data;
2407
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002408 switch (key) {
2409 case KEY_C:
2410 c->cursors_are_broken ^= 1;
2411 break;
2412 case KEY_V:
2413 c->sprites_are_broken ^= 1;
2414 break;
2415 case KEY_O:
2416 c->sprites_hidden ^= 1;
2417 break;
2418 default:
2419 break;
2420 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002421}
2422
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002423static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002424drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002425 int connector, const char *seat, int tty, int pixman,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002426 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002427{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002428 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002429 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002430 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002431 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002432 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002433 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002434
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002435 weston_log("initializing drm backend\n");
2436
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002437 ec = malloc(sizeof *ec);
2438 if (ec == NULL)
2439 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002440 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002441
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002442 /* KMS support for sprites is not complete yet, so disable the
2443 * functionality for now. */
2444 ec->sprites_are_broken = 1;
2445
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002446 ec->use_pixman = pixman;
2447
Daniel Stone725c2c32012-06-22 14:04:36 +01002448 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002449 config_file) < 0) {
2450 weston_log("weston_compositor_init failed\n");
2451 goto err_base;
2452 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002453
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002454 ec->udev = udev_new();
2455 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002456 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002457 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002458 }
2459
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002460 ec->base.wl_display = display;
2461 ec->tty = tty_create(&ec->base, vt_func, tty);
2462 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002463 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002464 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002465 }
2466
David Herrmann0af066f2012-10-29 19:21:16 +01002467 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002468 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002469 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002470 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002471 }
David Herrmann0af066f2012-10-29 19:21:16 +01002472 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002473
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002474 if (init_drm(ec, drm_device) < 0) {
2475 weston_log("failed to initialize kms\n");
2476 goto err_udev_dev;
2477 }
2478
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002479 if (ec->use_pixman) {
2480 if (init_pixman(ec) < 0) {
2481 weston_log("failed to initialize pixman renderer\n");
2482 goto err_udev_dev;
2483 }
2484 } else {
2485 if (init_egl(ec) < 0) {
2486 weston_log("failed to initialize egl\n");
2487 goto err_udev_dev;
2488 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002489 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002490
2491 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002492 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002493
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002494 ec->base.focus = 1;
2495
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002496 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002497
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002498 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002499 weston_compositor_add_key_binding(&ec->base, key,
2500 MODIFIER_CTRL | MODIFIER_ALT,
2501 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002502
Jesse Barnes58ef3792012-02-23 09:45:49 -05002503 wl_list_init(&ec->sprite_list);
2504 create_sprites(ec);
2505
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002506 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002507 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002508 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002509 }
2510
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002511 path = NULL;
2512
Tiago Vignattice03ec32011-12-19 01:14:03 +02002513 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002514
2515 loop = wl_display_get_event_loop(ec->base.wl_display);
2516 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002517 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002518 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002519
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002520 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2521 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002522 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002523 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002524 }
2525 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2526 "drm", NULL);
2527 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002528 wl_event_loop_add_fd(loop,
2529 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002530 WL_EVENT_READABLE, udev_drm_event, ec);
2531
2532 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002533 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002534 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002535 }
2536
Daniel Stonea96b93c2012-06-22 14:04:37 +01002537 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002538
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002539 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002540 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002541 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002542 planes_binding, ec);
2543 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2544 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002545
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002546 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002547
2548err_udev_monitor:
2549 wl_event_source_remove(ec->udev_drm_source);
2550 udev_monitor_unref(ec->udev_monitor);
2551err_drm_source:
2552 wl_event_source_remove(ec->drm_source);
2553 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2554 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002555err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002556 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002557 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002558 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002559err_udev_dev:
2560 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002561err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002562 tty_destroy(ec->tty);
2563err_udev:
2564 udev_unref(ec->udev);
2565err_compositor:
2566 weston_compositor_shutdown(&ec->base);
2567err_base:
2568 free(ec);
2569 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002570}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002571
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002572static int
2573set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2574{
2575 mode->flags = 0;
2576
2577 if (strcmp(hsync, "+hsync") == 0)
2578 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2579 else if (strcmp(hsync, "-hsync") == 0)
2580 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2581 else
2582 return -1;
2583
2584 if (strcmp(vsync, "+vsync") == 0)
2585 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2586 else if (strcmp(vsync, "-vsync") == 0)
2587 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2588 else
2589 return -1;
2590
2591 return 0;
2592}
2593
2594static int
2595check_for_modeline(struct drm_configured_output *output)
2596{
2597 drmModeModeInfo mode;
2598 char hsync[16];
2599 char vsync[16];
2600 char mode_name[16];
2601 float fclock;
2602
2603 mode.type = DRM_MODE_TYPE_USERDEF;
2604 mode.hskew = 0;
2605 mode.vscan = 0;
2606 mode.vrefresh = 0;
2607
2608 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2609 &fclock, &mode.hdisplay,
2610 &mode.hsync_start,
2611 &mode.hsync_end, &mode.htotal,
2612 &mode.vdisplay,
2613 &mode.vsync_start,
2614 &mode.vsync_end, &mode.vtotal,
2615 hsync, vsync) == 11) {
2616 if (set_sync_flags(&mode, hsync, vsync))
2617 return -1;
2618
2619 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2620 strcpy(mode.name, mode_name);
2621
2622 mode.clock = fclock * 1000;
2623 } else
2624 return -1;
2625
2626 output->crtc_mode = mode;
2627
2628 return 0;
2629}
2630
Scott Moreau8ab5d452012-07-30 19:51:08 -06002631static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002632drm_output_set_transform(struct drm_configured_output *output)
2633{
2634 if (!output_transform) {
2635 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2636 return;
2637 }
2638
2639 if (!strcmp(output_transform, "normal"))
2640 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2641 else if (!strcmp(output_transform, "90"))
2642 output->transform = WL_OUTPUT_TRANSFORM_90;
2643 else if (!strcmp(output_transform, "180"))
2644 output->transform = WL_OUTPUT_TRANSFORM_180;
2645 else if (!strcmp(output_transform, "270"))
2646 output->transform = WL_OUTPUT_TRANSFORM_270;
2647 else if (!strcmp(output_transform, "flipped"))
2648 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2649 else if (!strcmp(output_transform, "flipped-90"))
2650 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2651 else if (!strcmp(output_transform, "flipped-180"))
2652 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2653 else if (!strcmp(output_transform, "flipped-270"))
2654 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2655 else {
2656 weston_log("Invalid transform \"%s\" for output %s\n",
2657 output_transform, output_name);
2658 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2659 }
2660
2661 free(output_transform);
2662 output_transform = NULL;
2663}
2664
2665static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002666output_section_done(void *data)
2667{
2668 struct drm_configured_output *output;
2669
2670 output = malloc(sizeof *output);
2671
Scott Moreau1bad5db2012-08-18 01:04:05 -06002672 if (!output || !output_name || (output_name[0] == 'X') ||
2673 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002674 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002675 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002676 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002677 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002678 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002679 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002680 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002681 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002682 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002683
2684 output->config = OUTPUT_CONFIG_INVALID;
2685 output->name = output_name;
2686 output->mode = output_mode;
2687
Scott Moreau1bad5db2012-08-18 01:04:05 -06002688 if (output_mode) {
2689 if (strcmp(output_mode, "off") == 0)
2690 output->config = OUTPUT_CONFIG_OFF;
2691 else if (strcmp(output_mode, "preferred") == 0)
2692 output->config = OUTPUT_CONFIG_PREFERRED;
2693 else if (strcmp(output_mode, "current") == 0)
2694 output->config = OUTPUT_CONFIG_CURRENT;
2695 else if (sscanf(output_mode, "%dx%d",
2696 &output->width, &output->height) == 2)
2697 output->config = OUTPUT_CONFIG_MODE;
2698 else if (check_for_modeline(output) == 0)
2699 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002700
Scott Moreau1bad5db2012-08-18 01:04:05 -06002701 if (output->config == OUTPUT_CONFIG_INVALID)
2702 weston_log("Invalid mode \"%s\" for output %s\n",
2703 output_mode, output_name);
2704 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002705 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002706
2707 drm_output_set_transform(output);
2708
2709 wl_list_insert(&configured_output_list, &output->link);
2710
2711 if (output_transform)
2712 free(output_transform);
2713 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002714}
2715
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002716WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002717backend_init(struct wl_display *display, int argc, char *argv[],
2718 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002719{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002720 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002721 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002722
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002723 const struct weston_option drm_options[] = {
2724 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2725 { WESTON_OPTION_STRING, "seat", 0, &seat },
2726 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002727 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002728 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002729 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002730
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002731 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002732
Scott Moreau8ab5d452012-07-30 19:51:08 -06002733 wl_list_init(&configured_output_list);
2734
2735 const struct config_key drm_config_keys[] = {
2736 { "name", CONFIG_KEY_STRING, &output_name },
2737 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002738 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002739 };
2740
2741 const struct config_section config_section[] = {
2742 { "output", drm_config_keys,
2743 ARRAY_LENGTH(drm_config_keys), output_section_done },
2744 };
2745
2746 parse_config_file(config_file, config_section,
2747 ARRAY_LENGTH(config_section), NULL);
2748
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002749 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2750 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002751}