blob: 37e825316eab11d646fa43a5869504e05b7861e8 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020033#include <sys/mman.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040034
Benjamin Franzkec649a922011-03-02 11:56:04 +010035#include <xf86drm.h>
36#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050037#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010038
Benjamin Franzke060cf802011-04-30 09:32:11 +020039#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020040#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040041#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020042
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040043#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010044#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020045#include "pixman-renderer.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020046#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010047#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040048
Kristian Høgsberg061c4252012-06-28 11:28:15 -040049static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060050static char *output_name;
51static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060052static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060053static struct wl_list configured_output_list;
54
55enum output_config {
56 OUTPUT_CONFIG_INVALID = 0,
57 OUTPUT_CONFIG_OFF,
58 OUTPUT_CONFIG_PREFERRED,
59 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060060 OUTPUT_CONFIG_MODE,
61 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060062};
63
64struct drm_configured_output {
65 char *name;
66 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060067 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060068 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060069 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060070 enum output_config config;
71 struct wl_list link;
72};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040073
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050075 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
77 struct udev *udev;
78 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040079
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010080 struct udev_monitor *udev_monitor;
81 struct wl_event_source *udev_drm_source;
82
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010084 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010085 int fd;
86 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020087 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050088 uint32_t *crtcs;
89 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050090 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010091 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050092 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020093
Rob Clark4339add2012-08-09 14:18:28 -050094 /* we need these parameters in order to not fail drmModeAddFB2()
95 * due to out of bounds dimensions, and then mistakenly set
96 * sprites_are_broken:
97 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020098 uint32_t min_width, max_width;
99 uint32_t min_height, max_height;
100 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500101
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500103 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200104 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500105
Rob Clarkab5b1e32012-08-09 13:24:45 -0500106 int cursors_are_broken;
107
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200108 int use_pixman;
109
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200110 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400111};
112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400115 drmModeModeInfo mode_info;
116};
117
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118struct drm_output;
119
120struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122 uint32_t fb_id, stride, handle, size;
123 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200125 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200126
127 /* Used by gbm fbs */
128 struct gbm_bo *bo;
129
130 /* Used by dumb fbs */
131 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132};
133
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400134struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500135 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400136
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400137 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400138 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500139 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400140 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700141 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200142
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300143 int vblank_pending;
144 int page_flip_pending;
145
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400146 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400147 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400148 struct weston_plane cursor_plane;
149 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400150 struct weston_surface *cursor_surface;
151 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300152 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200153 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200154
155 struct drm_fb *dumb[2];
156 pixman_image_t *image[2];
157 int current_image;
158 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400159};
160
Jesse Barnes58ef3792012-02-23 09:45:49 -0500161/*
162 * An output has a primary display plane plus zero or more sprites for
163 * blending display contents.
164 */
165struct drm_sprite {
166 struct wl_list link;
167
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400168 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500169
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200170 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300171 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500172 struct drm_compositor *compositor;
173
Jesse Barnes58ef3792012-02-23 09:45:49 -0500174 uint32_t possible_crtcs;
175 uint32_t plane_id;
176 uint32_t count_formats;
177
178 int32_t src_x, src_y;
179 uint32_t src_w, src_h;
180 uint32_t dest_x, dest_y;
181 uint32_t dest_w, dest_h;
182
183 uint32_t formats[];
184};
185
Pekka Paalanen33156972012-08-03 13:30:30 -0400186struct drm_seat {
187 struct weston_seat base;
188 struct wl_list devices_list;
189 struct udev_monitor *udev_monitor;
190 struct wl_event_source *udev_monitor_source;
191 char *seat_id;
192};
193
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400194static void
195drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400196
Jesse Barnes58ef3792012-02-23 09:45:49 -0500197static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500198drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
199{
200 struct weston_compositor *ec = output_base->compositor;
201 struct drm_compositor *c =(struct drm_compositor *) ec;
202 struct drm_output *output = (struct drm_output *) output_base;
203 int crtc;
204
205 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
206 if (c->crtcs[crtc] != output->crtc_id)
207 continue;
208
209 if (supported & (1 << crtc))
210 return -1;
211 }
212
213 return 0;
214}
215
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300216static void
217drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
218{
219 struct drm_fb *fb = data;
220 struct gbm_device *gbm = gbm_bo_get_device(bo);
221
222 if (fb->fb_id)
223 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
224
Pekka Paalanende685b82012-12-04 15:58:12 +0200225 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300226
227 free(data);
228}
229
230static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200231drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
232{
233 struct drm_fb *fb;
234 int ret;
235
236 struct drm_mode_create_dumb create_arg;
237 struct drm_mode_destroy_dumb destroy_arg;
238 struct drm_mode_map_dumb map_arg;
239
240 fb = calloc(1, sizeof *fb);
241 if (!fb)
242 return NULL;
243
244 create_arg.bpp = 32;
245 create_arg.width = width;
246 create_arg.height = height;
247
248 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
249 if (ret)
250 goto err_fb;
251
252 fb->handle = create_arg.handle;
253 fb->stride = create_arg.pitch;
254 fb->size = create_arg.size;
255 fb->fd = ec->drm.fd;
256
257 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
258 fb->stride, fb->handle, &fb->fb_id);
259 if (ret)
260 goto err_bo;
261
262 memset(&map_arg, 0, sizeof(map_arg));
263 map_arg.handle = fb->handle;
264 drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
265
266 if (ret)
267 goto err_add_fb;
268
269 fb->map = mmap(0, fb->size, PROT_WRITE,
270 MAP_SHARED, ec->drm.fd, map_arg.offset);
271 if (fb->map == MAP_FAILED)
272 goto err_add_fb;
273
274 return fb;
275
276err_add_fb:
277 drmModeRmFB(ec->drm.fd, fb->fb_id);
278err_bo:
279 memset(&destroy_arg, 0, sizeof(destroy_arg));
280 destroy_arg.handle = create_arg.handle;
281 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
282err_fb:
283 free(fb);
284 return NULL;
285}
286
287static void
288drm_fb_destroy_dumb(struct drm_fb *fb)
289{
290 struct drm_mode_destroy_dumb destroy_arg;
291
292 if (!fb->map)
293 return;
294
295 if (fb->fb_id)
296 drmModeRmFB(fb->fd, fb->fb_id);
297
298 weston_buffer_reference(&fb->buffer_ref, NULL);
299
300 munmap(fb->map, fb->size);
301
302 memset(&destroy_arg, 0, sizeof(destroy_arg));
303 destroy_arg.handle = fb->handle;
304 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
305
306 free(fb);
307}
308
309static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500310drm_fb_get_from_bo(struct gbm_bo *bo,
311 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300312{
313 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200314 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200315 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300316 int ret;
317
318 if (fb)
319 return fb;
320
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200321 fb = calloc(1, sizeof *fb);
322 if (!fb)
323 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300324
325 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300326
327 width = gbm_bo_get_width(bo);
328 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 fb->stride = gbm_bo_get_stride(bo);
330 fb->handle = gbm_bo_get_handle(bo).u32;
331 fb->size = fb->stride * height;
332 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300333
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200334 if (compositor->min_width > width || width > compositor->max_width ||
335 compositor->min_height > height ||
336 height > compositor->max_height) {
337 weston_log("bo geometry out of bounds\n");
338 goto err_free;
339 }
340
341 ret = -1;
342
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200343 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 handles[0] = fb->handle;
345 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200346 offsets[0] = 0;
347
348 ret = drmModeAddFB2(compositor->drm.fd, width, height,
349 format, handles, pitches, offsets,
350 &fb->fb_id, 0);
351 if (ret) {
352 weston_log("addfb2 failed: %m\n");
353 compositor->no_addfb2 = 1;
354 compositor->sprites_are_broken = 1;
355 }
356 }
357
358 if (ret)
359 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200360 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200363 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365 }
366
367 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
368
369 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200370
371err_free:
372 free(fb);
373 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300374}
375
376static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
378{
Pekka Paalanende685b82012-12-04 15:58:12 +0200379 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200380
381 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200382
Pekka Paalanende685b82012-12-04 15:58:12 +0200383 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200384}
385
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200386static void
387drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
388{
389 if (!fb)
390 return;
391
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200392 if (fb->map &&
393 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200394 drm_fb_destroy_dumb(fb);
395 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200396 if (fb->is_client_buffer)
397 gbm_bo_destroy(fb->bo);
398 else
399 gbm_surface_release_buffer(output->surface,
400 output->current->bo);
401 }
402}
403
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500404static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200405drm_output_check_scanout_format(struct drm_output *output,
406 struct weston_surface *es, struct gbm_bo *bo)
407{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200408 uint32_t format;
409 pixman_region32_t r;
410
411 format = gbm_bo_get_format(bo);
412
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500413 switch (format) {
414 case GBM_FORMAT_XRGB8888:
415 return format;
416 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200417 /* We can only scanout an ARGB buffer if the surface's
418 * opaque region covers the whole output */
419 pixman_region32_init(&r);
420 pixman_region32_subtract(&r, &output->base.region,
421 &es->opaque);
422
423 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500424 format = GBM_FORMAT_XRGB8888;
425 else
426 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200427
428 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200429
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500430 return format;
431 default:
432 return 0;
433 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434}
435
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400436static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400437drm_output_prepare_scanout_surface(struct weston_output *_output,
438 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500439{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400440 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500441 struct drm_compositor *c =
442 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200443 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300444 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500445 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500446
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500447 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200448 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200449 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200450 buffer->width != output->base.current->width ||
451 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200452 output->base.transform != es->buffer_transform ||
453 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400454 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500455
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400456 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200457 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500458
Rob Bradford9b101872012-09-14 23:25:41 +0100459 /* Unable to use the buffer for scanout */
460 if (!bo)
461 return NULL;
462
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500463 format = drm_output_check_scanout_format(output, es, bo);
464 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300465 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400466 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300467 }
468
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500469 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300470 if (!output->next) {
471 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400472 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300473 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500474
Pekka Paalanende685b82012-12-04 15:58:12 +0200475 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500476
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400477 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500478}
479
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500480static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200481drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400482{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200483 struct drm_compositor *c =
484 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300485 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400486
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200487 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300489 bo = gbm_surface_lock_front_buffer(output->surface);
490 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200491 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400492 return;
493 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300494
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500495 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300496 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200497 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300498 gbm_surface_release_buffer(output->surface, bo);
499 return;
500 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501}
502
503static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200504drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
505{
506 struct weston_compositor *ec = output->base.compositor;
507 pixman_region32_t total_damage, previous_damage;
508
509 pixman_region32_init(&total_damage);
510 pixman_region32_init(&previous_damage);
511
512 pixman_region32_copy(&previous_damage, damage);
513
514 pixman_region32_union(&total_damage, damage, &output->previous_damage);
515 pixman_region32_copy(&output->previous_damage, &previous_damage);
516
517 output->current_image ^= 1;
518
519 output->next = output->dumb[output->current_image];
520 pixman_renderer_output_set_buffer(&output->base,
521 output->image[output->current_image]);
522
523 ec->renderer->repaint_output(&output->base, &total_damage);
524
525 pixman_region32_fini(&total_damage);
526 pixman_region32_fini(&previous_damage);
527}
528
529static void
530drm_output_render(struct drm_output *output, pixman_region32_t *damage)
531{
532 struct drm_compositor *c =
533 (struct drm_compositor *) output->base.compositor;
534
535 if (c->use_pixman)
536 drm_output_render_pixman(output, damage);
537 else
538 drm_output_render_gl(output, damage);
539
540 pixman_region32_subtract(&c->base.primary_plane.damage,
541 &c->base.primary_plane.damage, damage);
542}
543
544static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500545drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400546 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100547{
548 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500549 struct drm_compositor *compositor =
550 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500551 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400552 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500553 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100554
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300555 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400556 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300557 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400558 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100559
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400560 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300561 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400562 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300563 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400564 &output->connector_id, 1,
565 &mode->mode_info);
566 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200567 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400568 return;
569 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200570 }
571
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500572 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300573 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500574 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200575 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500576 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500577 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100578
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300579 output->page_flip_pending = 1;
580
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400581 drm_output_set_cursor(output);
582
Jesse Barnes58ef3792012-02-23 09:45:49 -0500583 /*
584 * Now, update all the sprite surfaces
585 */
586 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200587 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 drmVBlank vbl = {
589 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
590 .request.sequence = 1,
591 };
592
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200593 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200594 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500595 continue;
596
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200597 if (s->next && !compositor->sprites_hidden)
598 fb_id = s->next->fb_id;
599
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200601 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602 s->dest_x, s->dest_y,
603 s->dest_w, s->dest_h,
604 s->src_x, s->src_y,
605 s->src_w, s->src_h);
606 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200607 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 ret, strerror(errno));
609
Rob Clark5ca1a472012-08-08 20:27:37 -0500610 if (output->pipe > 0)
611 vbl.request.type |= DRM_VBLANK_SECONDARY;
612
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613 /*
614 * Queue a vblank signal so we know when the surface
615 * becomes active on the display or has been replaced.
616 */
617 vbl.request.signal = (unsigned long)s;
618 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
619 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200620 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 ret, strerror(errno));
622 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300623
624 s->output = output;
625 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 }
627
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500628 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400629}
630
631static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
633 void *data)
634{
635 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300636 struct drm_output *output = s->output;
637 uint32_t msecs;
638
639 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200641 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 s->current = s->next;
643 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300644
645 if (!output->page_flip_pending) {
646 msecs = sec * 1000 + usec / 1000;
647 weston_output_finish_frame(&output->base, msecs);
648 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649}
650
651static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400652page_flip_handler(int fd, unsigned int frame,
653 unsigned int sec, unsigned int usec, void *data)
654{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200655 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400656 uint32_t msecs;
657
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300658 output->page_flip_pending = 0;
659
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200660 drm_output_release_fb(output, output->current);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300661 output->current = output->next;
662 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400663
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300664 if (!output->vblank_pending) {
665 msecs = sec * 1000 + usec / 1000;
666 weston_output_finish_frame(&output->base, msecs);
667 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200668}
669
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500670static uint32_t
671drm_output_check_sprite_format(struct drm_sprite *s,
672 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500673{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500674 uint32_t i, format;
675
676 format = gbm_bo_get_format(bo);
677
678 if (format == GBM_FORMAT_ARGB8888) {
679 pixman_region32_t r;
680
681 pixman_region32_init(&r);
682 pixman_region32_subtract(&r, &es->transform.boundingbox,
683 &es->transform.opaque);
684
685 if (!pixman_region32_not_empty(&r))
686 format = GBM_FORMAT_XRGB8888;
687
688 pixman_region32_fini(&r);
689 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500690
691 for (i = 0; i < s->count_formats; i++)
692 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500693 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500694
695 return 0;
696}
697
698static int
699drm_surface_transform_supported(struct weston_surface *es)
700{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500701 return !es->transform.enabled ||
702 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500703}
704
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400705static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400707 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500708{
709 struct weston_compositor *ec = output_base->compositor;
710 struct drm_compositor *c =(struct drm_compositor *) ec;
711 struct drm_sprite *s;
712 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500713 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200715 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500716 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400717 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500718
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200719 if (c->gbm == NULL)
720 return NULL;
721
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200722 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200723 return NULL;
724
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500725 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400726 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500727
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300728 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400729 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300730
Pekka Paalanende685b82012-12-04 15:58:12 +0200731 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400732 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500733
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200734 if (es->alpha != 1.0f)
735 return NULL;
736
Pekka Paalanende685b82012-12-04 15:58:12 +0200737 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500738 return NULL;
739
Jesse Barnes58ef3792012-02-23 09:45:49 -0500740 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400741 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500742
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743 wl_list_for_each(s, &c->sprite_list, link) {
744 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
745 continue;
746
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200747 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500748 found = 1;
749 break;
750 }
751 }
752
753 /* No sprites available */
754 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400755 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500756
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400757 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200758 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400759 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400760 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400761
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500762 format = drm_output_check_sprite_format(s, es, bo);
763 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200764 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400765 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766 }
767
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200768 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200769 if (!s->next) {
770 gbm_bo_destroy(bo);
771 return NULL;
772 }
773
Pekka Paalanende685b82012-12-04 15:58:12 +0200774 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400776 box = pixman_region32_extents(&es->transform.boundingbox);
777 s->plane.x = box->x1;
778 s->plane.y = box->y1;
779
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780 /*
781 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200782 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500783 * for us already).
784 */
785 pixman_region32_init(&dest_rect);
786 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
787 &output_base->region);
788 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
789 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200790 tbox = weston_transformed_rect(output_base->width,
791 output_base->height,
792 output_base->transform, *box);
793 s->dest_x = tbox.x1;
794 s->dest_y = tbox.y1;
795 s->dest_w = tbox.x2 - tbox.x1;
796 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797 pixman_region32_fini(&dest_rect);
798
799 pixman_region32_init(&src_rect);
800 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
801 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400803
804 weston_surface_from_global_fixed(es,
805 wl_fixed_from_int(box->x1),
806 wl_fixed_from_int(box->y1),
807 &sx1, &sy1);
808 weston_surface_from_global_fixed(es,
809 wl_fixed_from_int(box->x2),
810 wl_fixed_from_int(box->y2),
811 &sx2, &sy2);
812
813 if (sx1 < 0)
814 sx1 = 0;
815 if (sy1 < 0)
816 sy1 = 0;
817 if (sx2 > wl_fixed_from_int(es->geometry.width))
818 sx2 = wl_fixed_from_int(es->geometry.width);
819 if (sy2 > wl_fixed_from_int(es->geometry.height))
820 sy2 = wl_fixed_from_int(es->geometry.height);
821
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200822 tbox.x1 = sx1;
823 tbox.y1 = sy1;
824 tbox.x2 = sx2;
825 tbox.y2 = sy2;
826
827 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
828 wl_fixed_from_int(es->geometry.height),
829 es->buffer_transform, tbox);
830
831 s->src_x = tbox.x1 << 8;
832 s->src_y = tbox.y1 << 8;
833 s->src_w = (tbox.x2 - tbox.x1) << 8;
834 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835 pixman_region32_fini(&src_rect);
836
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400837 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500838}
839
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400840static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400841drm_output_prepare_cursor_surface(struct weston_output *output_base,
842 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500843{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400844 struct drm_compositor *c =
845 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400846 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400847
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200848 if (c->gbm == NULL)
849 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200850 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
851 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400852 if (output->cursor_surface)
853 return NULL;
854 if (es->output_mask != (1u << output_base->id))
855 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500856 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400857 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200858 if (es->buffer_ref.buffer == NULL ||
859 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400860 es->geometry.width > 64 || es->geometry.height > 64)
861 return NULL;
862
863 output->cursor_surface = es;
864
865 return &output->cursor_plane;
866}
867
868static void
869drm_output_set_cursor(struct drm_output *output)
870{
871 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400872 struct drm_compositor *c =
873 (struct drm_compositor *) output->base.compositor;
874 EGLint handle, stride;
875 struct gbm_bo *bo;
876 uint32_t buf[64 * 64];
877 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400878 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500879
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400880 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400881 if (es == NULL) {
882 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
883 return;
884 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500885
Pekka Paalanende685b82012-12-04 15:58:12 +0200886 if (es->buffer_ref.buffer &&
887 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400888 pixman_region32_fini(&output->cursor_plane.damage);
889 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400890 output->current_cursor ^= 1;
891 bo = output->cursor_bo[output->current_cursor];
892 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200893 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
894 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400895 for (i = 0; i < es->geometry.height; i++)
896 memcpy(buf + i * 64, s + i * stride,
897 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500898
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400899 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300900 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400901
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400902 handle = gbm_bo_get_handle(bo).s32;
903 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500904 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300905 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500906 c->cursors_are_broken = 1;
907 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400908 }
909
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400910 x = es->geometry.x - output->base.x;
911 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400912 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500913 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400914 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500915 c->cursors_are_broken = 1;
916 }
917
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400918 output->cursor_plane.x = x;
919 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400920 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500921}
922
Jesse Barnes58ef3792012-02-23 09:45:49 -0500923static void
924drm_assign_planes(struct weston_output *output)
925{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400926 struct drm_compositor *c =
927 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200928 struct drm_output *drm_output = (struct drm_output *) output;
929 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400930 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500931 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400932 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500933
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200934 /* Reset the opaque region of the planes */
935 pixman_region32_fini(&drm_output->cursor_plane.opaque);
936 pixman_region32_init(&drm_output->cursor_plane.opaque);
937 pixman_region32_fini(&drm_output->fb_plane.opaque);
938 pixman_region32_init(&drm_output->fb_plane.opaque);
939
940 wl_list_for_each (s, &c->sprite_list, link) {
941 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
942 continue;
943
944 pixman_region32_fini(&s->plane.opaque);
945 pixman_region32_init(&s->plane.opaque);
946 }
947
Jesse Barnes58ef3792012-02-23 09:45:49 -0500948 /*
949 * Find a surface for each sprite in the output using some heuristics:
950 * 1) size
951 * 2) frequency of update
952 * 3) opacity (though some hw might support alpha blending)
953 * 4) clipping (this can be fixed with color keys)
954 *
955 * The idea is to save on blitting since this should save power.
956 * If we can get a large video surface on the sprite for example,
957 * the main display surface may not need to update at all, and
958 * the client buffer can be used directly for the sprite surface
959 * as we do for flipping full screen surfaces.
960 */
961 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400962 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400963 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +0200964 /* test whether this buffer can ever go into a plane:
965 * non-shm, or small enough to be a cursor
966 */
967 if ((es->buffer_ref.buffer &&
968 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
969 (es->geometry.width <= 64 && es->geometry.height <= 64))
970 es->keep_buffer = 1;
971 else
972 es->keep_buffer = 0;
973
Jesse Barnes58ef3792012-02-23 09:45:49 -0500974 pixman_region32_init(&surface_overlap);
975 pixman_region32_intersect(&surface_overlap, &overlap,
976 &es->transform.boundingbox);
977
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400978 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400979 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400980 next_plane = primary;
981 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400982 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400983 if (next_plane == NULL)
984 next_plane = drm_output_prepare_scanout_surface(output, es);
985 if (next_plane == NULL)
986 next_plane = drm_output_prepare_overlay_surface(output, es);
987 if (next_plane == NULL)
988 next_plane = primary;
989 weston_surface_move_to_plane(es, next_plane);
990 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500991 pixman_region32_union(&overlap, &overlap,
992 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400993
Jesse Barnes58ef3792012-02-23 09:45:49 -0500994 pixman_region32_fini(&surface_overlap);
995 }
996 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500997}
998
Matt Roper361d2ad2011-08-29 13:52:23 -0700999static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001000drm_output_fini_pixman(struct drm_output *output);
1001
1002static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001003drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001004{
1005 struct drm_output *output = (struct drm_output *) output_base;
1006 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001007 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001008 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001009
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001010 if (output->backlight)
1011 backlight_destroy(output->backlight);
1012
Matt Roper361d2ad2011-08-29 13:52:23 -07001013 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001014 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001015
1016 /* Restore original CRTC state */
1017 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001018 origcrtc->x, origcrtc->y,
1019 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001020 drmModeFreeCrtc(origcrtc);
1021
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001022 c->crtc_allocator &= ~(1 << output->crtc_id);
1023 c->connector_allocator &= ~(1 << output->connector_id);
1024
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001025 if (c->use_pixman) {
1026 drm_output_fini_pixman(output);
1027 } else {
1028 gl_renderer_output_destroy(output_base);
1029 gbm_surface_destroy(output->surface);
1030 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001031
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001032 weston_plane_release(&output->fb_plane);
1033 weston_plane_release(&output->cursor_plane);
1034
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001035 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001036 wl_list_remove(&output->base.link);
1037
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001038 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001039 free(output);
1040}
1041
Alex Wub7b8bda2012-04-17 17:20:48 +08001042static struct drm_mode *
1043choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1044{
1045 struct drm_mode *tmp_mode = NULL, *mode;
1046
1047 if (output->base.current->width == target_mode->width &&
1048 output->base.current->height == target_mode->height &&
1049 (output->base.current->refresh == target_mode->refresh ||
1050 target_mode->refresh == 0))
1051 return (struct drm_mode *)output->base.current;
1052
1053 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1054 if (mode->mode_info.hdisplay == target_mode->width &&
1055 mode->mode_info.vdisplay == target_mode->height) {
1056 if (mode->mode_info.vrefresh == target_mode->refresh ||
1057 target_mode->refresh == 0) {
1058 return mode;
1059 } else if (!tmp_mode)
1060 tmp_mode = mode;
1061 }
1062 }
1063
1064 return tmp_mode;
1065}
1066
1067static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001068drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001069static int
1070drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001071
1072static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001073drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1074{
1075 struct drm_output *output;
1076 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001077 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001078
1079 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001080 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001081 return -1;
1082 }
1083
1084 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001085 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001086 return -1;
1087 }
1088
1089 ec = (struct drm_compositor *)output_base->compositor;
1090 output = (struct drm_output *)output_base;
1091 drm_mode = choose_mode (output, mode);
1092
1093 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001094 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001095 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001096 }
1097
1098 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001099 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001100
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001101 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001102
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001103 output->base.current = &drm_mode->base;
1104 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001105 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1106
Alex Wub7b8bda2012-04-17 17:20:48 +08001107 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001108 drm_output_release_fb(output, output->current);
1109 drm_output_release_fb(output, output->next);
1110 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001111
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001112 if (ec->use_pixman) {
1113 drm_output_fini_pixman(output);
1114 if (drm_output_init_pixman(output, ec) < 0) {
1115 weston_log("failed to init output pixman state with "
1116 "new mode\n");
1117 return -1;
1118 }
1119 } else {
1120 gl_renderer_output_destroy(&output->base);
1121 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001122
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001123 if (drm_output_init_egl(output, ec) < 0) {
1124 weston_log("failed to init output egl state with "
1125 "new mode");
1126 return -1;
1127 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001128 }
1129
Alex Wub7b8bda2012-04-17 17:20:48 +08001130 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001131}
1132
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001133static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001134on_drm_input(int fd, uint32_t mask, void *data)
1135{
1136 drmEventContext evctx;
1137
1138 memset(&evctx, 0, sizeof evctx);
1139 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1140 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001141 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001142 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001143
1144 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001145}
1146
1147static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001148init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001149{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001150 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001151 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001152
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001153 sysnum = udev_device_get_sysnum(device);
1154 if (sysnum)
1155 ec->drm.id = atoi(sysnum);
1156 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001157 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001158 return -1;
1159 }
1160
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001161 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001162 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001163 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001164 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001165 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001166 udev_device_get_devnode(device));
1167 return -1;
1168 }
1169
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001170 weston_log("using %s\n", filename);
1171
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001172 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001173
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001174
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001175 return 0;
1176}
1177
1178static int
1179init_egl(struct drm_compositor *ec)
1180{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001181 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001182
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001183 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001184 NULL) < 0) {
1185 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001186 return -1;
1187 }
1188
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001189 return 0;
1190}
1191
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001192static int
1193init_pixman(struct drm_compositor *ec)
1194{
1195 return pixman_renderer_init(&ec->base);
1196}
1197
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001198static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001199drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1200{
1201 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001202 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001203
1204 mode = malloc(sizeof *mode);
1205 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001206 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001207
1208 mode->base.flags = 0;
1209 mode->base.width = info->hdisplay;
1210 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001211
1212 /* Calculate higher precision (mHz) refresh rate */
1213 refresh = (info->clock * 1000000LL / info->htotal +
1214 info->vtotal / 2) / info->vtotal;
1215
1216 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1217 refresh *= 2;
1218 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1219 refresh /= 2;
1220 if (info->vscan > 1)
1221 refresh /= info->vscan;
1222
1223 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001224 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001225
1226 if (info->type & DRM_MODE_TYPE_PREFERRED)
1227 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1228
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001229 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1230
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001231 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001232}
1233
1234static int
1235drm_subpixel_to_wayland(int drm_value)
1236{
1237 switch (drm_value) {
1238 default:
1239 case DRM_MODE_SUBPIXEL_UNKNOWN:
1240 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1241 case DRM_MODE_SUBPIXEL_NONE:
1242 return WL_OUTPUT_SUBPIXEL_NONE;
1243 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1244 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1245 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1246 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1247 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1248 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1249 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1250 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1251 }
1252}
1253
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001254/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001255static uint32_t
1256drm_get_backlight(struct drm_output *output)
1257{
1258 long brightness, max_brightness, norm;
1259
1260 brightness = backlight_get_brightness(output->backlight);
1261 max_brightness = backlight_get_max_brightness(output->backlight);
1262
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001263 /* convert it on a scale of 0 to 255 */
1264 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001265
1266 return (uint32_t) norm;
1267}
1268
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001269/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001270static void
1271drm_set_backlight(struct weston_output *output_base, uint32_t value)
1272{
1273 struct drm_output *output = (struct drm_output *) output_base;
1274 long max_brightness, new_brightness;
1275
1276 if (!output->backlight)
1277 return;
1278
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001279 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001280 return;
1281
1282 max_brightness = backlight_get_max_brightness(output->backlight);
1283
1284 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001285 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001286
1287 backlight_set_brightness(output->backlight, new_brightness);
1288}
1289
1290static drmModePropertyPtr
1291drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1292{
1293 drmModePropertyPtr props;
1294 int i;
1295
1296 for (i = 0; i < connector->count_props; i++) {
1297 props = drmModeGetProperty(fd, connector->props[i]);
1298 if (!props)
1299 continue;
1300
1301 if (!strcmp(props->name, name))
1302 return props;
1303
1304 drmModeFreeProperty(props);
1305 }
1306
1307 return NULL;
1308}
1309
1310static void
1311drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1312{
1313 struct drm_output *output = (struct drm_output *) output_base;
1314 struct weston_compositor *ec = output_base->compositor;
1315 struct drm_compositor *c = (struct drm_compositor *) ec;
1316 drmModeConnectorPtr connector;
1317 drmModePropertyPtr prop;
1318
1319 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1320 if (!connector)
1321 return;
1322
1323 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1324 if (!prop) {
1325 drmModeFreeConnector(connector);
1326 return;
1327 }
1328
1329 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1330 prop->prop_id, level);
1331 drmModeFreeProperty(prop);
1332 drmModeFreeConnector(connector);
1333}
1334
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001335static const char *connector_type_names[] = {
1336 "None",
1337 "VGA",
1338 "DVI",
1339 "DVI",
1340 "DVI",
1341 "Composite",
1342 "TV",
1343 "LVDS",
1344 "CTV",
1345 "DIN",
1346 "DP",
1347 "HDMI",
1348 "HDMI",
1349 "TV",
1350 "eDP",
1351};
1352
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001353static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001354find_crtc_for_connector(struct drm_compositor *ec,
1355 drmModeRes *resources, drmModeConnector *connector)
1356{
1357 drmModeEncoder *encoder;
1358 uint32_t possible_crtcs;
1359 int i, j;
1360
1361 for (j = 0; j < connector->count_encoders; j++) {
1362 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1363 if (encoder == NULL) {
1364 weston_log("Failed to get encoder.\n");
1365 return -1;
1366 }
1367 possible_crtcs = encoder->possible_crtcs;
1368 drmModeFreeEncoder(encoder);
1369
1370 for (i = 0; i < resources->count_crtcs; i++) {
1371 if (possible_crtcs & (1 << i) &&
1372 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1373 return i;
1374 }
1375 }
1376
1377 return -1;
1378}
1379
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001380/* Init output state that depends on gl or gbm */
1381static int
1382drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1383{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001384 int i, flags;
1385
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001386 output->surface = gbm_surface_create(ec->gbm,
1387 output->base.current->width,
1388 output->base.current->height,
1389 GBM_FORMAT_XRGB8888,
1390 GBM_BO_USE_SCANOUT |
1391 GBM_BO_USE_RENDERING);
1392 if (!output->surface) {
1393 weston_log("failed to create gbm surface\n");
1394 return -1;
1395 }
1396
1397 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001398 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001399 gbm_surface_destroy(output->surface);
1400 return -1;
1401 }
1402
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001403 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1404
1405 for (i = 0; i < 2; i++) {
1406 if (output->cursor_bo[i])
1407 continue;
1408
1409 output->cursor_bo[i] =
1410 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1411 flags);
1412 }
1413
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001414 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1415 weston_log("cursor buffers unavailable, using gl cursors\n");
1416 ec->cursors_are_broken = 1;
1417 }
1418
1419 return 0;
1420}
1421
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001422static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001423drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1424{
1425 int w = output->base.current->width;
1426 int h = output->base.current->height;
1427 unsigned int i;
1428
1429 /* FIXME error checking */
1430
1431 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1432 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1433 if (!output->dumb[i])
1434 goto err;
1435
1436 output->image[i] =
1437 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1438 output->dumb[i]->map,
1439 output->dumb[i]->stride);
1440 if (!output->image[i])
1441 goto err;
1442 }
1443
1444 if (pixman_renderer_output_create(&output->base) < 0)
1445 goto err;
1446
1447 pixman_region32_init_rect(&output->previous_damage,
1448 output->base.x, output->base.y, w, h);
1449
1450 return 0;
1451
1452err:
1453 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1454 if (output->dumb[i])
1455 drm_fb_destroy_dumb(output->dumb[i]);
1456 if (output->image[i])
1457 pixman_image_unref(output->image[i]);
1458
1459 output->dumb[i] = NULL;
1460 output->image[i] = NULL;
1461 }
1462
1463 return -1;
1464}
1465
1466static void
1467drm_output_fini_pixman(struct drm_output *output)
1468{
1469 unsigned int i;
1470
1471 pixman_renderer_output_destroy(&output->base);
1472 pixman_region32_fini(&output->previous_damage);
1473
1474 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1475 drm_fb_destroy_dumb(output->dumb[i]);
1476 pixman_image_unref(output->image[i]);
1477 output->dumb[i] = NULL;
1478 output->image[i] = NULL;
1479 }
1480}
1481
1482static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001483create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001484 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001485 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001486 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001487{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001488 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001489 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1490 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001491 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001492 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001493 drmModeModeInfo crtc_mode;
1494 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001495 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001496 char name[32];
1497 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001498
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001499 i = find_crtc_for_connector(ec, resources, connector);
1500 if (i < 0) {
1501 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001502 return -1;
1503 }
1504
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001505 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001506 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001507 return -1;
1508
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001509 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001510 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1511 output->base.make = "unknown";
1512 output->base.model = "unknown";
1513 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001514
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001515 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1516 type_name = connector_type_names[connector->connector_type];
1517 else
1518 type_name = "UNKNOWN";
1519 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1520 output->name = strdup(name);
1521
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001522 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001523 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001524 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001525 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001526 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001527
Matt Roper361d2ad2011-08-29 13:52:23 -07001528 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1529
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001530 /* Get the current mode on the crtc that's currently driving
1531 * this connector. */
1532 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001533 memset(&crtc_mode, 0, sizeof crtc_mode);
1534 if (encoder != NULL) {
1535 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1536 drmModeFreeEncoder(encoder);
1537 if (crtc == NULL)
1538 goto err_free;
1539 if (crtc->mode_valid)
1540 crtc_mode = crtc->mode;
1541 drmModeFreeCrtc(crtc);
1542 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001543
David Herrmann0f0d54e2011-12-08 17:05:45 +01001544 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001545 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1546 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001547 goto err_free;
1548 }
1549
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001550 preferred = NULL;
1551 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001552 configured = NULL;
1553
1554 wl_list_for_each(temp, &configured_output_list, link) {
1555 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001556 if (temp->mode)
1557 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001558 temp->name, temp->mode);
1559 o = temp;
1560 break;
1561 }
1562 }
1563
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001564 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001565 weston_log("Disabling output %s\n", o->name);
1566
1567 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1568 0, 0, 0, 0, 0, NULL);
1569 goto err_free;
1570 }
1571
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001572 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001573 if (o && o->config == OUTPUT_CONFIG_MODE &&
1574 o->width == drm_mode->base.width &&
1575 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001576 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001577 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001578 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001579 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001580 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001581 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001582
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001583 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001584 configured = drm_output_add_mode(output, &o->crtc_mode);
1585 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001586 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001587 current = configured;
1588 }
1589
Wang Quanxianacb805a2012-07-30 18:09:46 -04001590 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001591 current = drm_output_add_mode(output, &crtc_mode);
1592 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001593 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001594 }
1595
Scott Moreau8ab5d452012-07-30 19:51:08 -06001596 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1597 configured = current;
1598
Wang Quanxianacb805a2012-07-30 18:09:46 -04001599 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001600 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001601 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001602 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001603 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001604 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001605 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001606 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001607
1608 if (output->base.current == NULL) {
1609 weston_log("no available modes for %s\n", output->name);
1610 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001611 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001612
Wang Quanxianacb805a2012-07-30 18:09:46 -04001613 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1614
John Kåre Alsaker94659272012-11-13 19:10:18 +01001615 weston_output_init(&output->base, &ec->base, x, y,
1616 connector->mmWidth, connector->mmHeight,
1617 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1618
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001619 if (ec->use_pixman) {
1620 if (drm_output_init_pixman(output, ec) < 0) {
1621 weston_log("Failed to init output pixman state\n");
1622 goto err_output;
1623 }
1624 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001625 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001626 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001627 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001628
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001629 output->backlight = backlight_init(drm_device,
1630 connector->connector_type);
1631 if (output->backlight) {
1632 output->base.set_backlight = drm_set_backlight;
1633 output->base.backlight_current = drm_get_backlight(output);
1634 }
1635
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001636 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1637
Alex Wubd3354b2012-04-17 17:20:49 +08001638 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001639 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001640 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001641 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001642 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001643 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001644
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001645 weston_plane_init(&output->cursor_plane, 0, 0);
1646 weston_plane_init(&output->fb_plane, 0, 0);
1647
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001648 weston_log("Output %s, (connector %d, crtc %d)\n",
1649 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001650 wl_list_for_each(m, &output->base.mode_list, link)
1651 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1652 m->width, m->height, m->refresh / 1000.0,
1653 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1654 ", preferred" : "",
1655 m->flags & WL_OUTPUT_MODE_CURRENT ?
1656 ", current" : "",
1657 connector->count_modes == 0 ?
1658 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001659
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001660 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001661
John Kåre Alsaker94659272012-11-13 19:10:18 +01001662err_output:
1663 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001664err_free:
1665 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1666 base.link) {
1667 wl_list_remove(&drm_mode->base.link);
1668 free(drm_mode);
1669 }
1670
1671 drmModeFreeCrtc(output->original_crtc);
1672 ec->crtc_allocator &= ~(1 << output->crtc_id);
1673 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001674 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001675 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001676
David Herrmann0f0d54e2011-12-08 17:05:45 +01001677 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001678}
1679
Jesse Barnes58ef3792012-02-23 09:45:49 -05001680static void
1681create_sprites(struct drm_compositor *ec)
1682{
1683 struct drm_sprite *sprite;
1684 drmModePlaneRes *plane_res;
1685 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001686 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001687
1688 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1689 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001690 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001691 strerror(errno));
1692 return;
1693 }
1694
1695 for (i = 0; i < plane_res->count_planes; i++) {
1696 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1697 if (!plane)
1698 continue;
1699
1700 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1701 plane->count_formats));
1702 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001703 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001704 __func__);
1705 free(plane);
1706 continue;
1707 }
1708
1709 memset(sprite, 0, sizeof *sprite);
1710
1711 sprite->possible_crtcs = plane->possible_crtcs;
1712 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001713 sprite->current = NULL;
1714 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001715 sprite->compositor = ec;
1716 sprite->count_formats = plane->count_formats;
1717 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001718 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001719 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001720 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001721
1722 wl_list_insert(&ec->sprite_list, &sprite->link);
1723 }
1724
1725 free(plane_res->planes);
1726 free(plane_res);
1727}
1728
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001729static void
1730destroy_sprites(struct drm_compositor *compositor)
1731{
1732 struct drm_sprite *sprite, *next;
1733 struct drm_output *output;
1734
1735 output = container_of(compositor->base.output_list.next,
1736 struct drm_output, base.link);
1737
1738 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1739 drmModeSetPlane(compositor->drm.fd,
1740 sprite->plane_id,
1741 output->crtc_id, 0, 0,
1742 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001743 drm_output_release_fb(output, sprite->current);
1744 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001745 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001746 free(sprite);
1747 }
1748}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001749
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001750static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001751create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001752 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001753{
1754 drmModeConnector *connector;
1755 drmModeRes *resources;
1756 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001757 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001758
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001759 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001760 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001761 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001762 return -1;
1763 }
1764
Jesse Barnes58ef3792012-02-23 09:45:49 -05001765 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001766 if (!ec->crtcs) {
1767 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001768 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001769 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001770
Rob Clark4339add2012-08-09 14:18:28 -05001771 ec->min_width = resources->min_width;
1772 ec->max_width = resources->max_width;
1773 ec->min_height = resources->min_height;
1774 ec->max_height = resources->max_height;
1775
Jesse Barnes58ef3792012-02-23 09:45:49 -05001776 ec->num_crtcs = resources->count_crtcs;
1777 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1778
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001779 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001780 connector = drmModeGetConnector(ec->drm.fd,
1781 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001782 if (connector == NULL)
1783 continue;
1784
1785 if (connector->connection == DRM_MODE_CONNECTED &&
1786 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001787 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001788 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001789 connector, x, y,
1790 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001791 drmModeFreeConnector(connector);
1792 continue;
1793 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001794
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001795 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001796 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001797 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001798 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001799
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001800 drmModeFreeConnector(connector);
1801 }
1802
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001803 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001804 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001805 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001806 return -1;
1807 }
1808
1809 drmModeFreeResources(resources);
1810
1811 return 0;
1812}
1813
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001814static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001815update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001816{
1817 drmModeConnector *connector;
1818 drmModeRes *resources;
1819 struct drm_output *output, *next;
1820 int x = 0, y = 0;
1821 int x_offset = 0, y_offset = 0;
1822 uint32_t connected = 0, disconnects = 0;
1823 int i;
1824
1825 resources = drmModeGetResources(ec->drm.fd);
1826 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001827 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001828 return;
1829 }
1830
1831 /* collect new connects */
1832 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001833 int connector_id = resources->connectors[i];
1834
1835 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001836 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001837 continue;
1838
David Herrmann7551cff2011-12-08 17:05:43 +01001839 if (connector->connection != DRM_MODE_CONNECTED) {
1840 drmModeFreeConnector(connector);
1841 continue;
1842 }
1843
Benjamin Franzke117483d2011-08-30 11:38:26 +02001844 connected |= (1 << connector_id);
1845
1846 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001847 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001848 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001849 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001850
1851 /* XXX: not yet needed, we die with 0 outputs */
1852 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001853 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001854 else
1855 x = 0;
1856 y = 0;
1857 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001858 connector, x, y,
1859 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001860 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001861
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001862 }
1863 drmModeFreeConnector(connector);
1864 }
1865 drmModeFreeResources(resources);
1866
1867 disconnects = ec->connector_allocator & ~connected;
1868 if (disconnects) {
1869 wl_list_for_each_safe(output, next, &ec->base.output_list,
1870 base.link) {
1871 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001872 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001873 output->base.x - x_offset,
1874 output->base.y - y_offset);
1875 }
1876
1877 if (disconnects & (1 << output->connector_id)) {
1878 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001879 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001880 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001881 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001882 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001883 }
1884 }
1885 }
1886
1887 /* FIXME: handle zero outputs, without terminating */
1888 if (ec->connector_allocator == 0)
1889 wl_display_terminate(ec->base.wl_display);
1890}
1891
1892static int
David Herrmannd7488c22012-03-11 20:05:21 +01001893udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001894{
David Herrmannd7488c22012-03-11 20:05:21 +01001895 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001896 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001897
1898 sysnum = udev_device_get_sysnum(device);
1899 if (!sysnum || atoi(sysnum) != ec->drm.id)
1900 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001901
David Herrmann6ac52db2012-03-11 20:05:22 +01001902 val = udev_device_get_property_value(device, "HOTPLUG");
1903 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001904 return 0;
1905
David Herrmann6ac52db2012-03-11 20:05:22 +01001906 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001907}
1908
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001909static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001910udev_drm_event(int fd, uint32_t mask, void *data)
1911{
1912 struct drm_compositor *ec = data;
1913 struct udev_device *event;
1914
1915 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001916
David Herrmannd7488c22012-03-11 20:05:21 +01001917 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001918 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001919
1920 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001921
1922 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001923}
1924
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001925static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001926drm_restore(struct weston_compositor *ec)
1927{
1928 struct drm_compositor *d = (struct drm_compositor *) ec;
1929
1930 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1931 weston_log("failed to drop master: %m\n");
1932 tty_reset(d->tty);
1933}
1934
Pekka Paalanen33156972012-08-03 13:30:30 -04001935static const char default_seat[] = "seat0";
1936
1937static void
1938device_added(struct udev_device *udev_device, struct drm_seat *master)
1939{
1940 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001941 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001942 const char *devnode;
1943 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001944 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001945 int fd;
1946
1947 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1948 if (!device_seat)
1949 device_seat = default_seat;
1950
1951 if (strcmp(device_seat, master->seat_id))
1952 return;
1953
1954 c = master->base.compositor;
1955 devnode = udev_device_get_devnode(udev_device);
1956
1957 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001958 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001959 * read. mtdev_get() also expects this. */
1960 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1961 if (fd < 0) {
1962 weston_log("opening input device '%s' failed.\n", devnode);
1963 return;
1964 }
1965
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001966 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001967 if (!device) {
1968 close(fd);
1969 weston_log("not using input device '%s'.\n", devnode);
1970 return;
1971 }
1972
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001973 calibration_values =
1974 udev_device_get_property_value(udev_device,
1975 "WL_CALIBRATION");
1976
1977 if (calibration_values && sscanf(calibration_values,
1978 "%f %f %f %f %f %f",
1979 &device->abs.calibration[0],
1980 &device->abs.calibration[1],
1981 &device->abs.calibration[2],
1982 &device->abs.calibration[3],
1983 &device->abs.calibration[4],
1984 &device->abs.calibration[5]) == 6) {
1985 device->abs.apply_calibration = 1;
1986 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1987 device->abs.calibration[0],
1988 device->abs.calibration[1],
1989 device->abs.calibration[2],
1990 device->abs.calibration[3],
1991 device->abs.calibration[4],
1992 device->abs.calibration[5]);
1993 }
1994
Pekka Paalanen33156972012-08-03 13:30:30 -04001995 wl_list_insert(master->devices_list.prev, &device->link);
1996}
1997
1998static void
1999evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
2000{
2001 struct drm_seat *seat = (struct drm_seat *) seat_base;
2002 struct udev_enumerate *e;
2003 struct udev_list_entry *entry;
2004 struct udev_device *device;
2005 const char *path, *sysname;
2006
2007 e = udev_enumerate_new(udev);
2008 udev_enumerate_add_match_subsystem(e, "input");
2009 udev_enumerate_scan_devices(e);
2010 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2011 path = udev_list_entry_get_name(entry);
2012 device = udev_device_new_from_syspath(udev, path);
2013
2014 sysname = udev_device_get_sysname(device);
2015 if (strncmp("event", sysname, 5) != 0) {
2016 udev_device_unref(device);
2017 continue;
2018 }
2019
2020 device_added(device, seat);
2021
2022 udev_device_unref(device);
2023 }
2024 udev_enumerate_unref(e);
2025
2026 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
2027
2028 if (wl_list_empty(&seat->devices_list)) {
2029 weston_log(
2030 "warning: no input devices on entering Weston. "
2031 "Possible causes:\n"
2032 "\t- no permissions to read /dev/input/event*\n"
2033 "\t- seats misconfigured "
2034 "(Weston backend option 'seat', "
2035 "udev device property ID_SEAT)\n");
2036 }
2037}
2038
2039static int
2040evdev_udev_handler(int fd, uint32_t mask, void *data)
2041{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002042 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04002043 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002044 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002045 const char *action;
2046 const char *devnode;
2047
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002048 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04002049 if (!udev_device)
2050 return 1;
2051
2052 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002053 if (!action)
2054 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04002055
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002056 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
2057 goto out;
2058
2059 if (!strcmp(action, "add")) {
2060 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002061 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002062 else if (!strcmp(action, "remove")) {
2063 devnode = udev_device_get_devnode(udev_device);
2064 wl_list_for_each_safe(device, next, &seat->devices_list, link)
2065 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03002066 weston_log("input device %s, %s removed\n",
2067 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002068 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03002069 break;
2070 }
2071 }
2072
2073out:
Pekka Paalanen33156972012-08-03 13:30:30 -04002074 udev_device_unref(udev_device);
2075
2076 return 0;
2077}
2078
2079static int
2080evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
2081{
2082 struct drm_seat *master = (struct drm_seat *) seat_base;
2083 struct wl_event_loop *loop;
2084 struct weston_compositor *c = master->base.compositor;
2085 int fd;
2086
2087 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
2088 if (!master->udev_monitor) {
2089 weston_log("udev: failed to create the udev monitor\n");
2090 return 0;
2091 }
2092
2093 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
2094 "input", NULL);
2095
2096 if (udev_monitor_enable_receiving(master->udev_monitor)) {
2097 weston_log("udev: failed to bind the udev monitor\n");
2098 udev_monitor_unref(master->udev_monitor);
2099 return 0;
2100 }
2101
2102 loop = wl_display_get_event_loop(c->wl_display);
2103 fd = udev_monitor_get_fd(master->udev_monitor);
2104 master->udev_monitor_source =
2105 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
2106 evdev_udev_handler, master);
2107 if (!master->udev_monitor_source) {
2108 udev_monitor_unref(master->udev_monitor);
2109 return 0;
2110 }
2111
2112 return 1;
2113}
2114
2115static void
2116evdev_disable_udev_monitor(struct weston_seat *seat_base)
2117{
2118 struct drm_seat *seat = (struct drm_seat *) seat_base;
2119
2120 if (!seat->udev_monitor)
2121 return;
2122
2123 udev_monitor_unref(seat->udev_monitor);
2124 seat->udev_monitor = NULL;
2125 wl_event_source_remove(seat->udev_monitor_source);
2126 seat->udev_monitor_source = NULL;
2127}
2128
2129static void
2130drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
2131{
2132 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002133 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002134
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002135 wl_list_for_each(device, &seat->devices_list, link)
2136 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002137}
2138
2139static void
2140evdev_input_create(struct weston_compositor *c, struct udev *udev,
2141 const char *seat_id)
2142{
2143 struct drm_seat *seat;
2144
2145 seat = malloc(sizeof *seat);
2146 if (seat == NULL)
2147 return;
2148
2149 memset(seat, 0, sizeof *seat);
2150 weston_seat_init(&seat->base, c);
2151 seat->base.led_update = drm_led_update;
2152
2153 wl_list_init(&seat->devices_list);
2154 seat->seat_id = strdup(seat_id);
2155 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2156 free(seat->seat_id);
2157 free(seat);
2158 return;
2159 }
2160
2161 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002162}
2163
2164static void
2165evdev_remove_devices(struct weston_seat *seat_base)
2166{
2167 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002168 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002169
2170 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002171 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002172
Pekka Paalanend8583512012-08-03 14:39:11 +03002173 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002174 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002175}
2176
2177static void
2178evdev_input_destroy(struct weston_seat *seat_base)
2179{
2180 struct drm_seat *seat = (struct drm_seat *) seat_base;
2181
2182 evdev_remove_devices(seat_base);
2183 evdev_disable_udev_monitor(&seat->base);
2184
2185 weston_seat_release(seat_base);
2186 free(seat->seat_id);
2187 free(seat);
2188}
2189
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002190static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002191drm_free_configured_output(struct drm_configured_output *output)
2192{
2193 free(output->name);
2194 free(output->mode);
2195 free(output);
2196}
2197
2198static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002199drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002200{
2201 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002202 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002203 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002204
Daniel Stone37816df2012-05-16 18:45:18 +01002205 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2206 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002207 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002208 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002209
2210 wl_event_source_remove(d->udev_drm_source);
2211 wl_event_source_remove(d->drm_source);
2212
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002213 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002214
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002215 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002216
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002217 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002218
2219 if (d->gbm)
2220 gbm_device_destroy(d->gbm);
2221
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002222 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002223 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002224 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002225
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002226 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002227}
2228
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002229static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002230drm_compositor_set_modes(struct drm_compositor *compositor)
2231{
2232 struct drm_output *output;
2233 struct drm_mode *drm_mode;
2234 int ret;
2235
2236 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2237 drm_mode = (struct drm_mode *) output->base.current;
2238 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002239 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002240 &output->connector_id, 1,
2241 &drm_mode->mode_info);
2242 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002243 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002244 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002245 drm_mode->base.width, drm_mode->base.height,
2246 output->base.x, output->base.y);
2247 }
2248 }
2249}
2250
2251static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002252vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002253{
2254 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002255 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002256 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002257 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002258
2259 switch (event) {
2260 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002261 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002262 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002263 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002264 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002265 wl_display_terminate(compositor->wl_display);
2266 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002267 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002268 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002269 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002270 wl_list_for_each(seat, &compositor->seat_list, link) {
2271 evdev_add_devices(ec->udev, seat);
2272 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002273 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002274 break;
2275 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002276 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002277 wl_list_for_each(seat, &compositor->seat_list, link) {
2278 evdev_disable_udev_monitor(seat);
2279 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002280 }
2281
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002282 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002283 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002284 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002285
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002286 /* If we have a repaint scheduled (either from a
2287 * pending pageflip or the idle handler), make sure we
2288 * cancel that so we don't try to pageflip when we're
2289 * vt switched away. The SLEEPING state will prevent
2290 * further attemps at repainting. When we switch
2291 * back, we schedule a repaint, which will process
2292 * pending frame callbacks. */
2293
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002294 wl_list_for_each(output, &ec->base.output_list, base.link) {
2295 output->base.repaint_needed = 0;
2296 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002297 }
2298
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002299 output = container_of(ec->base.output_list.next,
2300 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002301
2302 wl_list_for_each(sprite, &ec->sprite_list, link)
2303 drmModeSetPlane(ec->drm.fd,
2304 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002305 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002306 0, 0, 0, 0, 0, 0, 0, 0);
2307
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002308 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002309 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002310
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002311 break;
2312 };
2313}
2314
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002315static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002316switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002317{
2318 struct drm_compositor *ec = data;
2319
Daniel Stone325fc2d2012-05-30 16:31:58 +01002320 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002321}
2322
David Herrmann0af066f2012-10-29 19:21:16 +01002323/*
2324 * Find primary GPU
2325 * Some systems may have multiple DRM devices attached to a single seat. This
2326 * function loops over all devices and tries to find a PCI device with the
2327 * boot_vga sysfs attribute set to 1.
2328 * If no such device is found, the first DRM device reported by udev is used.
2329 */
2330static struct udev_device*
2331find_primary_gpu(struct drm_compositor *ec, const char *seat)
2332{
2333 struct udev_enumerate *e;
2334 struct udev_list_entry *entry;
2335 const char *path, *device_seat, *id;
2336 struct udev_device *device, *drm_device, *pci;
2337
2338 e = udev_enumerate_new(ec->udev);
2339 udev_enumerate_add_match_subsystem(e, "drm");
2340 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2341
2342 udev_enumerate_scan_devices(e);
2343 drm_device = NULL;
2344 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2345 path = udev_list_entry_get_name(entry);
2346 device = udev_device_new_from_syspath(ec->udev, path);
2347 if (!device)
2348 continue;
2349 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2350 if (!device_seat)
2351 device_seat = default_seat;
2352 if (strcmp(device_seat, seat)) {
2353 udev_device_unref(device);
2354 continue;
2355 }
2356
2357 pci = udev_device_get_parent_with_subsystem_devtype(device,
2358 "pci", NULL);
2359 if (pci) {
2360 id = udev_device_get_sysattr_value(pci, "boot_vga");
2361 if (id && !strcmp(id, "1")) {
2362 if (drm_device)
2363 udev_device_unref(drm_device);
2364 drm_device = device;
2365 break;
2366 }
2367 }
2368
2369 if (!drm_device)
2370 drm_device = device;
2371 else
2372 udev_device_unref(device);
2373 }
2374
2375 udev_enumerate_unref(e);
2376 return drm_device;
2377}
2378
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002379static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002380planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002381{
2382 struct drm_compositor *c = data;
2383
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002384 switch (key) {
2385 case KEY_C:
2386 c->cursors_are_broken ^= 1;
2387 break;
2388 case KEY_V:
2389 c->sprites_are_broken ^= 1;
2390 break;
2391 case KEY_O:
2392 c->sprites_hidden ^= 1;
2393 break;
2394 default:
2395 break;
2396 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002397}
2398
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002399static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002400drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002401 int connector, const char *seat, int tty, int pixman,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002402 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002403{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002404 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002405 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002406 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002407 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002408 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002409 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002410
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002411 weston_log("initializing drm backend\n");
2412
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002413 ec = malloc(sizeof *ec);
2414 if (ec == NULL)
2415 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002416 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002417
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002418 /* KMS support for sprites is not complete yet, so disable the
2419 * functionality for now. */
2420 ec->sprites_are_broken = 1;
2421
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002422 ec->use_pixman = pixman;
2423
Daniel Stone725c2c32012-06-22 14:04:36 +01002424 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002425 config_file) < 0) {
2426 weston_log("weston_compositor_init failed\n");
2427 goto err_base;
2428 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002429
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002430 ec->udev = udev_new();
2431 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002432 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002433 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002434 }
2435
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002436 ec->base.wl_display = display;
2437 ec->tty = tty_create(&ec->base, vt_func, tty);
2438 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002439 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002440 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002441 }
2442
David Herrmann0af066f2012-10-29 19:21:16 +01002443 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002444 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002445 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002446 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002447 }
David Herrmann0af066f2012-10-29 19:21:16 +01002448 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002449
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002450 if (init_drm(ec, drm_device) < 0) {
2451 weston_log("failed to initialize kms\n");
2452 goto err_udev_dev;
2453 }
2454
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002455 if (ec->use_pixman) {
2456 if (init_pixman(ec) < 0) {
2457 weston_log("failed to initialize pixman renderer\n");
2458 goto err_udev_dev;
2459 }
2460 } else {
2461 if (init_egl(ec) < 0) {
2462 weston_log("failed to initialize egl\n");
2463 goto err_udev_dev;
2464 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002465 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002466
2467 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002468 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002469
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002470 ec->base.focus = 1;
2471
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002472 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002473
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002474 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002475 weston_compositor_add_key_binding(&ec->base, key,
2476 MODIFIER_CTRL | MODIFIER_ALT,
2477 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002478
Jesse Barnes58ef3792012-02-23 09:45:49 -05002479 wl_list_init(&ec->sprite_list);
2480 create_sprites(ec);
2481
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002482 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002483 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002484 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002485 }
2486
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002487 path = NULL;
2488
Tiago Vignattice03ec32011-12-19 01:14:03 +02002489 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002490
2491 loop = wl_display_get_event_loop(ec->base.wl_display);
2492 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002493 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002494 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002495
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002496 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2497 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002498 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002499 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002500 }
2501 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2502 "drm", NULL);
2503 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002504 wl_event_loop_add_fd(loop,
2505 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002506 WL_EVENT_READABLE, udev_drm_event, ec);
2507
2508 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002509 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002510 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002511 }
2512
Daniel Stonea96b93c2012-06-22 14:04:37 +01002513 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002514
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002515 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002516 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002517 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002518 planes_binding, ec);
2519 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2520 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002521
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002522 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002523
2524err_udev_monitor:
2525 wl_event_source_remove(ec->udev_drm_source);
2526 udev_monitor_unref(ec->udev_monitor);
2527err_drm_source:
2528 wl_event_source_remove(ec->drm_source);
2529 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2530 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002531err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002532 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002533 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002534 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002535err_udev_dev:
2536 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002537err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002538 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2539 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002540 tty_destroy(ec->tty);
2541err_udev:
2542 udev_unref(ec->udev);
2543err_compositor:
2544 weston_compositor_shutdown(&ec->base);
2545err_base:
2546 free(ec);
2547 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002548}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002549
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002550static int
2551set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2552{
2553 mode->flags = 0;
2554
2555 if (strcmp(hsync, "+hsync") == 0)
2556 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2557 else if (strcmp(hsync, "-hsync") == 0)
2558 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2559 else
2560 return -1;
2561
2562 if (strcmp(vsync, "+vsync") == 0)
2563 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2564 else if (strcmp(vsync, "-vsync") == 0)
2565 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2566 else
2567 return -1;
2568
2569 return 0;
2570}
2571
2572static int
2573check_for_modeline(struct drm_configured_output *output)
2574{
2575 drmModeModeInfo mode;
2576 char hsync[16];
2577 char vsync[16];
2578 char mode_name[16];
2579 float fclock;
2580
2581 mode.type = DRM_MODE_TYPE_USERDEF;
2582 mode.hskew = 0;
2583 mode.vscan = 0;
2584 mode.vrefresh = 0;
2585
2586 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2587 &fclock, &mode.hdisplay,
2588 &mode.hsync_start,
2589 &mode.hsync_end, &mode.htotal,
2590 &mode.vdisplay,
2591 &mode.vsync_start,
2592 &mode.vsync_end, &mode.vtotal,
2593 hsync, vsync) == 11) {
2594 if (set_sync_flags(&mode, hsync, vsync))
2595 return -1;
2596
2597 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2598 strcpy(mode.name, mode_name);
2599
2600 mode.clock = fclock * 1000;
2601 } else
2602 return -1;
2603
2604 output->crtc_mode = mode;
2605
2606 return 0;
2607}
2608
Scott Moreau8ab5d452012-07-30 19:51:08 -06002609static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002610drm_output_set_transform(struct drm_configured_output *output)
2611{
2612 if (!output_transform) {
2613 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2614 return;
2615 }
2616
2617 if (!strcmp(output_transform, "normal"))
2618 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2619 else if (!strcmp(output_transform, "90"))
2620 output->transform = WL_OUTPUT_TRANSFORM_90;
2621 else if (!strcmp(output_transform, "180"))
2622 output->transform = WL_OUTPUT_TRANSFORM_180;
2623 else if (!strcmp(output_transform, "270"))
2624 output->transform = WL_OUTPUT_TRANSFORM_270;
2625 else if (!strcmp(output_transform, "flipped"))
2626 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2627 else if (!strcmp(output_transform, "flipped-90"))
2628 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2629 else if (!strcmp(output_transform, "flipped-180"))
2630 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2631 else if (!strcmp(output_transform, "flipped-270"))
2632 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2633 else {
2634 weston_log("Invalid transform \"%s\" for output %s\n",
2635 output_transform, output_name);
2636 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2637 }
2638
2639 free(output_transform);
2640 output_transform = NULL;
2641}
2642
2643static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002644output_section_done(void *data)
2645{
2646 struct drm_configured_output *output;
2647
2648 output = malloc(sizeof *output);
2649
Scott Moreau1bad5db2012-08-18 01:04:05 -06002650 if (!output || !output_name || (output_name[0] == 'X') ||
2651 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002652 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002653 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002654 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002655 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002656 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002657 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002658 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002659 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002660 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002661
2662 output->config = OUTPUT_CONFIG_INVALID;
2663 output->name = output_name;
2664 output->mode = output_mode;
2665
Scott Moreau1bad5db2012-08-18 01:04:05 -06002666 if (output_mode) {
2667 if (strcmp(output_mode, "off") == 0)
2668 output->config = OUTPUT_CONFIG_OFF;
2669 else if (strcmp(output_mode, "preferred") == 0)
2670 output->config = OUTPUT_CONFIG_PREFERRED;
2671 else if (strcmp(output_mode, "current") == 0)
2672 output->config = OUTPUT_CONFIG_CURRENT;
2673 else if (sscanf(output_mode, "%dx%d",
2674 &output->width, &output->height) == 2)
2675 output->config = OUTPUT_CONFIG_MODE;
2676 else if (check_for_modeline(output) == 0)
2677 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002678
Scott Moreau1bad5db2012-08-18 01:04:05 -06002679 if (output->config == OUTPUT_CONFIG_INVALID)
2680 weston_log("Invalid mode \"%s\" for output %s\n",
2681 output_mode, output_name);
2682 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002683 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002684
2685 drm_output_set_transform(output);
2686
2687 wl_list_insert(&configured_output_list, &output->link);
2688
2689 if (output_transform)
2690 free(output_transform);
2691 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002692}
2693
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002694WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002695backend_init(struct wl_display *display, int argc, char *argv[],
2696 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002697{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002698 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002699 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002700
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002701 const struct weston_option drm_options[] = {
2702 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2703 { WESTON_OPTION_STRING, "seat", 0, &seat },
2704 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002705 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002706 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002707 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002708
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002709 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002710
Scott Moreau8ab5d452012-07-30 19:51:08 -06002711 wl_list_init(&configured_output_list);
2712
2713 const struct config_key drm_config_keys[] = {
2714 { "name", CONFIG_KEY_STRING, &output_name },
2715 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002716 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002717 };
2718
2719 const struct config_section config_section[] = {
2720 { "output", drm_config_keys,
2721 ARRAY_LENGTH(drm_config_keys), output_section_done },
2722 };
2723
2724 parse_config_file(config_file, config_section,
2725 ARRAY_LENGTH(config_section), NULL);
2726
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002727 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2728 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002729}