blob: b77d10351f24160dcaa7be53913851c872139978 [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"
Tiago Vignattice03ec32011-12-19 01:14:03 +020045#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010046#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047
Kristian Høgsberg061c4252012-06-28 11:28:15 -040048static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060049static char *output_name;
50static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060051static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060052static struct wl_list configured_output_list;
53
54enum output_config {
55 OUTPUT_CONFIG_INVALID = 0,
56 OUTPUT_CONFIG_OFF,
57 OUTPUT_CONFIG_PREFERRED,
58 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060059 OUTPUT_CONFIG_MODE,
60 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060061};
62
63struct drm_configured_output {
64 char *name;
65 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060066 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060067 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060068 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060069 enum output_config config;
70 struct wl_list link;
71};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040072
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050074 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040075
76 struct udev *udev;
77 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040078
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010079 struct udev_monitor *udev_monitor;
80 struct wl_event_source *udev_drm_source;
81
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010083 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010084 int fd;
85 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020086 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050087 uint32_t *crtcs;
88 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050089 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010090 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050091 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020092
Rob Clark4339add2012-08-09 14:18:28 -050093 /* we need these parameters in order to not fail drmModeAddFB2()
94 * due to out of bounds dimensions, and then mistakenly set
95 * sprites_are_broken:
96 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020097 uint32_t min_width, max_width;
98 uint32_t min_height, max_height;
99 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500100
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500102 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200103 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500104
Rob Clarkab5b1e32012-08-09 13:24:45 -0500105 int cursors_are_broken;
106
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200107 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400108};
109
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400110struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500111 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400112 drmModeModeInfo mode_info;
113};
114
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300115struct drm_output;
116
117struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200119 uint32_t fb_id, stride, handle, size;
120 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200122 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200123
124 /* Used by gbm fbs */
125 struct gbm_bo *bo;
126
127 /* Used by dumb fbs */
128 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300129};
130
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400131struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500132 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400133
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400134 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400135 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500136 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400137 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700138 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200139
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300140 int vblank_pending;
141 int page_flip_pending;
142
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400143 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400144 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400145 struct weston_plane cursor_plane;
146 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400147 struct weston_surface *cursor_surface;
148 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300149 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200150 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400151};
152
Jesse Barnes58ef3792012-02-23 09:45:49 -0500153/*
154 * An output has a primary display plane plus zero or more sprites for
155 * blending display contents.
156 */
157struct drm_sprite {
158 struct wl_list link;
159
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400160 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500161
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200162 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300163 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500164 struct drm_compositor *compositor;
165
Jesse Barnes58ef3792012-02-23 09:45:49 -0500166 uint32_t possible_crtcs;
167 uint32_t plane_id;
168 uint32_t count_formats;
169
170 int32_t src_x, src_y;
171 uint32_t src_w, src_h;
172 uint32_t dest_x, dest_y;
173 uint32_t dest_w, dest_h;
174
175 uint32_t formats[];
176};
177
Pekka Paalanen33156972012-08-03 13:30:30 -0400178struct drm_seat {
179 struct weston_seat base;
180 struct wl_list devices_list;
181 struct udev_monitor *udev_monitor;
182 struct wl_event_source *udev_monitor_source;
183 char *seat_id;
184};
185
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400186static void
187drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400188
Jesse Barnes58ef3792012-02-23 09:45:49 -0500189static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500190drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
191{
192 struct weston_compositor *ec = output_base->compositor;
193 struct drm_compositor *c =(struct drm_compositor *) ec;
194 struct drm_output *output = (struct drm_output *) output_base;
195 int crtc;
196
197 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
198 if (c->crtcs[crtc] != output->crtc_id)
199 continue;
200
201 if (supported & (1 << crtc))
202 return -1;
203 }
204
205 return 0;
206}
207
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300208static void
209drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
210{
211 struct drm_fb *fb = data;
212 struct gbm_device *gbm = gbm_bo_get_device(bo);
213
214 if (fb->fb_id)
215 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
216
Pekka Paalanende685b82012-12-04 15:58:12 +0200217 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300218
219 free(data);
220}
221
222static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200223drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
224{
225 struct drm_fb *fb;
226 int ret;
227
228 struct drm_mode_create_dumb create_arg;
229 struct drm_mode_destroy_dumb destroy_arg;
230 struct drm_mode_map_dumb map_arg;
231
232 fb = calloc(1, sizeof *fb);
233 if (!fb)
234 return NULL;
235
236 create_arg.bpp = 32;
237 create_arg.width = width;
238 create_arg.height = height;
239
240 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
241 if (ret)
242 goto err_fb;
243
244 fb->handle = create_arg.handle;
245 fb->stride = create_arg.pitch;
246 fb->size = create_arg.size;
247 fb->fd = ec->drm.fd;
248
249 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
250 fb->stride, fb->handle, &fb->fb_id);
251 if (ret)
252 goto err_bo;
253
254 memset(&map_arg, 0, sizeof(map_arg));
255 map_arg.handle = fb->handle;
256 drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
257
258 if (ret)
259 goto err_add_fb;
260
261 fb->map = mmap(0, fb->size, PROT_WRITE,
262 MAP_SHARED, ec->drm.fd, map_arg.offset);
263 if (fb->map == MAP_FAILED)
264 goto err_add_fb;
265
266 return fb;
267
268err_add_fb:
269 drmModeRmFB(ec->drm.fd, fb->fb_id);
270err_bo:
271 memset(&destroy_arg, 0, sizeof(destroy_arg));
272 destroy_arg.handle = create_arg.handle;
273 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
274err_fb:
275 free(fb);
276 return NULL;
277}
278
279static void
280drm_fb_destroy_dumb(struct drm_fb *fb)
281{
282 struct drm_mode_destroy_dumb destroy_arg;
283
284 if (!fb->map)
285 return;
286
287 if (fb->fb_id)
288 drmModeRmFB(fb->fd, fb->fb_id);
289
290 weston_buffer_reference(&fb->buffer_ref, NULL);
291
292 munmap(fb->map, fb->size);
293
294 memset(&destroy_arg, 0, sizeof(destroy_arg));
295 destroy_arg.handle = fb->handle;
296 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
297
298 free(fb);
299}
300
301static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500302drm_fb_get_from_bo(struct gbm_bo *bo,
303 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300304{
305 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200306 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200307 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300308 int ret;
309
310 if (fb)
311 return fb;
312
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200313 fb = calloc(1, sizeof *fb);
314 if (!fb)
315 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300316
317 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300318
319 width = gbm_bo_get_width(bo);
320 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200321 fb->stride = gbm_bo_get_stride(bo);
322 fb->handle = gbm_bo_get_handle(bo).u32;
323 fb->size = fb->stride * height;
324 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300325
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200326 if (compositor->min_width > width || width > compositor->max_width ||
327 compositor->min_height > height ||
328 height > compositor->max_height) {
329 weston_log("bo geometry out of bounds\n");
330 goto err_free;
331 }
332
333 ret = -1;
334
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200335 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200336 handles[0] = fb->handle;
337 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200338 offsets[0] = 0;
339
340 ret = drmModeAddFB2(compositor->drm.fd, width, height,
341 format, handles, pitches, offsets,
342 &fb->fb_id, 0);
343 if (ret) {
344 weston_log("addfb2 failed: %m\n");
345 compositor->no_addfb2 = 1;
346 compositor->sprites_are_broken = 1;
347 }
348 }
349
350 if (ret)
351 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200352 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200353
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200355 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200356 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300357 }
358
359 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
360
361 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200362
363err_free:
364 free(fb);
365 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366}
367
368static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200369drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
370{
Pekka Paalanende685b82012-12-04 15:58:12 +0200371 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200372
373 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200374
Pekka Paalanende685b82012-12-04 15:58:12 +0200375 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376}
377
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200378static void
379drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
380{
381 if (!fb)
382 return;
383
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200384 if (fb->map) {
385 drm_fb_destroy_dumb(fb);
386 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200387 if (fb->is_client_buffer)
388 gbm_bo_destroy(fb->bo);
389 else
390 gbm_surface_release_buffer(output->surface,
391 output->current->bo);
392 }
393}
394
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500395static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200396drm_output_check_scanout_format(struct drm_output *output,
397 struct weston_surface *es, struct gbm_bo *bo)
398{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200399 uint32_t format;
400 pixman_region32_t r;
401
402 format = gbm_bo_get_format(bo);
403
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500404 switch (format) {
405 case GBM_FORMAT_XRGB8888:
406 return format;
407 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200408 /* We can only scanout an ARGB buffer if the surface's
409 * opaque region covers the whole output */
410 pixman_region32_init(&r);
411 pixman_region32_subtract(&r, &output->base.region,
412 &es->opaque);
413
414 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500415 format = GBM_FORMAT_XRGB8888;
416 else
417 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200418
419 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500421 return format;
422 default:
423 return 0;
424 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200425}
426
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400427static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400428drm_output_prepare_scanout_surface(struct weston_output *_output,
429 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500430{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400431 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500432 struct drm_compositor *c =
433 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200434 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300435 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500436 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500437
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500438 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200439 es->geometry.y != output->base.y ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200440 buffer == NULL ||
441 buffer->width != output->base.current->width ||
442 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200443 output->base.transform != es->buffer_transform ||
444 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400445 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500446
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400447 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200448 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500449
Rob Bradford9b101872012-09-14 23:25:41 +0100450 /* Unable to use the buffer for scanout */
451 if (!bo)
452 return NULL;
453
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500454 format = drm_output_check_scanout_format(output, es, bo);
455 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300456 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400457 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300458 }
459
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500460 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300461 if (!output->next) {
462 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400463 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300464 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500465
Pekka Paalanende685b82012-12-04 15:58:12 +0200466 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500467
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400468 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500469}
470
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500471static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400472drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400473{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200474 struct drm_compositor *c =
475 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300476 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400477
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200478 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400479
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200480 pixman_region32_subtract(&c->base.primary_plane.damage,
481 &c->base.primary_plane.damage, damage);
482
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300483 bo = gbm_surface_lock_front_buffer(output->surface);
484 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200485 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400486 return;
487 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300488
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500489 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300490 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200491 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300492 gbm_surface_release_buffer(output->surface, bo);
493 return;
494 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400495}
496
497static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500498drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400499 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100500{
501 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500502 struct drm_compositor *compositor =
503 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500504 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400505 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500506 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100507
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300508 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400509 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300510 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400511 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100512
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400513 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300514 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300516 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400517 &output->connector_id, 1,
518 &mode->mode_info);
519 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200520 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400521 return;
522 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200523 }
524
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500525 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300526 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500527 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200528 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500529 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500530 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100531
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300532 output->page_flip_pending = 1;
533
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400534 drm_output_set_cursor(output);
535
Jesse Barnes58ef3792012-02-23 09:45:49 -0500536 /*
537 * Now, update all the sprite surfaces
538 */
539 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200540 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500541 drmVBlank vbl = {
542 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
543 .request.sequence = 1,
544 };
545
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200546 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200547 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500548 continue;
549
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200550 if (s->next && !compositor->sprites_hidden)
551 fb_id = s->next->fb_id;
552
Jesse Barnes58ef3792012-02-23 09:45:49 -0500553 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200554 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500555 s->dest_x, s->dest_y,
556 s->dest_w, s->dest_h,
557 s->src_x, s->src_y,
558 s->src_w, s->src_h);
559 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200560 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500561 ret, strerror(errno));
562
Rob Clark5ca1a472012-08-08 20:27:37 -0500563 if (output->pipe > 0)
564 vbl.request.type |= DRM_VBLANK_SECONDARY;
565
Jesse Barnes58ef3792012-02-23 09:45:49 -0500566 /*
567 * Queue a vblank signal so we know when the surface
568 * becomes active on the display or has been replaced.
569 */
570 vbl.request.signal = (unsigned long)s;
571 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
572 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200573 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574 ret, strerror(errno));
575 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300576
577 s->output = output;
578 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500579 }
580
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500581 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400582}
583
584static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500585vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
586 void *data)
587{
588 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300589 struct drm_output *output = s->output;
590 uint32_t msecs;
591
592 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500593
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200594 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200595 s->current = s->next;
596 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300597
598 if (!output->page_flip_pending) {
599 msecs = sec * 1000 + usec / 1000;
600 weston_output_finish_frame(&output->base, msecs);
601 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602}
603
604static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400605page_flip_handler(int fd, unsigned int frame,
606 unsigned int sec, unsigned int usec, void *data)
607{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200608 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400609 uint32_t msecs;
610
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300611 output->page_flip_pending = 0;
612
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200613 drm_output_release_fb(output, output->current);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300614 output->current = output->next;
615 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400616
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300617 if (!output->vblank_pending) {
618 msecs = sec * 1000 + usec / 1000;
619 weston_output_finish_frame(&output->base, msecs);
620 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200621}
622
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500623static uint32_t
624drm_output_check_sprite_format(struct drm_sprite *s,
625 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500627 uint32_t i, format;
628
629 format = gbm_bo_get_format(bo);
630
631 if (format == GBM_FORMAT_ARGB8888) {
632 pixman_region32_t r;
633
634 pixman_region32_init(&r);
635 pixman_region32_subtract(&r, &es->transform.boundingbox,
636 &es->transform.opaque);
637
638 if (!pixman_region32_not_empty(&r))
639 format = GBM_FORMAT_XRGB8888;
640
641 pixman_region32_fini(&r);
642 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643
644 for (i = 0; i < s->count_formats; i++)
645 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500646 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647
648 return 0;
649}
650
651static int
652drm_surface_transform_supported(struct weston_surface *es)
653{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400654 struct weston_matrix *matrix = &es->transform.matrix;
655 int i;
656
657 if (!es->transform.enabled)
658 return 1;
659
660 for (i = 0; i < 16; i++) {
661 switch (i) {
662 case 10:
663 case 15:
664 if (matrix->d[i] != 1.0)
665 return 0;
666 break;
667 case 0:
668 case 5:
669 case 12:
670 case 13:
671 break;
672 default:
673 if (matrix->d[i] != 0.0)
674 return 0;
675 break;
676 }
677 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500678
679 return 1;
680}
681
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400682static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500683drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400684 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500685{
686 struct weston_compositor *ec = output_base->compositor;
687 struct drm_compositor *c =(struct drm_compositor *) ec;
688 struct drm_sprite *s;
689 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500690 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500691 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200692 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500693 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400694 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500695
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200696 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200697 return NULL;
698
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500699 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400700 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500701
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300702 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400703 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300704
Pekka Paalanende685b82012-12-04 15:58:12 +0200705 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400706 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500707
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200708 if (es->alpha != 1.0f)
709 return NULL;
710
Pekka Paalanende685b82012-12-04 15:58:12 +0200711 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500712 return NULL;
713
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400715 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500716
Jesse Barnes58ef3792012-02-23 09:45:49 -0500717 wl_list_for_each(s, &c->sprite_list, link) {
718 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
719 continue;
720
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200721 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500722 found = 1;
723 break;
724 }
725 }
726
727 /* No sprites available */
728 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400729 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500730
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400731 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200732 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400733 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400734 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400735
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500736 format = drm_output_check_sprite_format(s, es, bo);
737 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200738 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400739 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500740 }
741
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200742 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200743 if (!s->next) {
744 gbm_bo_destroy(bo);
745 return NULL;
746 }
747
Pekka Paalanende685b82012-12-04 15:58:12 +0200748 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500749
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400750 box = pixman_region32_extents(&es->transform.boundingbox);
751 s->plane.x = box->x1;
752 s->plane.y = box->y1;
753
Jesse Barnes58ef3792012-02-23 09:45:49 -0500754 /*
755 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200756 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500757 * for us already).
758 */
759 pixman_region32_init(&dest_rect);
760 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
761 &output_base->region);
762 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
763 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200764 tbox = weston_transformed_rect(output_base->width,
765 output_base->height,
766 output_base->transform, *box);
767 s->dest_x = tbox.x1;
768 s->dest_y = tbox.y1;
769 s->dest_w = tbox.x2 - tbox.x1;
770 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771 pixman_region32_fini(&dest_rect);
772
773 pixman_region32_init(&src_rect);
774 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
775 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500776 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400777
778 weston_surface_from_global_fixed(es,
779 wl_fixed_from_int(box->x1),
780 wl_fixed_from_int(box->y1),
781 &sx1, &sy1);
782 weston_surface_from_global_fixed(es,
783 wl_fixed_from_int(box->x2),
784 wl_fixed_from_int(box->y2),
785 &sx2, &sy2);
786
787 if (sx1 < 0)
788 sx1 = 0;
789 if (sy1 < 0)
790 sy1 = 0;
791 if (sx2 > wl_fixed_from_int(es->geometry.width))
792 sx2 = wl_fixed_from_int(es->geometry.width);
793 if (sy2 > wl_fixed_from_int(es->geometry.height))
794 sy2 = wl_fixed_from_int(es->geometry.height);
795
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200796 tbox.x1 = sx1;
797 tbox.y1 = sy1;
798 tbox.x2 = sx2;
799 tbox.y2 = sy2;
800
801 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
802 wl_fixed_from_int(es->geometry.height),
803 es->buffer_transform, tbox);
804
805 s->src_x = tbox.x1 << 8;
806 s->src_y = tbox.y1 << 8;
807 s->src_w = (tbox.x2 - tbox.x1) << 8;
808 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809 pixman_region32_fini(&src_rect);
810
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400811 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812}
813
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400814static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400815drm_output_prepare_cursor_surface(struct weston_output *output_base,
816 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500817{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400818 struct drm_compositor *c =
819 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400820 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400821
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200822 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
823 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400824 if (output->cursor_surface)
825 return NULL;
826 if (es->output_mask != (1u << output_base->id))
827 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500828 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400829 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200830 if (es->buffer_ref.buffer == NULL ||
831 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400832 es->geometry.width > 64 || es->geometry.height > 64)
833 return NULL;
834
835 output->cursor_surface = es;
836
837 return &output->cursor_plane;
838}
839
840static void
841drm_output_set_cursor(struct drm_output *output)
842{
843 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400844 struct drm_compositor *c =
845 (struct drm_compositor *) output->base.compositor;
846 EGLint handle, stride;
847 struct gbm_bo *bo;
848 uint32_t buf[64 * 64];
849 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400850 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500851
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400852 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400853 if (es == NULL) {
854 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
855 return;
856 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500857
Pekka Paalanende685b82012-12-04 15:58:12 +0200858 if (es->buffer_ref.buffer &&
859 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400860 pixman_region32_fini(&output->cursor_plane.damage);
861 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400862 output->current_cursor ^= 1;
863 bo = output->cursor_bo[output->current_cursor];
864 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200865 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
866 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400867 for (i = 0; i < es->geometry.height; i++)
868 memcpy(buf + i * 64, s + i * stride,
869 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500870
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400871 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300872 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400873
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400874 handle = gbm_bo_get_handle(bo).s32;
875 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500876 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300877 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500878 c->cursors_are_broken = 1;
879 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400880 }
881
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400882 x = es->geometry.x - output->base.x;
883 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400884 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500885 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400886 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500887 c->cursors_are_broken = 1;
888 }
889
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400890 output->cursor_plane.x = x;
891 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400892 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500893}
894
Jesse Barnes58ef3792012-02-23 09:45:49 -0500895static void
896drm_assign_planes(struct weston_output *output)
897{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400898 struct drm_compositor *c =
899 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200900 struct drm_output *drm_output = (struct drm_output *) output;
901 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400902 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500903 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400904 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500905
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200906 /* Reset the opaque region of the planes */
907 pixman_region32_fini(&drm_output->cursor_plane.opaque);
908 pixman_region32_init(&drm_output->cursor_plane.opaque);
909 pixman_region32_fini(&drm_output->fb_plane.opaque);
910 pixman_region32_init(&drm_output->fb_plane.opaque);
911
912 wl_list_for_each (s, &c->sprite_list, link) {
913 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
914 continue;
915
916 pixman_region32_fini(&s->plane.opaque);
917 pixman_region32_init(&s->plane.opaque);
918 }
919
Jesse Barnes58ef3792012-02-23 09:45:49 -0500920 /*
921 * Find a surface for each sprite in the output using some heuristics:
922 * 1) size
923 * 2) frequency of update
924 * 3) opacity (though some hw might support alpha blending)
925 * 4) clipping (this can be fixed with color keys)
926 *
927 * The idea is to save on blitting since this should save power.
928 * If we can get a large video surface on the sprite for example,
929 * the main display surface may not need to update at all, and
930 * the client buffer can be used directly for the sprite surface
931 * as we do for flipping full screen surfaces.
932 */
933 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400934 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400935 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200936 /* test whether this buffer can ever go into a plane:
937 * non-shm, or small enough to be a cursor
938 */
939 if ((es->buffer_ref.buffer &&
940 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
941 (es->geometry.width <= 64 && es->geometry.height <= 64))
942 es->keep_buffer = 1;
943 else
944 es->keep_buffer = 0;
945
Jesse Barnes58ef3792012-02-23 09:45:49 -0500946 pixman_region32_init(&surface_overlap);
947 pixman_region32_intersect(&surface_overlap, &overlap,
948 &es->transform.boundingbox);
949
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400950 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400951 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400952 next_plane = primary;
953 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400954 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400955 if (next_plane == NULL)
956 next_plane = drm_output_prepare_scanout_surface(output, es);
957 if (next_plane == NULL)
958 next_plane = drm_output_prepare_overlay_surface(output, es);
959 if (next_plane == NULL)
960 next_plane = primary;
961 weston_surface_move_to_plane(es, next_plane);
962 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500963 pixman_region32_union(&overlap, &overlap,
964 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400965
Jesse Barnes58ef3792012-02-23 09:45:49 -0500966 pixman_region32_fini(&surface_overlap);
967 }
968 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500969}
970
Matt Roper361d2ad2011-08-29 13:52:23 -0700971static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500972drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700973{
974 struct drm_output *output = (struct drm_output *) output_base;
975 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200976 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700977 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700978
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200979 if (output->backlight)
980 backlight_destroy(output->backlight);
981
Matt Roper361d2ad2011-08-29 13:52:23 -0700982 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400983 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700984
985 /* Restore original CRTC state */
986 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200987 origcrtc->x, origcrtc->y,
988 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700989 drmModeFreeCrtc(origcrtc);
990
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200991 c->crtc_allocator &= ~(1 << output->crtc_id);
992 c->connector_allocator &= ~(1 << output->connector_id);
993
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100994 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100995
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400996 gbm_surface_destroy(output->surface);
997
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400998 weston_plane_release(&output->fb_plane);
999 weston_plane_release(&output->cursor_plane);
1000
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001001 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001002 wl_list_remove(&output->base.link);
1003
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001004 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001005 free(output);
1006}
1007
Alex Wub7b8bda2012-04-17 17:20:48 +08001008static struct drm_mode *
1009choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1010{
1011 struct drm_mode *tmp_mode = NULL, *mode;
1012
1013 if (output->base.current->width == target_mode->width &&
1014 output->base.current->height == target_mode->height &&
1015 (output->base.current->refresh == target_mode->refresh ||
1016 target_mode->refresh == 0))
1017 return (struct drm_mode *)output->base.current;
1018
1019 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1020 if (mode->mode_info.hdisplay == target_mode->width &&
1021 mode->mode_info.vdisplay == target_mode->height) {
1022 if (mode->mode_info.vrefresh == target_mode->refresh ||
1023 target_mode->refresh == 0) {
1024 return mode;
1025 } else if (!tmp_mode)
1026 tmp_mode = mode;
1027 }
1028 }
1029
1030 return tmp_mode;
1031}
1032
1033static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001034drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
1035
1036static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001037drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1038{
1039 struct drm_output *output;
1040 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001041 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001042
1043 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001044 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001045 return -1;
1046 }
1047
1048 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001049 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001050 return -1;
1051 }
1052
1053 ec = (struct drm_compositor *)output_base->compositor;
1054 output = (struct drm_output *)output_base;
1055 drm_mode = choose_mode (output, mode);
1056
1057 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001058 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001059 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001060 }
1061
1062 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001063 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001064
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001065 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001066
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001067 output->base.current = &drm_mode->base;
1068 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001069 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1070
Alex Wub7b8bda2012-04-17 17:20:48 +08001071 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001072 drm_output_release_fb(output, output->current);
1073 drm_output_release_fb(output, output->next);
1074 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001075
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001076 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +08001077 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001078
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001079 if (drm_output_init_egl(output, ec) < 0) {
1080 weston_log("failed to init output egl state with new mode");
1081 return -1;
1082 }
1083
Alex Wub7b8bda2012-04-17 17:20:48 +08001084 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001085}
1086
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001087static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001088on_drm_input(int fd, uint32_t mask, void *data)
1089{
1090 drmEventContext evctx;
1091
1092 memset(&evctx, 0, sizeof evctx);
1093 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1094 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001095 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001096 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001097
1098 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001099}
1100
1101static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001102init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001103{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001104 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001105 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001106
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001107 sysnum = udev_device_get_sysnum(device);
1108 if (sysnum)
1109 ec->drm.id = atoi(sysnum);
1110 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001111 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001112 return -1;
1113 }
1114
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001115 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001116 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001117 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001118 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001119 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001120 udev_device_get_devnode(device));
1121 return -1;
1122 }
1123
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001124 weston_log("using %s\n", filename);
1125
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001126 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001127
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001128
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001129 return 0;
1130}
1131
1132static int
1133init_egl(struct drm_compositor *ec)
1134{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001135 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001136
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001137 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001138 NULL) < 0) {
1139 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001140 return -1;
1141 }
1142
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001143 return 0;
1144}
1145
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001146static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001147drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1148{
1149 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001150 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001151
1152 mode = malloc(sizeof *mode);
1153 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001154 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001155
1156 mode->base.flags = 0;
1157 mode->base.width = info->hdisplay;
1158 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001159
1160 /* Calculate higher precision (mHz) refresh rate */
1161 refresh = (info->clock * 1000000LL / info->htotal +
1162 info->vtotal / 2) / info->vtotal;
1163
1164 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1165 refresh *= 2;
1166 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1167 refresh /= 2;
1168 if (info->vscan > 1)
1169 refresh /= info->vscan;
1170
1171 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001172 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001173
1174 if (info->type & DRM_MODE_TYPE_PREFERRED)
1175 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1176
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001177 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1178
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001179 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001180}
1181
1182static int
1183drm_subpixel_to_wayland(int drm_value)
1184{
1185 switch (drm_value) {
1186 default:
1187 case DRM_MODE_SUBPIXEL_UNKNOWN:
1188 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1189 case DRM_MODE_SUBPIXEL_NONE:
1190 return WL_OUTPUT_SUBPIXEL_NONE;
1191 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1192 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1193 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1194 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1195 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1196 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1197 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1198 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1199 }
1200}
1201
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001202/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001203static uint32_t
1204drm_get_backlight(struct drm_output *output)
1205{
1206 long brightness, max_brightness, norm;
1207
1208 brightness = backlight_get_brightness(output->backlight);
1209 max_brightness = backlight_get_max_brightness(output->backlight);
1210
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001211 /* convert it on a scale of 0 to 255 */
1212 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001213
1214 return (uint32_t) norm;
1215}
1216
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001217/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001218static void
1219drm_set_backlight(struct weston_output *output_base, uint32_t value)
1220{
1221 struct drm_output *output = (struct drm_output *) output_base;
1222 long max_brightness, new_brightness;
1223
1224 if (!output->backlight)
1225 return;
1226
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001227 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001228 return;
1229
1230 max_brightness = backlight_get_max_brightness(output->backlight);
1231
1232 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001233 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001234
1235 backlight_set_brightness(output->backlight, new_brightness);
1236}
1237
1238static drmModePropertyPtr
1239drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1240{
1241 drmModePropertyPtr props;
1242 int i;
1243
1244 for (i = 0; i < connector->count_props; i++) {
1245 props = drmModeGetProperty(fd, connector->props[i]);
1246 if (!props)
1247 continue;
1248
1249 if (!strcmp(props->name, name))
1250 return props;
1251
1252 drmModeFreeProperty(props);
1253 }
1254
1255 return NULL;
1256}
1257
1258static void
1259drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1260{
1261 struct drm_output *output = (struct drm_output *) output_base;
1262 struct weston_compositor *ec = output_base->compositor;
1263 struct drm_compositor *c = (struct drm_compositor *) ec;
1264 drmModeConnectorPtr connector;
1265 drmModePropertyPtr prop;
1266
1267 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1268 if (!connector)
1269 return;
1270
1271 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1272 if (!prop) {
1273 drmModeFreeConnector(connector);
1274 return;
1275 }
1276
1277 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1278 prop->prop_id, level);
1279 drmModeFreeProperty(prop);
1280 drmModeFreeConnector(connector);
1281}
1282
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001283static const char *connector_type_names[] = {
1284 "None",
1285 "VGA",
1286 "DVI",
1287 "DVI",
1288 "DVI",
1289 "Composite",
1290 "TV",
1291 "LVDS",
1292 "CTV",
1293 "DIN",
1294 "DP",
1295 "HDMI",
1296 "HDMI",
1297 "TV",
1298 "eDP",
1299};
1300
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001301static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001302find_crtc_for_connector(struct drm_compositor *ec,
1303 drmModeRes *resources, drmModeConnector *connector)
1304{
1305 drmModeEncoder *encoder;
1306 uint32_t possible_crtcs;
1307 int i, j;
1308
1309 for (j = 0; j < connector->count_encoders; j++) {
1310 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1311 if (encoder == NULL) {
1312 weston_log("Failed to get encoder.\n");
1313 return -1;
1314 }
1315 possible_crtcs = encoder->possible_crtcs;
1316 drmModeFreeEncoder(encoder);
1317
1318 for (i = 0; i < resources->count_crtcs; i++) {
1319 if (possible_crtcs & (1 << i) &&
1320 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1321 return i;
1322 }
1323 }
1324
1325 return -1;
1326}
1327
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001328/* Init output state that depends on gl or gbm */
1329static int
1330drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1331{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001332 int i, flags;
1333
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001334 output->surface = gbm_surface_create(ec->gbm,
1335 output->base.current->width,
1336 output->base.current->height,
1337 GBM_FORMAT_XRGB8888,
1338 GBM_BO_USE_SCANOUT |
1339 GBM_BO_USE_RENDERING);
1340 if (!output->surface) {
1341 weston_log("failed to create gbm surface\n");
1342 return -1;
1343 }
1344
1345 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001346 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001347 gbm_surface_destroy(output->surface);
1348 return -1;
1349 }
1350
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001351 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1352
1353 for (i = 0; i < 2; i++) {
1354 if (output->cursor_bo[i])
1355 continue;
1356
1357 output->cursor_bo[i] =
1358 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1359 flags);
1360 }
1361
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001362 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1363 weston_log("cursor buffers unavailable, using gl cursors\n");
1364 ec->cursors_are_broken = 1;
1365 }
1366
1367 return 0;
1368}
1369
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001370static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001371create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001372 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001373 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001374 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001375{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001376 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001377 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1378 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001379 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001380 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001381 drmModeModeInfo crtc_mode;
1382 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001383 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001384 char name[32];
1385 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001386
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001387 i = find_crtc_for_connector(ec, resources, connector);
1388 if (i < 0) {
1389 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001390 return -1;
1391 }
1392
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001393 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001394 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001395 return -1;
1396
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001397 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001398 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1399 output->base.make = "unknown";
1400 output->base.model = "unknown";
1401 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001402
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001403 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1404 type_name = connector_type_names[connector->connector_type];
1405 else
1406 type_name = "UNKNOWN";
1407 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1408 output->name = strdup(name);
1409
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001410 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001411 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001412 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001413 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001414 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001415
Matt Roper361d2ad2011-08-29 13:52:23 -07001416 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1417
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001418 /* Get the current mode on the crtc that's currently driving
1419 * this connector. */
1420 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001421 memset(&crtc_mode, 0, sizeof crtc_mode);
1422 if (encoder != NULL) {
1423 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1424 drmModeFreeEncoder(encoder);
1425 if (crtc == NULL)
1426 goto err_free;
1427 if (crtc->mode_valid)
1428 crtc_mode = crtc->mode;
1429 drmModeFreeCrtc(crtc);
1430 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001431
David Herrmann0f0d54e2011-12-08 17:05:45 +01001432 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001433 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1434 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001435 goto err_free;
1436 }
1437
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001438 preferred = NULL;
1439 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001440 configured = NULL;
1441
1442 wl_list_for_each(temp, &configured_output_list, link) {
1443 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001444 if (temp->mode)
1445 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001446 temp->name, temp->mode);
1447 o = temp;
1448 break;
1449 }
1450 }
1451
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001452 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001453 weston_log("Disabling output %s\n", o->name);
1454
1455 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1456 0, 0, 0, 0, 0, NULL);
1457 goto err_free;
1458 }
1459
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001460 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001461 if (o && o->config == OUTPUT_CONFIG_MODE &&
1462 o->width == drm_mode->base.width &&
1463 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001464 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001465 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001466 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001467 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001468 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001469 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001470
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001471 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001472 configured = drm_output_add_mode(output, &o->crtc_mode);
1473 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001474 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001475 current = configured;
1476 }
1477
Wang Quanxianacb805a2012-07-30 18:09:46 -04001478 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001479 current = drm_output_add_mode(output, &crtc_mode);
1480 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001481 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001482 }
1483
Scott Moreau8ab5d452012-07-30 19:51:08 -06001484 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1485 configured = current;
1486
Wang Quanxianacb805a2012-07-30 18:09:46 -04001487 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001488 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001489 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001490 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001491 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001492 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001493 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001494 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001495
1496 if (output->base.current == NULL) {
1497 weston_log("no available modes for %s\n", output->name);
1498 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001499 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001500
Wang Quanxianacb805a2012-07-30 18:09:46 -04001501 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1502
John Kåre Alsaker94659272012-11-13 19:10:18 +01001503 weston_output_init(&output->base, &ec->base, x, y,
1504 connector->mmWidth, connector->mmHeight,
1505 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1506
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001507 if (drm_output_init_egl(output, ec) < 0) {
1508 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001509 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001510 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001511
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001512 output->backlight = backlight_init(drm_device,
1513 connector->connector_type);
1514 if (output->backlight) {
1515 output->base.set_backlight = drm_set_backlight;
1516 output->base.backlight_current = drm_get_backlight(output);
1517 }
1518
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001519 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1520
Alex Wubd3354b2012-04-17 17:20:49 +08001521 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001522 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001523 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001524 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001525 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001526 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001527
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001528 weston_plane_init(&output->cursor_plane, 0, 0);
1529 weston_plane_init(&output->fb_plane, 0, 0);
1530
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001531 weston_log("Output %s, (connector %d, crtc %d)\n",
1532 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001533 wl_list_for_each(m, &output->base.mode_list, link)
1534 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1535 m->width, m->height, m->refresh / 1000.0,
1536 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1537 ", preferred" : "",
1538 m->flags & WL_OUTPUT_MODE_CURRENT ?
1539 ", current" : "",
1540 connector->count_modes == 0 ?
1541 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001542
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001543 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001544
John Kåre Alsaker94659272012-11-13 19:10:18 +01001545err_output:
1546 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001547err_free:
1548 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1549 base.link) {
1550 wl_list_remove(&drm_mode->base.link);
1551 free(drm_mode);
1552 }
1553
1554 drmModeFreeCrtc(output->original_crtc);
1555 ec->crtc_allocator &= ~(1 << output->crtc_id);
1556 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001557 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001558 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001559
David Herrmann0f0d54e2011-12-08 17:05:45 +01001560 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001561}
1562
Jesse Barnes58ef3792012-02-23 09:45:49 -05001563static void
1564create_sprites(struct drm_compositor *ec)
1565{
1566 struct drm_sprite *sprite;
1567 drmModePlaneRes *plane_res;
1568 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001569 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001570
1571 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1572 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001573 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001574 strerror(errno));
1575 return;
1576 }
1577
1578 for (i = 0; i < plane_res->count_planes; i++) {
1579 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1580 if (!plane)
1581 continue;
1582
1583 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1584 plane->count_formats));
1585 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001586 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001587 __func__);
1588 free(plane);
1589 continue;
1590 }
1591
1592 memset(sprite, 0, sizeof *sprite);
1593
1594 sprite->possible_crtcs = plane->possible_crtcs;
1595 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001596 sprite->current = NULL;
1597 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001598 sprite->compositor = ec;
1599 sprite->count_formats = plane->count_formats;
1600 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001601 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001602 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001603 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001604
1605 wl_list_insert(&ec->sprite_list, &sprite->link);
1606 }
1607
1608 free(plane_res->planes);
1609 free(plane_res);
1610}
1611
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001612static void
1613destroy_sprites(struct drm_compositor *compositor)
1614{
1615 struct drm_sprite *sprite, *next;
1616 struct drm_output *output;
1617
1618 output = container_of(compositor->base.output_list.next,
1619 struct drm_output, base.link);
1620
1621 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1622 drmModeSetPlane(compositor->drm.fd,
1623 sprite->plane_id,
1624 output->crtc_id, 0, 0,
1625 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001626 drm_output_release_fb(output, sprite->current);
1627 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001628 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001629 free(sprite);
1630 }
1631}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001632
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001633static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001634create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001635 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001636{
1637 drmModeConnector *connector;
1638 drmModeRes *resources;
1639 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001640 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001641
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001642 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001643 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001644 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001645 return -1;
1646 }
1647
Jesse Barnes58ef3792012-02-23 09:45:49 -05001648 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001649 if (!ec->crtcs) {
1650 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001651 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001652 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001653
Rob Clark4339add2012-08-09 14:18:28 -05001654 ec->min_width = resources->min_width;
1655 ec->max_width = resources->max_width;
1656 ec->min_height = resources->min_height;
1657 ec->max_height = resources->max_height;
1658
Jesse Barnes58ef3792012-02-23 09:45:49 -05001659 ec->num_crtcs = resources->count_crtcs;
1660 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1661
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001662 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001663 connector = drmModeGetConnector(ec->drm.fd,
1664 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001665 if (connector == NULL)
1666 continue;
1667
1668 if (connector->connection == DRM_MODE_CONNECTED &&
1669 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001670 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001671 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001672 connector, x, y,
1673 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001674 drmModeFreeConnector(connector);
1675 continue;
1676 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001677
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001678 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001679 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001680 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001681 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001682
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001683 drmModeFreeConnector(connector);
1684 }
1685
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001686 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001687 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001688 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001689 return -1;
1690 }
1691
1692 drmModeFreeResources(resources);
1693
1694 return 0;
1695}
1696
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001697static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001698update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001699{
1700 drmModeConnector *connector;
1701 drmModeRes *resources;
1702 struct drm_output *output, *next;
1703 int x = 0, y = 0;
1704 int x_offset = 0, y_offset = 0;
1705 uint32_t connected = 0, disconnects = 0;
1706 int i;
1707
1708 resources = drmModeGetResources(ec->drm.fd);
1709 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001710 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001711 return;
1712 }
1713
1714 /* collect new connects */
1715 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001716 int connector_id = resources->connectors[i];
1717
1718 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001719 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001720 continue;
1721
David Herrmann7551cff2011-12-08 17:05:43 +01001722 if (connector->connection != DRM_MODE_CONNECTED) {
1723 drmModeFreeConnector(connector);
1724 continue;
1725 }
1726
Benjamin Franzke117483d2011-08-30 11:38:26 +02001727 connected |= (1 << connector_id);
1728
1729 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001730 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001731 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001732 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001733
1734 /* XXX: not yet needed, we die with 0 outputs */
1735 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001736 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001737 else
1738 x = 0;
1739 y = 0;
1740 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001741 connector, x, y,
1742 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001743 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001744
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001745 }
1746 drmModeFreeConnector(connector);
1747 }
1748 drmModeFreeResources(resources);
1749
1750 disconnects = ec->connector_allocator & ~connected;
1751 if (disconnects) {
1752 wl_list_for_each_safe(output, next, &ec->base.output_list,
1753 base.link) {
1754 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001755 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001756 output->base.x - x_offset,
1757 output->base.y - y_offset);
1758 }
1759
1760 if (disconnects & (1 << output->connector_id)) {
1761 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001762 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001763 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001764 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001765 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001766 }
1767 }
1768 }
1769
1770 /* FIXME: handle zero outputs, without terminating */
1771 if (ec->connector_allocator == 0)
1772 wl_display_terminate(ec->base.wl_display);
1773}
1774
1775static int
David Herrmannd7488c22012-03-11 20:05:21 +01001776udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001777{
David Herrmannd7488c22012-03-11 20:05:21 +01001778 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001779 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001780
1781 sysnum = udev_device_get_sysnum(device);
1782 if (!sysnum || atoi(sysnum) != ec->drm.id)
1783 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001784
David Herrmann6ac52db2012-03-11 20:05:22 +01001785 val = udev_device_get_property_value(device, "HOTPLUG");
1786 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001787 return 0;
1788
David Herrmann6ac52db2012-03-11 20:05:22 +01001789 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001790}
1791
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001792static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001793udev_drm_event(int fd, uint32_t mask, void *data)
1794{
1795 struct drm_compositor *ec = data;
1796 struct udev_device *event;
1797
1798 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001799
David Herrmannd7488c22012-03-11 20:05:21 +01001800 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001801 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001802
1803 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001804
1805 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001806}
1807
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001808static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001809drm_restore(struct weston_compositor *ec)
1810{
1811 struct drm_compositor *d = (struct drm_compositor *) ec;
1812
1813 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1814 weston_log("failed to drop master: %m\n");
1815 tty_reset(d->tty);
1816}
1817
Pekka Paalanen33156972012-08-03 13:30:30 -04001818static const char default_seat[] = "seat0";
1819
1820static void
1821device_added(struct udev_device *udev_device, struct drm_seat *master)
1822{
1823 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001824 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001825 const char *devnode;
1826 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001827 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001828 int fd;
1829
1830 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1831 if (!device_seat)
1832 device_seat = default_seat;
1833
1834 if (strcmp(device_seat, master->seat_id))
1835 return;
1836
1837 c = master->base.compositor;
1838 devnode = udev_device_get_devnode(udev_device);
1839
1840 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001841 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001842 * read. mtdev_get() also expects this. */
1843 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1844 if (fd < 0) {
1845 weston_log("opening input device '%s' failed.\n", devnode);
1846 return;
1847 }
1848
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001849 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001850 if (!device) {
1851 close(fd);
1852 weston_log("not using input device '%s'.\n", devnode);
1853 return;
1854 }
1855
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001856 calibration_values =
1857 udev_device_get_property_value(udev_device,
1858 "WL_CALIBRATION");
1859
1860 if (calibration_values && sscanf(calibration_values,
1861 "%f %f %f %f %f %f",
1862 &device->abs.calibration[0],
1863 &device->abs.calibration[1],
1864 &device->abs.calibration[2],
1865 &device->abs.calibration[3],
1866 &device->abs.calibration[4],
1867 &device->abs.calibration[5]) == 6) {
1868 device->abs.apply_calibration = 1;
1869 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1870 device->abs.calibration[0],
1871 device->abs.calibration[1],
1872 device->abs.calibration[2],
1873 device->abs.calibration[3],
1874 device->abs.calibration[4],
1875 device->abs.calibration[5]);
1876 }
1877
Pekka Paalanen33156972012-08-03 13:30:30 -04001878 wl_list_insert(master->devices_list.prev, &device->link);
1879}
1880
1881static void
1882evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1883{
1884 struct drm_seat *seat = (struct drm_seat *) seat_base;
1885 struct udev_enumerate *e;
1886 struct udev_list_entry *entry;
1887 struct udev_device *device;
1888 const char *path, *sysname;
1889
1890 e = udev_enumerate_new(udev);
1891 udev_enumerate_add_match_subsystem(e, "input");
1892 udev_enumerate_scan_devices(e);
1893 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1894 path = udev_list_entry_get_name(entry);
1895 device = udev_device_new_from_syspath(udev, path);
1896
1897 sysname = udev_device_get_sysname(device);
1898 if (strncmp("event", sysname, 5) != 0) {
1899 udev_device_unref(device);
1900 continue;
1901 }
1902
1903 device_added(device, seat);
1904
1905 udev_device_unref(device);
1906 }
1907 udev_enumerate_unref(e);
1908
1909 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1910
1911 if (wl_list_empty(&seat->devices_list)) {
1912 weston_log(
1913 "warning: no input devices on entering Weston. "
1914 "Possible causes:\n"
1915 "\t- no permissions to read /dev/input/event*\n"
1916 "\t- seats misconfigured "
1917 "(Weston backend option 'seat', "
1918 "udev device property ID_SEAT)\n");
1919 }
1920}
1921
1922static int
1923evdev_udev_handler(int fd, uint32_t mask, void *data)
1924{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001925 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001926 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001927 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001928 const char *action;
1929 const char *devnode;
1930
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001931 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001932 if (!udev_device)
1933 return 1;
1934
1935 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001936 if (!action)
1937 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001938
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001939 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1940 goto out;
1941
1942 if (!strcmp(action, "add")) {
1943 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001944 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001945 else if (!strcmp(action, "remove")) {
1946 devnode = udev_device_get_devnode(udev_device);
1947 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1948 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001949 weston_log("input device %s, %s removed\n",
1950 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001951 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001952 break;
1953 }
1954 }
1955
1956out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001957 udev_device_unref(udev_device);
1958
1959 return 0;
1960}
1961
1962static int
1963evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1964{
1965 struct drm_seat *master = (struct drm_seat *) seat_base;
1966 struct wl_event_loop *loop;
1967 struct weston_compositor *c = master->base.compositor;
1968 int fd;
1969
1970 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1971 if (!master->udev_monitor) {
1972 weston_log("udev: failed to create the udev monitor\n");
1973 return 0;
1974 }
1975
1976 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1977 "input", NULL);
1978
1979 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1980 weston_log("udev: failed to bind the udev monitor\n");
1981 udev_monitor_unref(master->udev_monitor);
1982 return 0;
1983 }
1984
1985 loop = wl_display_get_event_loop(c->wl_display);
1986 fd = udev_monitor_get_fd(master->udev_monitor);
1987 master->udev_monitor_source =
1988 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1989 evdev_udev_handler, master);
1990 if (!master->udev_monitor_source) {
1991 udev_monitor_unref(master->udev_monitor);
1992 return 0;
1993 }
1994
1995 return 1;
1996}
1997
1998static void
1999evdev_disable_udev_monitor(struct weston_seat *seat_base)
2000{
2001 struct drm_seat *seat = (struct drm_seat *) seat_base;
2002
2003 if (!seat->udev_monitor)
2004 return;
2005
2006 udev_monitor_unref(seat->udev_monitor);
2007 seat->udev_monitor = NULL;
2008 wl_event_source_remove(seat->udev_monitor_source);
2009 seat->udev_monitor_source = NULL;
2010}
2011
2012static void
2013drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
2014{
2015 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002016 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002017
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002018 wl_list_for_each(device, &seat->devices_list, link)
2019 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002020}
2021
2022static void
2023evdev_input_create(struct weston_compositor *c, struct udev *udev,
2024 const char *seat_id)
2025{
2026 struct drm_seat *seat;
2027
2028 seat = malloc(sizeof *seat);
2029 if (seat == NULL)
2030 return;
2031
2032 memset(seat, 0, sizeof *seat);
2033 weston_seat_init(&seat->base, c);
2034 seat->base.led_update = drm_led_update;
2035
2036 wl_list_init(&seat->devices_list);
2037 seat->seat_id = strdup(seat_id);
2038 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2039 free(seat->seat_id);
2040 free(seat);
2041 return;
2042 }
2043
2044 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002045}
2046
2047static void
2048evdev_remove_devices(struct weston_seat *seat_base)
2049{
2050 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002051 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002052
2053 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002054 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002055
Pekka Paalanend8583512012-08-03 14:39:11 +03002056 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002057 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002058}
2059
2060static void
2061evdev_input_destroy(struct weston_seat *seat_base)
2062{
2063 struct drm_seat *seat = (struct drm_seat *) seat_base;
2064
2065 evdev_remove_devices(seat_base);
2066 evdev_disable_udev_monitor(&seat->base);
2067
2068 weston_seat_release(seat_base);
2069 free(seat->seat_id);
2070 free(seat);
2071}
2072
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002073static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002074drm_free_configured_output(struct drm_configured_output *output)
2075{
2076 free(output->name);
2077 free(output->mode);
2078 free(output);
2079}
2080
2081static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002082drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002083{
2084 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002085 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002086 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002087
Daniel Stone37816df2012-05-16 18:45:18 +01002088 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2089 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002090 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002091 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002092
2093 wl_event_source_remove(d->udev_drm_source);
2094 wl_event_source_remove(d->drm_source);
2095
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002096 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002097
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002098 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002099
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002100 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002101 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002102 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002103 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002104 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002105
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002106 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002107}
2108
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002109static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002110drm_compositor_set_modes(struct drm_compositor *compositor)
2111{
2112 struct drm_output *output;
2113 struct drm_mode *drm_mode;
2114 int ret;
2115
2116 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2117 drm_mode = (struct drm_mode *) output->base.current;
2118 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002119 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002120 &output->connector_id, 1,
2121 &drm_mode->mode_info);
2122 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002123 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002124 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002125 drm_mode->base.width, drm_mode->base.height,
2126 output->base.x, output->base.y);
2127 }
2128 }
2129}
2130
2131static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002132vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002133{
2134 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002135 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002136 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002137 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002138
2139 switch (event) {
2140 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002141 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002142 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002143 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002144 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002145 wl_display_terminate(compositor->wl_display);
2146 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002147 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002148 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002149 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002150 wl_list_for_each(seat, &compositor->seat_list, link) {
2151 evdev_add_devices(ec->udev, seat);
2152 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002153 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002154 break;
2155 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002156 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002157 wl_list_for_each(seat, &compositor->seat_list, link) {
2158 evdev_disable_udev_monitor(seat);
2159 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002160 }
2161
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002162 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002163 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002164 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002165
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002166 /* If we have a repaint scheduled (either from a
2167 * pending pageflip or the idle handler), make sure we
2168 * cancel that so we don't try to pageflip when we're
2169 * vt switched away. The SLEEPING state will prevent
2170 * further attemps at repainting. When we switch
2171 * back, we schedule a repaint, which will process
2172 * pending frame callbacks. */
2173
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002174 wl_list_for_each(output, &ec->base.output_list, base.link) {
2175 output->base.repaint_needed = 0;
2176 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002177 }
2178
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002179 output = container_of(ec->base.output_list.next,
2180 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002181
2182 wl_list_for_each(sprite, &ec->sprite_list, link)
2183 drmModeSetPlane(ec->drm.fd,
2184 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002185 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002186 0, 0, 0, 0, 0, 0, 0, 0);
2187
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002188 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002189 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002190
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002191 break;
2192 };
2193}
2194
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002195static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002196switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002197{
2198 struct drm_compositor *ec = data;
2199
Daniel Stone325fc2d2012-05-30 16:31:58 +01002200 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002201}
2202
David Herrmann0af066f2012-10-29 19:21:16 +01002203/*
2204 * Find primary GPU
2205 * Some systems may have multiple DRM devices attached to a single seat. This
2206 * function loops over all devices and tries to find a PCI device with the
2207 * boot_vga sysfs attribute set to 1.
2208 * If no such device is found, the first DRM device reported by udev is used.
2209 */
2210static struct udev_device*
2211find_primary_gpu(struct drm_compositor *ec, const char *seat)
2212{
2213 struct udev_enumerate *e;
2214 struct udev_list_entry *entry;
2215 const char *path, *device_seat, *id;
2216 struct udev_device *device, *drm_device, *pci;
2217
2218 e = udev_enumerate_new(ec->udev);
2219 udev_enumerate_add_match_subsystem(e, "drm");
2220 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2221
2222 udev_enumerate_scan_devices(e);
2223 drm_device = NULL;
2224 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2225 path = udev_list_entry_get_name(entry);
2226 device = udev_device_new_from_syspath(ec->udev, path);
2227 if (!device)
2228 continue;
2229 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2230 if (!device_seat)
2231 device_seat = default_seat;
2232 if (strcmp(device_seat, seat)) {
2233 udev_device_unref(device);
2234 continue;
2235 }
2236
2237 pci = udev_device_get_parent_with_subsystem_devtype(device,
2238 "pci", NULL);
2239 if (pci) {
2240 id = udev_device_get_sysattr_value(pci, "boot_vga");
2241 if (id && !strcmp(id, "1")) {
2242 if (drm_device)
2243 udev_device_unref(drm_device);
2244 drm_device = device;
2245 break;
2246 }
2247 }
2248
2249 if (!drm_device)
2250 drm_device = device;
2251 else
2252 udev_device_unref(device);
2253 }
2254
2255 udev_enumerate_unref(e);
2256 return drm_device;
2257}
2258
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002259static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002260planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002261{
2262 struct drm_compositor *c = data;
2263
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002264 switch (key) {
2265 case KEY_C:
2266 c->cursors_are_broken ^= 1;
2267 break;
2268 case KEY_V:
2269 c->sprites_are_broken ^= 1;
2270 break;
2271 case KEY_O:
2272 c->sprites_hidden ^= 1;
2273 break;
2274 default:
2275 break;
2276 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002277}
2278
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002279static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002280drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002281 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002282 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002283{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002284 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002285 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002286 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002287 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002288 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002289 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002290
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002291 weston_log("initializing drm backend\n");
2292
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002293 ec = malloc(sizeof *ec);
2294 if (ec == NULL)
2295 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002296 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002297
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002298 /* KMS support for sprites is not complete yet, so disable the
2299 * functionality for now. */
2300 ec->sprites_are_broken = 1;
2301
Daniel Stone725c2c32012-06-22 14:04:36 +01002302 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002303 config_file) < 0) {
2304 weston_log("weston_compositor_init failed\n");
2305 goto err_base;
2306 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002307
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002308 ec->udev = udev_new();
2309 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002310 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002311 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002312 }
2313
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002314 ec->base.wl_display = display;
2315 ec->tty = tty_create(&ec->base, vt_func, tty);
2316 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002317 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002318 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002319 }
2320
David Herrmann0af066f2012-10-29 19:21:16 +01002321 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002322 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002323 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002324 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002325 }
David Herrmann0af066f2012-10-29 19:21:16 +01002326 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002327
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002328 if (init_drm(ec, drm_device) < 0) {
2329 weston_log("failed to initialize kms\n");
2330 goto err_udev_dev;
2331 }
2332
2333 if (init_egl(ec) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002334 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002335 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002336 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002337
2338 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002339 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002340
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002341 ec->base.focus = 1;
2342
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002343 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002344
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002345 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002346 weston_compositor_add_key_binding(&ec->base, key,
2347 MODIFIER_CTRL | MODIFIER_ALT,
2348 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002349
Jesse Barnes58ef3792012-02-23 09:45:49 -05002350 wl_list_init(&ec->sprite_list);
2351 create_sprites(ec);
2352
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002353 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002354 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002355 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002356 }
2357
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002358 path = NULL;
2359
Tiago Vignattice03ec32011-12-19 01:14:03 +02002360 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002361
2362 loop = wl_display_get_event_loop(ec->base.wl_display);
2363 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002364 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002365 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002366
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002367 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2368 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002369 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002370 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002371 }
2372 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2373 "drm", NULL);
2374 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002375 wl_event_loop_add_fd(loop,
2376 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002377 WL_EVENT_READABLE, udev_drm_event, ec);
2378
2379 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002380 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002381 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002382 }
2383
Daniel Stonea96b93c2012-06-22 14:04:37 +01002384 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002385
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002386 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002387 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002388 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002389 planes_binding, ec);
2390 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2391 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002392
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002393 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002394
2395err_udev_monitor:
2396 wl_event_source_remove(ec->udev_drm_source);
2397 udev_monitor_unref(ec->udev_monitor);
2398err_drm_source:
2399 wl_event_source_remove(ec->drm_source);
2400 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2401 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002402err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002403 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002404 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002405 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002406err_udev_dev:
2407 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002408err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002409 tty_destroy(ec->tty);
2410err_udev:
2411 udev_unref(ec->udev);
2412err_compositor:
2413 weston_compositor_shutdown(&ec->base);
2414err_base:
2415 free(ec);
2416 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002417}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002418
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002419static int
2420set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2421{
2422 mode->flags = 0;
2423
2424 if (strcmp(hsync, "+hsync") == 0)
2425 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2426 else if (strcmp(hsync, "-hsync") == 0)
2427 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2428 else
2429 return -1;
2430
2431 if (strcmp(vsync, "+vsync") == 0)
2432 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2433 else if (strcmp(vsync, "-vsync") == 0)
2434 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2435 else
2436 return -1;
2437
2438 return 0;
2439}
2440
2441static int
2442check_for_modeline(struct drm_configured_output *output)
2443{
2444 drmModeModeInfo mode;
2445 char hsync[16];
2446 char vsync[16];
2447 char mode_name[16];
2448 float fclock;
2449
2450 mode.type = DRM_MODE_TYPE_USERDEF;
2451 mode.hskew = 0;
2452 mode.vscan = 0;
2453 mode.vrefresh = 0;
2454
2455 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2456 &fclock, &mode.hdisplay,
2457 &mode.hsync_start,
2458 &mode.hsync_end, &mode.htotal,
2459 &mode.vdisplay,
2460 &mode.vsync_start,
2461 &mode.vsync_end, &mode.vtotal,
2462 hsync, vsync) == 11) {
2463 if (set_sync_flags(&mode, hsync, vsync))
2464 return -1;
2465
2466 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2467 strcpy(mode.name, mode_name);
2468
2469 mode.clock = fclock * 1000;
2470 } else
2471 return -1;
2472
2473 output->crtc_mode = mode;
2474
2475 return 0;
2476}
2477
Scott Moreau8ab5d452012-07-30 19:51:08 -06002478static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002479drm_output_set_transform(struct drm_configured_output *output)
2480{
2481 if (!output_transform) {
2482 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2483 return;
2484 }
2485
2486 if (!strcmp(output_transform, "normal"))
2487 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2488 else if (!strcmp(output_transform, "90"))
2489 output->transform = WL_OUTPUT_TRANSFORM_90;
2490 else if (!strcmp(output_transform, "180"))
2491 output->transform = WL_OUTPUT_TRANSFORM_180;
2492 else if (!strcmp(output_transform, "270"))
2493 output->transform = WL_OUTPUT_TRANSFORM_270;
2494 else if (!strcmp(output_transform, "flipped"))
2495 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2496 else if (!strcmp(output_transform, "flipped-90"))
2497 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2498 else if (!strcmp(output_transform, "flipped-180"))
2499 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2500 else if (!strcmp(output_transform, "flipped-270"))
2501 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2502 else {
2503 weston_log("Invalid transform \"%s\" for output %s\n",
2504 output_transform, output_name);
2505 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2506 }
2507
2508 free(output_transform);
2509 output_transform = NULL;
2510}
2511
2512static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002513output_section_done(void *data)
2514{
2515 struct drm_configured_output *output;
2516
2517 output = malloc(sizeof *output);
2518
Scott Moreau1bad5db2012-08-18 01:04:05 -06002519 if (!output || !output_name || (output_name[0] == 'X') ||
2520 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002521 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002522 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002523 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002524 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002525 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002526 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002527 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002528 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002529 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002530
2531 output->config = OUTPUT_CONFIG_INVALID;
2532 output->name = output_name;
2533 output->mode = output_mode;
2534
Scott Moreau1bad5db2012-08-18 01:04:05 -06002535 if (output_mode) {
2536 if (strcmp(output_mode, "off") == 0)
2537 output->config = OUTPUT_CONFIG_OFF;
2538 else if (strcmp(output_mode, "preferred") == 0)
2539 output->config = OUTPUT_CONFIG_PREFERRED;
2540 else if (strcmp(output_mode, "current") == 0)
2541 output->config = OUTPUT_CONFIG_CURRENT;
2542 else if (sscanf(output_mode, "%dx%d",
2543 &output->width, &output->height) == 2)
2544 output->config = OUTPUT_CONFIG_MODE;
2545 else if (check_for_modeline(output) == 0)
2546 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002547
Scott Moreau1bad5db2012-08-18 01:04:05 -06002548 if (output->config == OUTPUT_CONFIG_INVALID)
2549 weston_log("Invalid mode \"%s\" for output %s\n",
2550 output_mode, output_name);
2551 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002552 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002553
2554 drm_output_set_transform(output);
2555
2556 wl_list_insert(&configured_output_list, &output->link);
2557
2558 if (output_transform)
2559 free(output_transform);
2560 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002561}
2562
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002563WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002564backend_init(struct wl_display *display, int argc, char *argv[],
2565 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002566{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002567 int connector = 0, tty = 0;
2568 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002569
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002570 const struct weston_option drm_options[] = {
2571 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2572 { WESTON_OPTION_STRING, "seat", 0, &seat },
2573 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002574 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002575 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002576
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002577 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002578
Scott Moreau8ab5d452012-07-30 19:51:08 -06002579 wl_list_init(&configured_output_list);
2580
2581 const struct config_key drm_config_keys[] = {
2582 { "name", CONFIG_KEY_STRING, &output_name },
2583 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002584 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002585 };
2586
2587 const struct config_section config_section[] = {
2588 { "output", drm_config_keys,
2589 ARRAY_LENGTH(drm_config_keys), output_section_done },
2590 };
2591
2592 parse_config_file(config_file, config_section,
2593 ARRAY_LENGTH(config_section), NULL);
2594
Daniel Stonec1be8e52012-06-01 11:14:02 -04002595 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2596 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002597}