blob: da36cd3f2f1fd13097d2c9d2a1587bdc7af7efb6 [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>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010043#include "gl-renderer.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020044#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010045#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046
Kristian Høgsberg061c4252012-06-28 11:28:15 -040047static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060048static char *output_name;
49static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060050static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060051static struct wl_list configured_output_list;
52
53enum output_config {
54 OUTPUT_CONFIG_INVALID = 0,
55 OUTPUT_CONFIG_OFF,
56 OUTPUT_CONFIG_PREFERRED,
57 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060058 OUTPUT_CONFIG_MODE,
59 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060060};
61
62struct drm_configured_output {
63 char *name;
64 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060065 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060066 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060067 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060068 enum output_config config;
69 struct wl_list link;
70};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040071
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050073 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
75 struct udev *udev;
76 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040077
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010078 struct udev_monitor *udev_monitor;
79 struct wl_event_source *udev_drm_source;
80
Benjamin Franzke2af7f102011-03-02 11:14:59 +010081 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010082 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 int fd;
84 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020085 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050086 uint32_t *crtcs;
87 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050088 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010089 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050090 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020091
Rob Clark4339add2012-08-09 14:18:28 -050092 /* we need these parameters in order to not fail drmModeAddFB2()
93 * due to out of bounds dimensions, and then mistakenly set
94 * sprites_are_broken:
95 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020096 uint32_t min_width, max_width;
97 uint32_t min_height, max_height;
98 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050099
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500101 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200102 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103
Rob Clarkab5b1e32012-08-09 13:24:45 -0500104 int cursors_are_broken;
105
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400107};
108
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500110 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400111 drmModeModeInfo mode_info;
112};
113
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114struct drm_output;
115
116struct drm_fb {
117 struct gbm_bo *bo;
118 struct drm_output *output;
119 uint32_t fb_id;
120 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200121 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300122};
123
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400124struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500125 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400127 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400128 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500129 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400130 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700131 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200132
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300133 int vblank_pending;
134 int page_flip_pending;
135
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400136 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400137 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400138 struct weston_plane cursor_plane;
139 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400140 struct weston_surface *cursor_surface;
141 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300142 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200143 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144};
145
Jesse Barnes58ef3792012-02-23 09:45:49 -0500146/*
147 * An output has a primary display plane plus zero or more sprites for
148 * blending display contents.
149 */
150struct drm_sprite {
151 struct wl_list link;
152
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400153 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500154
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200155 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300156 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500157 struct drm_compositor *compositor;
158
Jesse Barnes58ef3792012-02-23 09:45:49 -0500159 uint32_t possible_crtcs;
160 uint32_t plane_id;
161 uint32_t count_formats;
162
163 int32_t src_x, src_y;
164 uint32_t src_w, src_h;
165 uint32_t dest_x, dest_y;
166 uint32_t dest_w, dest_h;
167
168 uint32_t formats[];
169};
170
Pekka Paalanen33156972012-08-03 13:30:30 -0400171struct drm_seat {
172 struct weston_seat base;
173 struct wl_list devices_list;
174 struct udev_monitor *udev_monitor;
175 struct wl_event_source *udev_monitor_source;
176 char *seat_id;
177};
178
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400179static void
180drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400181
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
184{
185 struct weston_compositor *ec = output_base->compositor;
186 struct drm_compositor *c =(struct drm_compositor *) ec;
187 struct drm_output *output = (struct drm_output *) output_base;
188 int crtc;
189
190 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
191 if (c->crtcs[crtc] != output->crtc_id)
192 continue;
193
194 if (supported & (1 << crtc))
195 return -1;
196 }
197
198 return 0;
199}
200
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300201static void
202drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
203{
204 struct drm_fb *fb = data;
205 struct gbm_device *gbm = gbm_bo_get_device(bo);
206
207 if (fb->fb_id)
208 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
209
Pekka Paalanende685b82012-12-04 15:58:12 +0200210 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300211
212 free(data);
213}
214
215static struct drm_fb *
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200216drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_compositor *compositor)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300217{
218 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200219 uint32_t width, height, stride, handle, format;
220 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300221 int ret;
222
223 if (fb)
224 return fb;
225
226 fb = malloc(sizeof *fb);
227
228 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300229 fb->is_client_buffer = 0;
Pekka Paalanende685b82012-12-04 15:58:12 +0200230 fb->buffer_ref.buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300231
232 width = gbm_bo_get_width(bo);
233 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400234 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300235 handle = gbm_bo_get_handle(bo).u32;
236
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200237 if (compositor->min_width > width || width > compositor->max_width ||
238 compositor->min_height > height ||
239 height > compositor->max_height) {
240 weston_log("bo geometry out of bounds\n");
241 goto err_free;
242 }
243
244 ret = -1;
245
246 format = gbm_bo_get_format(bo);
247
248 if (format && !compositor->no_addfb2) {
249 handles[0] = handle;
250 pitches[0] = stride;
251 offsets[0] = 0;
252
253 ret = drmModeAddFB2(compositor->drm.fd, width, height,
254 format, handles, pitches, offsets,
255 &fb->fb_id, 0);
256 if (ret) {
257 weston_log("addfb2 failed: %m\n");
258 compositor->no_addfb2 = 1;
259 compositor->sprites_are_broken = 1;
260 }
261 }
262
263 if (ret)
264 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
265 stride, handle, &fb->fb_id);
266
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300267 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200268 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200269 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300270 }
271
272 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
273
274 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200275
276err_free:
277 free(fb);
278 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300279}
280
281static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200282drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
283{
Pekka Paalanende685b82012-12-04 15:58:12 +0200284 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200285
286 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200287
Pekka Paalanende685b82012-12-04 15:58:12 +0200288 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200289}
290
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200291static int
292drm_output_check_scanout_format(struct drm_output *output,
293 struct weston_surface *es, struct gbm_bo *bo)
294{
295 int ret = 0;
296 uint32_t format;
297 pixman_region32_t r;
298
299 format = gbm_bo_get_format(bo);
300
301 if (format == GBM_FORMAT_XRGB8888)
302 ret = 1;
303 else if (format == GBM_FORMAT_ARGB8888) {
304 /* We can only scanout an ARGB buffer if the surface's
305 * opaque region covers the whole output */
306 pixman_region32_init(&r);
307 pixman_region32_subtract(&r, &output->base.region,
308 &es->opaque);
309
310 if (!pixman_region32_not_empty(&r))
311 ret = 1;
312
313 pixman_region32_fini(&r);
314 }
315
316 return ret;
317}
318
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400319static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400320drm_output_prepare_scanout_surface(struct weston_output *_output,
321 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500322{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400323 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500324 struct drm_compositor *c =
325 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200326 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500328
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500329 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200330 es->geometry.y != output->base.y ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200331 buffer == NULL ||
332 buffer->width != output->base.current->width ||
333 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200334 output->base.transform != es->buffer_transform ||
335 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400336 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500337
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400338 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200339 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500340
Rob Bradford9b101872012-09-14 23:25:41 +0100341 /* Unable to use the buffer for scanout */
342 if (!bo)
343 return NULL;
344
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200345 if (!drm_output_check_scanout_format(output, es, bo)) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300346 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400347 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300348 }
349
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200350 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300351 if (!output->next) {
352 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400353 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500355
Pekka Paalanende685b82012-12-04 15:58:12 +0200356 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500357
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400358 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500359}
360
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500361static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400362drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400363{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200364 struct drm_compositor *c =
365 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400367
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200368 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400369
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200370 pixman_region32_subtract(&c->base.primary_plane.damage,
371 &c->base.primary_plane.damage, damage);
372
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300373 bo = gbm_surface_lock_front_buffer(output->surface);
374 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200375 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400376 return;
377 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200381 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300382 gbm_surface_release_buffer(output->surface, bo);
383 return;
384 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400385}
386
387static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500388drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400389 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100390{
391 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500392 struct drm_compositor *compositor =
393 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500394 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400395 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500396 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100397
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300398 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400399 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300400 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400401 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100402
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400403 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300404 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400405 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300406 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400407 &output->connector_id, 1,
408 &mode->mode_info);
409 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200410 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400411 return;
412 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200413 }
414
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500415 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300416 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500417 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200418 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500419 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500420 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100421
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300422 output->page_flip_pending = 1;
423
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400424 drm_output_set_cursor(output);
425
Jesse Barnes58ef3792012-02-23 09:45:49 -0500426 /*
427 * Now, update all the sprite surfaces
428 */
429 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200430 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431 drmVBlank vbl = {
432 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
433 .request.sequence = 1,
434 };
435
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200436 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200437 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500438 continue;
439
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200440 if (s->next && !compositor->sprites_hidden)
441 fb_id = s->next->fb_id;
442
Jesse Barnes58ef3792012-02-23 09:45:49 -0500443 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200444 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500445 s->dest_x, s->dest_y,
446 s->dest_w, s->dest_h,
447 s->src_x, s->src_y,
448 s->src_w, s->src_h);
449 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200450 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500451 ret, strerror(errno));
452
Rob Clark5ca1a472012-08-08 20:27:37 -0500453 if (output->pipe > 0)
454 vbl.request.type |= DRM_VBLANK_SECONDARY;
455
Jesse Barnes58ef3792012-02-23 09:45:49 -0500456 /*
457 * Queue a vblank signal so we know when the surface
458 * becomes active on the display or has been replaced.
459 */
460 vbl.request.signal = (unsigned long)s;
461 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
462 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200463 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500464 ret, strerror(errno));
465 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300466
467 s->output = output;
468 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500469 }
470
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500471 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400472}
473
474static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500475vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
476 void *data)
477{
478 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300479 struct drm_output *output = s->output;
480 uint32_t msecs;
481
482 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500483
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200484 if (s->current)
485 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500486
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200487 s->current = s->next;
488 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300489
490 if (!output->page_flip_pending) {
491 msecs = sec * 1000 + usec / 1000;
492 weston_output_finish_frame(&output->base, msecs);
493 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500494}
495
496static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400497page_flip_handler(int fd, unsigned int frame,
498 unsigned int sec, unsigned int usec, void *data)
499{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200500 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400501 uint32_t msecs;
502
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300503 output->page_flip_pending = 0;
504
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300505 if (output->current) {
506 if (output->current->is_client_buffer)
507 gbm_bo_destroy(output->current->bo);
508 else
509 gbm_surface_release_buffer(output->surface,
510 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200511 }
512
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300513 output->current = output->next;
514 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400515
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300516 if (!output->vblank_pending) {
517 msecs = sec * 1000 + usec / 1000;
518 weston_output_finish_frame(&output->base, msecs);
519 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200520}
521
522static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500523drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
524{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400525 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500526
527 for (i = 0; i < s->count_formats; i++)
528 if (s->formats[i] == format)
529 return 1;
530
531 return 0;
532}
533
534static int
535drm_surface_transform_supported(struct weston_surface *es)
536{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400537 struct weston_matrix *matrix = &es->transform.matrix;
538 int i;
539
540 if (!es->transform.enabled)
541 return 1;
542
543 for (i = 0; i < 16; i++) {
544 switch (i) {
545 case 10:
546 case 15:
547 if (matrix->d[i] != 1.0)
548 return 0;
549 break;
550 case 0:
551 case 5:
552 case 12:
553 case 13:
554 break;
555 default:
556 if (matrix->d[i] != 0.0)
557 return 0;
558 break;
559 }
560 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500561
562 return 1;
563}
564
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400565static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500566drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400567 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500568{
569 struct weston_compositor *ec = output_base->compositor;
570 struct drm_compositor *c =(struct drm_compositor *) ec;
571 struct drm_sprite *s;
572 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574 pixman_region32_t dest_rect, src_rect;
575 pixman_box32_t *box;
576 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400577 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200579 if (output_base->transform != WL_OUTPUT_TRANSFORM_NORMAL)
580 return NULL;
581
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500582 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400583 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500584
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300585 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400586 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300587
Pekka Paalanende685b82012-12-04 15:58:12 +0200588 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400589 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500590
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200591 if (es->alpha != 1.0f)
592 return NULL;
593
Pekka Paalanende685b82012-12-04 15:58:12 +0200594 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500595 return NULL;
596
Jesse Barnes58ef3792012-02-23 09:45:49 -0500597 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400598 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600 wl_list_for_each(s, &c->sprite_list, link) {
601 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
602 continue;
603
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200604 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 found = 1;
606 break;
607 }
608 }
609
610 /* No sprites available */
611 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400612 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400614 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200615 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400616 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400617 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400618
Jesse Barnes58ef3792012-02-23 09:45:49 -0500619 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200621 if (!drm_surface_format_supported(s, format)) {
622 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400623 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 }
625
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200626 s->next = drm_fb_get_from_bo(bo, c);
627 if (!s->next) {
628 gbm_bo_destroy(bo);
629 return NULL;
630 }
631
Pekka Paalanende685b82012-12-04 15:58:12 +0200632 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500633
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400634 box = pixman_region32_extents(&es->transform.boundingbox);
635 s->plane.x = box->x1;
636 s->plane.y = box->y1;
637
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638 /*
639 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200640 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 * for us already).
642 */
643 pixman_region32_init(&dest_rect);
644 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
645 &output_base->region);
646 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
647 box = pixman_region32_extents(&dest_rect);
648 s->dest_x = box->x1;
649 s->dest_y = box->y1;
650 s->dest_w = box->x2 - box->x1;
651 s->dest_h = box->y2 - box->y1;
652 pixman_region32_fini(&dest_rect);
653
654 pixman_region32_init(&src_rect);
655 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
656 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400658
659 weston_surface_from_global_fixed(es,
660 wl_fixed_from_int(box->x1),
661 wl_fixed_from_int(box->y1),
662 &sx1, &sy1);
663 weston_surface_from_global_fixed(es,
664 wl_fixed_from_int(box->x2),
665 wl_fixed_from_int(box->y2),
666 &sx2, &sy2);
667
668 if (sx1 < 0)
669 sx1 = 0;
670 if (sy1 < 0)
671 sy1 = 0;
672 if (sx2 > wl_fixed_from_int(es->geometry.width))
673 sx2 = wl_fixed_from_int(es->geometry.width);
674 if (sy2 > wl_fixed_from_int(es->geometry.height))
675 sy2 = wl_fixed_from_int(es->geometry.height);
676
677 s->src_x = sx1 << 8;
678 s->src_y = sy1 << 8;
679 s->src_w = (sx2 - sx1) << 8;
680 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681 pixman_region32_fini(&src_rect);
682
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400683 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500684}
685
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400686static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400687drm_output_prepare_cursor_surface(struct weston_output *output_base,
688 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500689{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400690 struct drm_compositor *c =
691 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400692 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400693
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200694 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
695 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400696 if (output->cursor_surface)
697 return NULL;
698 if (es->output_mask != (1u << output_base->id))
699 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500700 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400701 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200702 if (es->buffer_ref.buffer == NULL ||
703 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400704 es->geometry.width > 64 || es->geometry.height > 64)
705 return NULL;
706
707 output->cursor_surface = es;
708
709 return &output->cursor_plane;
710}
711
712static void
713drm_output_set_cursor(struct drm_output *output)
714{
715 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400716 struct drm_compositor *c =
717 (struct drm_compositor *) output->base.compositor;
718 EGLint handle, stride;
719 struct gbm_bo *bo;
720 uint32_t buf[64 * 64];
721 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400722 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500723
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400724 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400725 if (es == NULL) {
726 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
727 return;
728 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500729
Pekka Paalanende685b82012-12-04 15:58:12 +0200730 if (es->buffer_ref.buffer &&
731 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400732 pixman_region32_fini(&output->cursor_plane.damage);
733 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400734 output->current_cursor ^= 1;
735 bo = output->cursor_bo[output->current_cursor];
736 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200737 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
738 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400739 for (i = 0; i < es->geometry.height; i++)
740 memcpy(buf + i * 64, s + i * stride,
741 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500742
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400743 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300744 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400745
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400746 handle = gbm_bo_get_handle(bo).s32;
747 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500748 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300749 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500750 c->cursors_are_broken = 1;
751 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400752 }
753
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400754 x = es->geometry.x - output->base.x;
755 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400756 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500757 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400758 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500759 c->cursors_are_broken = 1;
760 }
761
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400762 output->cursor_plane.x = x;
763 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400764 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500765}
766
Jesse Barnes58ef3792012-02-23 09:45:49 -0500767static void
768drm_assign_planes(struct weston_output *output)
769{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400770 struct drm_compositor *c =
771 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200772 struct drm_output *drm_output = (struct drm_output *) output;
773 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400774 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400776 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500777
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200778 /* Reset the opaque region of the planes */
779 pixman_region32_fini(&drm_output->cursor_plane.opaque);
780 pixman_region32_init(&drm_output->cursor_plane.opaque);
781 pixman_region32_fini(&drm_output->fb_plane.opaque);
782 pixman_region32_init(&drm_output->fb_plane.opaque);
783
784 wl_list_for_each (s, &c->sprite_list, link) {
785 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
786 continue;
787
788 pixman_region32_fini(&s->plane.opaque);
789 pixman_region32_init(&s->plane.opaque);
790 }
791
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792 /*
793 * Find a surface for each sprite in the output using some heuristics:
794 * 1) size
795 * 2) frequency of update
796 * 3) opacity (though some hw might support alpha blending)
797 * 4) clipping (this can be fixed with color keys)
798 *
799 * The idea is to save on blitting since this should save power.
800 * If we can get a large video surface on the sprite for example,
801 * the main display surface may not need to update at all, and
802 * the client buffer can be used directly for the sprite surface
803 * as we do for flipping full screen surfaces.
804 */
805 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400806 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400807 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808 pixman_region32_init(&surface_overlap);
809 pixman_region32_intersect(&surface_overlap, &overlap,
810 &es->transform.boundingbox);
811
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400812 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400813 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400814 next_plane = primary;
815 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400816 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400817 if (next_plane == NULL)
818 next_plane = drm_output_prepare_scanout_surface(output, es);
819 if (next_plane == NULL)
820 next_plane = drm_output_prepare_overlay_surface(output, es);
821 if (next_plane == NULL)
822 next_plane = primary;
823 weston_surface_move_to_plane(es, next_plane);
824 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500825 pixman_region32_union(&overlap, &overlap,
826 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400827
Jesse Barnes58ef3792012-02-23 09:45:49 -0500828 pixman_region32_fini(&surface_overlap);
829 }
830 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831}
832
Matt Roper361d2ad2011-08-29 13:52:23 -0700833static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500834drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700835{
836 struct drm_output *output = (struct drm_output *) output_base;
837 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200838 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700839 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700840
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200841 if (output->backlight)
842 backlight_destroy(output->backlight);
843
Matt Roper361d2ad2011-08-29 13:52:23 -0700844 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400845 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700846
847 /* Restore original CRTC state */
848 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200849 origcrtc->x, origcrtc->y,
850 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700851 drmModeFreeCrtc(origcrtc);
852
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200853 c->crtc_allocator &= ~(1 << output->crtc_id);
854 c->connector_allocator &= ~(1 << output->connector_id);
855
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100856 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100857
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400858 gbm_surface_destroy(output->surface);
859
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400860 weston_plane_release(&output->fb_plane);
861 weston_plane_release(&output->cursor_plane);
862
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500863 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200864 wl_list_remove(&output->base.link);
865
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400866 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700867 free(output);
868}
869
Alex Wub7b8bda2012-04-17 17:20:48 +0800870static struct drm_mode *
871choose_mode (struct drm_output *output, struct weston_mode *target_mode)
872{
873 struct drm_mode *tmp_mode = NULL, *mode;
874
875 if (output->base.current->width == target_mode->width &&
876 output->base.current->height == target_mode->height &&
877 (output->base.current->refresh == target_mode->refresh ||
878 target_mode->refresh == 0))
879 return (struct drm_mode *)output->base.current;
880
881 wl_list_for_each(mode, &output->base.mode_list, base.link) {
882 if (mode->mode_info.hdisplay == target_mode->width &&
883 mode->mode_info.vdisplay == target_mode->height) {
884 if (mode->mode_info.vrefresh == target_mode->refresh ||
885 target_mode->refresh == 0) {
886 return mode;
887 } else if (!tmp_mode)
888 tmp_mode = mode;
889 }
890 }
891
892 return tmp_mode;
893}
894
895static int
896drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
897{
898 struct drm_output *output;
899 struct drm_mode *drm_mode;
900 int ret;
901 struct drm_compositor *ec;
902 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800903
904 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200905 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800906 return -1;
907 }
908
909 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200910 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800911 return -1;
912 }
913
914 ec = (struct drm_compositor *)output_base->compositor;
915 output = (struct drm_output *)output_base;
916 drm_mode = choose_mode (output, mode);
917
918 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200919 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800920 return -1;
921 } else if (&drm_mode->base == output->base.current) {
922 return 0;
923 } else if (drm_mode->base.width == output->base.current->width &&
924 drm_mode->base.height == output->base.current->height) {
925 /* only change refresh value */
926 ret = drmModeSetCrtc(ec->drm.fd,
927 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300928 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800929 &output->connector_id, 1, &drm_mode->mode_info);
930
931 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200932 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800933 drm_mode->base.width,
934 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400935 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800936 ret = -1;
937 } else {
938 output->base.current->flags = 0;
939 output->base.current = &drm_mode->base;
940 drm_mode->base.flags =
941 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
942 ret = 0;
943 }
944
945 return ret;
946 }
947
948 drm_mode->base.flags =
949 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
950
951 surface = gbm_surface_create(ec->gbm,
952 drm_mode->base.width,
953 drm_mode->base.height,
954 GBM_FORMAT_XRGB8888,
955 GBM_BO_USE_SCANOUT |
956 GBM_BO_USE_RENDERING);
957 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200958 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800959 return -1;
960 }
961
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100962 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800963
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100964 if (!gl_renderer_output_create(&output->base, surface)) {
John Kåre Alsaker94659272012-11-13 19:10:18 +0100965 weston_log("failed to create renderer output\n");
966 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800967 }
968
969 ret = drmModeSetCrtc(ec->drm.fd,
970 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300971 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800972 &output->connector_id, 1, &drm_mode->mode_info);
973 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200974 weston_log("failed to set mode\n");
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100975 goto err_gl;
Alex Wub7b8bda2012-04-17 17:20:48 +0800976 }
977
978 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300979 if (output->current) {
980 if (output->current->is_client_buffer)
981 gbm_bo_destroy(output->current->bo);
982 else
983 gbm_surface_release_buffer(output->surface,
984 output->current->bo);
985 }
986 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800987
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300988 if (output->next) {
989 if (output->next->is_client_buffer)
990 gbm_bo_destroy(output->next->bo);
991 else
992 gbm_surface_release_buffer(output->surface,
993 output->next->bo);
994 }
995 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800996
Alex Wub7b8bda2012-04-17 17:20:48 +0800997 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800998 output->surface = surface;
999
1000 /*update output*/
1001 output->base.current = &drm_mode->base;
1002 output->base.dirty = 1;
1003 weston_output_move(&output->base, output->base.x, output->base.y);
1004 return 0;
1005
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001006err_gl:
1007 gl_renderer_output_destroy(&output->base);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001008err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +08001009 gbm_surface_destroy(surface);
1010 return -1;
1011}
1012
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001013static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001014on_drm_input(int fd, uint32_t mask, void *data)
1015{
1016 drmEventContext evctx;
1017
1018 memset(&evctx, 0, sizeof evctx);
1019 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1020 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001021 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001022 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001023
1024 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001025}
1026
1027static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001028init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001029{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001030 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001031 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001032
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001033 sysnum = udev_device_get_sysnum(device);
1034 if (sysnum)
1035 ec->drm.id = atoi(sysnum);
1036 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001037 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001038 return -1;
1039 }
1040
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001041 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001042 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001043 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001044 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001045 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001046 udev_device_get_devnode(device));
1047 return -1;
1048 }
1049
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001050 weston_log("using %s\n", filename);
1051
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001052 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001053 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001054
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001055 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001056 NULL) < 0) {
1057 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001058 return -1;
1059 }
1060
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001061 return 0;
1062}
1063
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001064static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001065drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1066{
1067 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001068 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001069
1070 mode = malloc(sizeof *mode);
1071 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001072 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001073
1074 mode->base.flags = 0;
1075 mode->base.width = info->hdisplay;
1076 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001077
1078 /* Calculate higher precision (mHz) refresh rate */
1079 refresh = (info->clock * 1000000LL / info->htotal +
1080 info->vtotal / 2) / info->vtotal;
1081
1082 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1083 refresh *= 2;
1084 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1085 refresh /= 2;
1086 if (info->vscan > 1)
1087 refresh /= info->vscan;
1088
1089 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001090 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001091
1092 if (info->type & DRM_MODE_TYPE_PREFERRED)
1093 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1094
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001095 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1096
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001097 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001098}
1099
1100static int
1101drm_subpixel_to_wayland(int drm_value)
1102{
1103 switch (drm_value) {
1104 default:
1105 case DRM_MODE_SUBPIXEL_UNKNOWN:
1106 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1107 case DRM_MODE_SUBPIXEL_NONE:
1108 return WL_OUTPUT_SUBPIXEL_NONE;
1109 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1110 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1111 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1112 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1113 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1114 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1115 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1116 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1117 }
1118}
1119
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001120/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001121static uint32_t
1122drm_get_backlight(struct drm_output *output)
1123{
1124 long brightness, max_brightness, norm;
1125
1126 brightness = backlight_get_brightness(output->backlight);
1127 max_brightness = backlight_get_max_brightness(output->backlight);
1128
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001129 /* convert it on a scale of 0 to 255 */
1130 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001131
1132 return (uint32_t) norm;
1133}
1134
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001135/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001136static void
1137drm_set_backlight(struct weston_output *output_base, uint32_t value)
1138{
1139 struct drm_output *output = (struct drm_output *) output_base;
1140 long max_brightness, new_brightness;
1141
1142 if (!output->backlight)
1143 return;
1144
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001145 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001146 return;
1147
1148 max_brightness = backlight_get_max_brightness(output->backlight);
1149
1150 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001151 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001152
1153 backlight_set_brightness(output->backlight, new_brightness);
1154}
1155
1156static drmModePropertyPtr
1157drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1158{
1159 drmModePropertyPtr props;
1160 int i;
1161
1162 for (i = 0; i < connector->count_props; i++) {
1163 props = drmModeGetProperty(fd, connector->props[i]);
1164 if (!props)
1165 continue;
1166
1167 if (!strcmp(props->name, name))
1168 return props;
1169
1170 drmModeFreeProperty(props);
1171 }
1172
1173 return NULL;
1174}
1175
1176static void
1177drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1178{
1179 struct drm_output *output = (struct drm_output *) output_base;
1180 struct weston_compositor *ec = output_base->compositor;
1181 struct drm_compositor *c = (struct drm_compositor *) ec;
1182 drmModeConnectorPtr connector;
1183 drmModePropertyPtr prop;
1184
1185 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1186 if (!connector)
1187 return;
1188
1189 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1190 if (!prop) {
1191 drmModeFreeConnector(connector);
1192 return;
1193 }
1194
1195 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1196 prop->prop_id, level);
1197 drmModeFreeProperty(prop);
1198 drmModeFreeConnector(connector);
1199}
1200
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001201static const char *connector_type_names[] = {
1202 "None",
1203 "VGA",
1204 "DVI",
1205 "DVI",
1206 "DVI",
1207 "Composite",
1208 "TV",
1209 "LVDS",
1210 "CTV",
1211 "DIN",
1212 "DP",
1213 "HDMI",
1214 "HDMI",
1215 "TV",
1216 "eDP",
1217};
1218
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001219static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001220find_crtc_for_connector(struct drm_compositor *ec,
1221 drmModeRes *resources, drmModeConnector *connector)
1222{
1223 drmModeEncoder *encoder;
1224 uint32_t possible_crtcs;
1225 int i, j;
1226
1227 for (j = 0; j < connector->count_encoders; j++) {
1228 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1229 if (encoder == NULL) {
1230 weston_log("Failed to get encoder.\n");
1231 return -1;
1232 }
1233 possible_crtcs = encoder->possible_crtcs;
1234 drmModeFreeEncoder(encoder);
1235
1236 for (i = 0; i < resources->count_crtcs; i++) {
1237 if (possible_crtcs & (1 << i) &&
1238 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1239 return i;
1240 }
1241 }
1242
1243 return -1;
1244}
1245
1246static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001247create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001248 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001249 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001250 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001251{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001252 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001253 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1254 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001255 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001256 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001257 drmModeModeInfo crtc_mode;
1258 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001259 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001260 char name[32];
1261 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001263 i = find_crtc_for_connector(ec, resources, connector);
1264 if (i < 0) {
1265 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001266 return -1;
1267 }
1268
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001269 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001270 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001271 return -1;
1272
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001273 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001274 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1275 output->base.make = "unknown";
1276 output->base.model = "unknown";
1277 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001278
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001279 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1280 type_name = connector_type_names[connector->connector_type];
1281 else
1282 type_name = "UNKNOWN";
1283 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1284 output->name = strdup(name);
1285
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001286 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001287 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001288 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001289 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001290 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001291
Matt Roper361d2ad2011-08-29 13:52:23 -07001292 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1293
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001294 /* Get the current mode on the crtc that's currently driving
1295 * this connector. */
1296 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001297 memset(&crtc_mode, 0, sizeof crtc_mode);
1298 if (encoder != NULL) {
1299 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1300 drmModeFreeEncoder(encoder);
1301 if (crtc == NULL)
1302 goto err_free;
1303 if (crtc->mode_valid)
1304 crtc_mode = crtc->mode;
1305 drmModeFreeCrtc(crtc);
1306 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001307
David Herrmann0f0d54e2011-12-08 17:05:45 +01001308 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001309 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1310 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001311 goto err_free;
1312 }
1313
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001314 preferred = NULL;
1315 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001316 configured = NULL;
1317
1318 wl_list_for_each(temp, &configured_output_list, link) {
1319 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001320 if (temp->mode)
1321 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001322 temp->name, temp->mode);
1323 o = temp;
1324 break;
1325 }
1326 }
1327
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001328 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001329 weston_log("Disabling output %s\n", o->name);
1330
1331 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1332 0, 0, 0, 0, 0, NULL);
1333 goto err_free;
1334 }
1335
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001336 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001337 if (o && o->config == OUTPUT_CONFIG_MODE &&
1338 o->width == drm_mode->base.width &&
1339 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001340 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001341 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001342 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001343 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001344 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001345 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001346
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001347 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001348 configured = drm_output_add_mode(output, &o->crtc_mode);
1349 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001350 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001351 current = configured;
1352 }
1353
Wang Quanxianacb805a2012-07-30 18:09:46 -04001354 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001355 current = drm_output_add_mode(output, &crtc_mode);
1356 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001357 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001358 }
1359
Scott Moreau8ab5d452012-07-30 19:51:08 -06001360 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1361 configured = current;
1362
Wang Quanxianacb805a2012-07-30 18:09:46 -04001363 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001364 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001365 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001366 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001367 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001368 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001369 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001370 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001371
1372 if (output->base.current == NULL) {
1373 weston_log("no available modes for %s\n", output->name);
1374 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001375 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001376
Wang Quanxianacb805a2012-07-30 18:09:46 -04001377 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1378
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001379 output->surface = gbm_surface_create(ec->gbm,
1380 output->base.current->width,
1381 output->base.current->height,
1382 GBM_FORMAT_XRGB8888,
1383 GBM_BO_USE_SCANOUT |
1384 GBM_BO_USE_RENDERING);
1385 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001386 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001387 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001388 }
1389
John Kåre Alsaker94659272012-11-13 19:10:18 +01001390 weston_output_init(&output->base, &ec->base, x, y,
1391 connector->mmWidth, connector->mmHeight,
1392 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1393
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001394 if (gl_renderer_output_create(&output->base, output->surface) < 0)
John Kåre Alsaker94659272012-11-13 19:10:18 +01001395 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001396
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001397 output->cursor_bo[0] =
1398 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1399 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1400 output->cursor_bo[1] =
1401 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1402 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001403 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1404 weston_log("cursor buffers unavailable, using gl cursors\n");
1405 ec->cursors_are_broken = 1;
1406 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001407
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001408 output->backlight = backlight_init(drm_device,
1409 connector->connector_type);
1410 if (output->backlight) {
1411 output->base.set_backlight = drm_set_backlight;
1412 output->base.backlight_current = drm_get_backlight(output);
1413 }
1414
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001415 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1416
Alex Wubd3354b2012-04-17 17:20:49 +08001417 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001418 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001419 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001420 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001421 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001422 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001423
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001424 weston_plane_init(&output->cursor_plane, 0, 0);
1425 weston_plane_init(&output->fb_plane, 0, 0);
1426
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001427 weston_log("Output %s, (connector %d, crtc %d)\n",
1428 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001429 wl_list_for_each(m, &output->base.mode_list, link)
1430 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1431 m->width, m->height, m->refresh / 1000.0,
1432 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1433 ", preferred" : "",
1434 m->flags & WL_OUTPUT_MODE_CURRENT ?
1435 ", current" : "",
1436 connector->count_modes == 0 ?
1437 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001438
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001439 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001440
John Kåre Alsaker94659272012-11-13 19:10:18 +01001441err_output:
1442 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001443 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001444err_free:
1445 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1446 base.link) {
1447 wl_list_remove(&drm_mode->base.link);
1448 free(drm_mode);
1449 }
1450
1451 drmModeFreeCrtc(output->original_crtc);
1452 ec->crtc_allocator &= ~(1 << output->crtc_id);
1453 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001454 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001455 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001456
David Herrmann0f0d54e2011-12-08 17:05:45 +01001457 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001458}
1459
Jesse Barnes58ef3792012-02-23 09:45:49 -05001460static void
1461create_sprites(struct drm_compositor *ec)
1462{
1463 struct drm_sprite *sprite;
1464 drmModePlaneRes *plane_res;
1465 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001466 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001467
1468 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1469 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001470 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001471 strerror(errno));
1472 return;
1473 }
1474
1475 for (i = 0; i < plane_res->count_planes; i++) {
1476 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1477 if (!plane)
1478 continue;
1479
1480 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1481 plane->count_formats));
1482 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001483 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001484 __func__);
1485 free(plane);
1486 continue;
1487 }
1488
1489 memset(sprite, 0, sizeof *sprite);
1490
1491 sprite->possible_crtcs = plane->possible_crtcs;
1492 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001493 sprite->current = NULL;
1494 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001495 sprite->compositor = ec;
1496 sprite->count_formats = plane->count_formats;
1497 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001498 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001499 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001500 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001501
1502 wl_list_insert(&ec->sprite_list, &sprite->link);
1503 }
1504
1505 free(plane_res->planes);
1506 free(plane_res);
1507}
1508
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001509static void
1510destroy_sprites(struct drm_compositor *compositor)
1511{
1512 struct drm_sprite *sprite, *next;
1513 struct drm_output *output;
1514
1515 output = container_of(compositor->base.output_list.next,
1516 struct drm_output, base.link);
1517
1518 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1519 drmModeSetPlane(compositor->drm.fd,
1520 sprite->plane_id,
1521 output->crtc_id, 0, 0,
1522 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001523 if (sprite->current)
1524 gbm_bo_destroy(sprite->current->bo);
1525 if (sprite->next)
1526 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001527 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001528 free(sprite);
1529 }
1530}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001531
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001532static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001533create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001534 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001535{
1536 drmModeConnector *connector;
1537 drmModeRes *resources;
1538 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001539 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001540
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001541 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001542 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001543 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001544 return -1;
1545 }
1546
Jesse Barnes58ef3792012-02-23 09:45:49 -05001547 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001548 if (!ec->crtcs) {
1549 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001550 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001551 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001552
Rob Clark4339add2012-08-09 14:18:28 -05001553 ec->min_width = resources->min_width;
1554 ec->max_width = resources->max_width;
1555 ec->min_height = resources->min_height;
1556 ec->max_height = resources->max_height;
1557
Jesse Barnes58ef3792012-02-23 09:45:49 -05001558 ec->num_crtcs = resources->count_crtcs;
1559 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1560
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001561 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001562 connector = drmModeGetConnector(ec->drm.fd,
1563 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001564 if (connector == NULL)
1565 continue;
1566
1567 if (connector->connection == DRM_MODE_CONNECTED &&
1568 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001569 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001570 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001571 connector, x, y,
1572 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001573 drmModeFreeConnector(connector);
1574 continue;
1575 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001576
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001577 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001578 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001579 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001580 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001581
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001582 drmModeFreeConnector(connector);
1583 }
1584
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001585 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001586 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001587 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001588 return -1;
1589 }
1590
1591 drmModeFreeResources(resources);
1592
1593 return 0;
1594}
1595
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001596static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001597update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001598{
1599 drmModeConnector *connector;
1600 drmModeRes *resources;
1601 struct drm_output *output, *next;
1602 int x = 0, y = 0;
1603 int x_offset = 0, y_offset = 0;
1604 uint32_t connected = 0, disconnects = 0;
1605 int i;
1606
1607 resources = drmModeGetResources(ec->drm.fd);
1608 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001609 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001610 return;
1611 }
1612
1613 /* collect new connects */
1614 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001615 int connector_id = resources->connectors[i];
1616
1617 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001618 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001619 continue;
1620
David Herrmann7551cff2011-12-08 17:05:43 +01001621 if (connector->connection != DRM_MODE_CONNECTED) {
1622 drmModeFreeConnector(connector);
1623 continue;
1624 }
1625
Benjamin Franzke117483d2011-08-30 11:38:26 +02001626 connected |= (1 << connector_id);
1627
1628 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001629 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001630 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001631 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001632
1633 /* XXX: not yet needed, we die with 0 outputs */
1634 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001635 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001636 else
1637 x = 0;
1638 y = 0;
1639 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001640 connector, x, y,
1641 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001642 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001643
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001644 }
1645 drmModeFreeConnector(connector);
1646 }
1647 drmModeFreeResources(resources);
1648
1649 disconnects = ec->connector_allocator & ~connected;
1650 if (disconnects) {
1651 wl_list_for_each_safe(output, next, &ec->base.output_list,
1652 base.link) {
1653 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001654 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001655 output->base.x - x_offset,
1656 output->base.y - y_offset);
1657 }
1658
1659 if (disconnects & (1 << output->connector_id)) {
1660 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001661 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001662 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001663 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001664 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001665 }
1666 }
1667 }
1668
1669 /* FIXME: handle zero outputs, without terminating */
1670 if (ec->connector_allocator == 0)
1671 wl_display_terminate(ec->base.wl_display);
1672}
1673
1674static int
David Herrmannd7488c22012-03-11 20:05:21 +01001675udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001676{
David Herrmannd7488c22012-03-11 20:05:21 +01001677 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001678 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001679
1680 sysnum = udev_device_get_sysnum(device);
1681 if (!sysnum || atoi(sysnum) != ec->drm.id)
1682 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001683
David Herrmann6ac52db2012-03-11 20:05:22 +01001684 val = udev_device_get_property_value(device, "HOTPLUG");
1685 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001686 return 0;
1687
David Herrmann6ac52db2012-03-11 20:05:22 +01001688 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001689}
1690
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001691static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001692udev_drm_event(int fd, uint32_t mask, void *data)
1693{
1694 struct drm_compositor *ec = data;
1695 struct udev_device *event;
1696
1697 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001698
David Herrmannd7488c22012-03-11 20:05:21 +01001699 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001700 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001701
1702 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001703
1704 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001705}
1706
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001707static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001708drm_restore(struct weston_compositor *ec)
1709{
1710 struct drm_compositor *d = (struct drm_compositor *) ec;
1711
1712 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1713 weston_log("failed to drop master: %m\n");
1714 tty_reset(d->tty);
1715}
1716
Pekka Paalanen33156972012-08-03 13:30:30 -04001717static const char default_seat[] = "seat0";
1718
1719static void
1720device_added(struct udev_device *udev_device, struct drm_seat *master)
1721{
1722 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001723 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001724 const char *devnode;
1725 const char *device_seat;
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001726 const char *calibration_values;
Pekka Paalanen33156972012-08-03 13:30:30 -04001727 int fd;
1728
1729 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1730 if (!device_seat)
1731 device_seat = default_seat;
1732
1733 if (strcmp(device_seat, master->seat_id))
1734 return;
1735
1736 c = master->base.compositor;
1737 devnode = udev_device_get_devnode(udev_device);
1738
1739 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001740 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001741 * read. mtdev_get() also expects this. */
1742 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1743 if (fd < 0) {
1744 weston_log("opening input device '%s' failed.\n", devnode);
1745 return;
1746 }
1747
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001748 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001749 if (!device) {
1750 close(fd);
1751 weston_log("not using input device '%s'.\n", devnode);
1752 return;
1753 }
1754
Rob Bradfordf4f58be2012-12-03 19:44:17 +00001755 calibration_values =
1756 udev_device_get_property_value(udev_device,
1757 "WL_CALIBRATION");
1758
1759 if (calibration_values && sscanf(calibration_values,
1760 "%f %f %f %f %f %f",
1761 &device->abs.calibration[0],
1762 &device->abs.calibration[1],
1763 &device->abs.calibration[2],
1764 &device->abs.calibration[3],
1765 &device->abs.calibration[4],
1766 &device->abs.calibration[5]) == 6) {
1767 device->abs.apply_calibration = 1;
1768 weston_log ("Applying calibration: %f %f %f %f %f %f\n",
1769 device->abs.calibration[0],
1770 device->abs.calibration[1],
1771 device->abs.calibration[2],
1772 device->abs.calibration[3],
1773 device->abs.calibration[4],
1774 device->abs.calibration[5]);
1775 }
1776
Pekka Paalanen33156972012-08-03 13:30:30 -04001777 wl_list_insert(master->devices_list.prev, &device->link);
1778}
1779
1780static void
1781evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1782{
1783 struct drm_seat *seat = (struct drm_seat *) seat_base;
1784 struct udev_enumerate *e;
1785 struct udev_list_entry *entry;
1786 struct udev_device *device;
1787 const char *path, *sysname;
1788
1789 e = udev_enumerate_new(udev);
1790 udev_enumerate_add_match_subsystem(e, "input");
1791 udev_enumerate_scan_devices(e);
1792 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1793 path = udev_list_entry_get_name(entry);
1794 device = udev_device_new_from_syspath(udev, path);
1795
1796 sysname = udev_device_get_sysname(device);
1797 if (strncmp("event", sysname, 5) != 0) {
1798 udev_device_unref(device);
1799 continue;
1800 }
1801
1802 device_added(device, seat);
1803
1804 udev_device_unref(device);
1805 }
1806 udev_enumerate_unref(e);
1807
1808 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1809
1810 if (wl_list_empty(&seat->devices_list)) {
1811 weston_log(
1812 "warning: no input devices on entering Weston. "
1813 "Possible causes:\n"
1814 "\t- no permissions to read /dev/input/event*\n"
1815 "\t- seats misconfigured "
1816 "(Weston backend option 'seat', "
1817 "udev device property ID_SEAT)\n");
1818 }
1819}
1820
1821static int
1822evdev_udev_handler(int fd, uint32_t mask, void *data)
1823{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001824 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001825 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001826 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001827 const char *action;
1828 const char *devnode;
1829
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001830 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001831 if (!udev_device)
1832 return 1;
1833
1834 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001835 if (!action)
1836 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001837
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001838 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1839 goto out;
1840
1841 if (!strcmp(action, "add")) {
1842 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001843 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001844 else if (!strcmp(action, "remove")) {
1845 devnode = udev_device_get_devnode(udev_device);
1846 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1847 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001848 weston_log("input device %s, %s removed\n",
1849 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001850 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001851 break;
1852 }
1853 }
1854
1855out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001856 udev_device_unref(udev_device);
1857
1858 return 0;
1859}
1860
1861static int
1862evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1863{
1864 struct drm_seat *master = (struct drm_seat *) seat_base;
1865 struct wl_event_loop *loop;
1866 struct weston_compositor *c = master->base.compositor;
1867 int fd;
1868
1869 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1870 if (!master->udev_monitor) {
1871 weston_log("udev: failed to create the udev monitor\n");
1872 return 0;
1873 }
1874
1875 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1876 "input", NULL);
1877
1878 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1879 weston_log("udev: failed to bind the udev monitor\n");
1880 udev_monitor_unref(master->udev_monitor);
1881 return 0;
1882 }
1883
1884 loop = wl_display_get_event_loop(c->wl_display);
1885 fd = udev_monitor_get_fd(master->udev_monitor);
1886 master->udev_monitor_source =
1887 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1888 evdev_udev_handler, master);
1889 if (!master->udev_monitor_source) {
1890 udev_monitor_unref(master->udev_monitor);
1891 return 0;
1892 }
1893
1894 return 1;
1895}
1896
1897static void
1898evdev_disable_udev_monitor(struct weston_seat *seat_base)
1899{
1900 struct drm_seat *seat = (struct drm_seat *) seat_base;
1901
1902 if (!seat->udev_monitor)
1903 return;
1904
1905 udev_monitor_unref(seat->udev_monitor);
1906 seat->udev_monitor = NULL;
1907 wl_event_source_remove(seat->udev_monitor_source);
1908 seat->udev_monitor_source = NULL;
1909}
1910
1911static void
1912drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1913{
1914 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001915 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001916
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001917 wl_list_for_each(device, &seat->devices_list, link)
1918 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001919}
1920
1921static void
1922evdev_input_create(struct weston_compositor *c, struct udev *udev,
1923 const char *seat_id)
1924{
1925 struct drm_seat *seat;
1926
1927 seat = malloc(sizeof *seat);
1928 if (seat == NULL)
1929 return;
1930
1931 memset(seat, 0, sizeof *seat);
1932 weston_seat_init(&seat->base, c);
1933 seat->base.led_update = drm_led_update;
1934
1935 wl_list_init(&seat->devices_list);
1936 seat->seat_id = strdup(seat_id);
1937 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1938 free(seat->seat_id);
1939 free(seat);
1940 return;
1941 }
1942
1943 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001944}
1945
1946static void
1947evdev_remove_devices(struct weston_seat *seat_base)
1948{
1949 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001950 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001951
1952 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001953 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001954
Pekka Paalanend8583512012-08-03 14:39:11 +03001955 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001956 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001957}
1958
1959static void
1960evdev_input_destroy(struct weston_seat *seat_base)
1961{
1962 struct drm_seat *seat = (struct drm_seat *) seat_base;
1963
1964 evdev_remove_devices(seat_base);
1965 evdev_disable_udev_monitor(&seat->base);
1966
1967 weston_seat_release(seat_base);
1968 free(seat->seat_id);
1969 free(seat);
1970}
1971
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001972static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001973drm_free_configured_output(struct drm_configured_output *output)
1974{
1975 free(output->name);
1976 free(output->mode);
1977 free(output);
1978}
1979
1980static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001981drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001982{
1983 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001984 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001985 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001986
Daniel Stone37816df2012-05-16 18:45:18 +01001987 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1988 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001989 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001990 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001991
1992 wl_event_source_remove(d->udev_drm_source);
1993 wl_event_source_remove(d->drm_source);
1994
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001995 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001996
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001997 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001998
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001999 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002000 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002001 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002002 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002003 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002004
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002005 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002006}
2007
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002008static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002009drm_compositor_set_modes(struct drm_compositor *compositor)
2010{
2011 struct drm_output *output;
2012 struct drm_mode *drm_mode;
2013 int ret;
2014
2015 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2016 drm_mode = (struct drm_mode *) output->base.current;
2017 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002018 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002019 &output->connector_id, 1,
2020 &drm_mode->mode_info);
2021 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002022 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002023 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002024 drm_mode->base.width, drm_mode->base.height,
2025 output->base.x, output->base.y);
2026 }
2027 }
2028}
2029
2030static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002031vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002032{
2033 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002034 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002035 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002036 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002037
2038 switch (event) {
2039 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002040 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002041 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002042 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002043 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002044 wl_display_terminate(compositor->wl_display);
2045 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002046 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002047 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002048 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002049 wl_list_for_each(seat, &compositor->seat_list, link) {
2050 evdev_add_devices(ec->udev, seat);
2051 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002052 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002053 break;
2054 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002055 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002056 wl_list_for_each(seat, &compositor->seat_list, link) {
2057 evdev_disable_udev_monitor(seat);
2058 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002059 }
2060
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002061 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002062 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002063 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002064
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002065 /* If we have a repaint scheduled (either from a
2066 * pending pageflip or the idle handler), make sure we
2067 * cancel that so we don't try to pageflip when we're
2068 * vt switched away. The SLEEPING state will prevent
2069 * further attemps at repainting. When we switch
2070 * back, we schedule a repaint, which will process
2071 * pending frame callbacks. */
2072
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002073 wl_list_for_each(output, &ec->base.output_list, base.link) {
2074 output->base.repaint_needed = 0;
2075 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002076 }
2077
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002078 output = container_of(ec->base.output_list.next,
2079 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002080
2081 wl_list_for_each(sprite, &ec->sprite_list, link)
2082 drmModeSetPlane(ec->drm.fd,
2083 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002084 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002085 0, 0, 0, 0, 0, 0, 0, 0);
2086
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002087 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002088 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002089
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002090 break;
2091 };
2092}
2093
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002094static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002095switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002096{
2097 struct drm_compositor *ec = data;
2098
Daniel Stone325fc2d2012-05-30 16:31:58 +01002099 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002100}
2101
David Herrmann0af066f2012-10-29 19:21:16 +01002102/*
2103 * Find primary GPU
2104 * Some systems may have multiple DRM devices attached to a single seat. This
2105 * function loops over all devices and tries to find a PCI device with the
2106 * boot_vga sysfs attribute set to 1.
2107 * If no such device is found, the first DRM device reported by udev is used.
2108 */
2109static struct udev_device*
2110find_primary_gpu(struct drm_compositor *ec, const char *seat)
2111{
2112 struct udev_enumerate *e;
2113 struct udev_list_entry *entry;
2114 const char *path, *device_seat, *id;
2115 struct udev_device *device, *drm_device, *pci;
2116
2117 e = udev_enumerate_new(ec->udev);
2118 udev_enumerate_add_match_subsystem(e, "drm");
2119 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2120
2121 udev_enumerate_scan_devices(e);
2122 drm_device = NULL;
2123 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2124 path = udev_list_entry_get_name(entry);
2125 device = udev_device_new_from_syspath(ec->udev, path);
2126 if (!device)
2127 continue;
2128 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2129 if (!device_seat)
2130 device_seat = default_seat;
2131 if (strcmp(device_seat, seat)) {
2132 udev_device_unref(device);
2133 continue;
2134 }
2135
2136 pci = udev_device_get_parent_with_subsystem_devtype(device,
2137 "pci", NULL);
2138 if (pci) {
2139 id = udev_device_get_sysattr_value(pci, "boot_vga");
2140 if (id && !strcmp(id, "1")) {
2141 if (drm_device)
2142 udev_device_unref(drm_device);
2143 drm_device = device;
2144 break;
2145 }
2146 }
2147
2148 if (!drm_device)
2149 drm_device = device;
2150 else
2151 udev_device_unref(device);
2152 }
2153
2154 udev_enumerate_unref(e);
2155 return drm_device;
2156}
2157
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002158static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002159planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002160{
2161 struct drm_compositor *c = data;
2162
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002163 switch (key) {
2164 case KEY_C:
2165 c->cursors_are_broken ^= 1;
2166 break;
2167 case KEY_V:
2168 c->sprites_are_broken ^= 1;
2169 break;
2170 case KEY_O:
2171 c->sprites_hidden ^= 1;
2172 break;
2173 default:
2174 break;
2175 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002176}
2177
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002178static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002179drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002180 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002181 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002182{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002183 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002184 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002185 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002186 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002187 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002188 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002189
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002190 weston_log("initializing drm backend\n");
2191
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002192 ec = malloc(sizeof *ec);
2193 if (ec == NULL)
2194 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002195 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002196
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002197 /* KMS support for sprites is not complete yet, so disable the
2198 * functionality for now. */
2199 ec->sprites_are_broken = 1;
2200
Daniel Stone725c2c32012-06-22 14:04:36 +01002201 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002202 config_file) < 0) {
2203 weston_log("weston_compositor_init failed\n");
2204 goto err_base;
2205 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002206
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002207 ec->udev = udev_new();
2208 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002209 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002210 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211 }
2212
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002213 ec->base.wl_display = display;
2214 ec->tty = tty_create(&ec->base, vt_func, tty);
2215 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002216 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002217 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002218 }
2219
David Herrmann0af066f2012-10-29 19:21:16 +01002220 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002221 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002222 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002223 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002224 }
David Herrmann0af066f2012-10-29 19:21:16 +01002225 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002226
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002227 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002228 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002229 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002230 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002231
2232 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002233 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002234
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002235 ec->base.focus = 1;
2236
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002237 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002238
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002239 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002240 weston_compositor_add_key_binding(&ec->base, key,
2241 MODIFIER_CTRL | MODIFIER_ALT,
2242 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002243
Jesse Barnes58ef3792012-02-23 09:45:49 -05002244 wl_list_init(&ec->sprite_list);
2245 create_sprites(ec);
2246
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002247 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002248 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002249 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002250 }
2251
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002252 path = NULL;
2253
Tiago Vignattice03ec32011-12-19 01:14:03 +02002254 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002255
2256 loop = wl_display_get_event_loop(ec->base.wl_display);
2257 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002258 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002259 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002260
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002261 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2262 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002263 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002264 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002265 }
2266 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2267 "drm", NULL);
2268 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002269 wl_event_loop_add_fd(loop,
2270 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002271 WL_EVENT_READABLE, udev_drm_event, ec);
2272
2273 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002274 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002275 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002276 }
2277
Daniel Stonea96b93c2012-06-22 14:04:37 +01002278 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002279
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002280 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002281 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002282 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002283 planes_binding, ec);
2284 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2285 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002286
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002287 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002288
2289err_udev_monitor:
2290 wl_event_source_remove(ec->udev_drm_source);
2291 udev_monitor_unref(ec->udev_monitor);
2292err_drm_source:
2293 wl_event_source_remove(ec->drm_source);
2294 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2295 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002296err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002297 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002298 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002299 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002300err_udev_dev:
2301 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002302err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002303 tty_destroy(ec->tty);
2304err_udev:
2305 udev_unref(ec->udev);
2306err_compositor:
2307 weston_compositor_shutdown(&ec->base);
2308err_base:
2309 free(ec);
2310 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002311}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002312
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002313static int
2314set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2315{
2316 mode->flags = 0;
2317
2318 if (strcmp(hsync, "+hsync") == 0)
2319 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2320 else if (strcmp(hsync, "-hsync") == 0)
2321 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2322 else
2323 return -1;
2324
2325 if (strcmp(vsync, "+vsync") == 0)
2326 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2327 else if (strcmp(vsync, "-vsync") == 0)
2328 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2329 else
2330 return -1;
2331
2332 return 0;
2333}
2334
2335static int
2336check_for_modeline(struct drm_configured_output *output)
2337{
2338 drmModeModeInfo mode;
2339 char hsync[16];
2340 char vsync[16];
2341 char mode_name[16];
2342 float fclock;
2343
2344 mode.type = DRM_MODE_TYPE_USERDEF;
2345 mode.hskew = 0;
2346 mode.vscan = 0;
2347 mode.vrefresh = 0;
2348
2349 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2350 &fclock, &mode.hdisplay,
2351 &mode.hsync_start,
2352 &mode.hsync_end, &mode.htotal,
2353 &mode.vdisplay,
2354 &mode.vsync_start,
2355 &mode.vsync_end, &mode.vtotal,
2356 hsync, vsync) == 11) {
2357 if (set_sync_flags(&mode, hsync, vsync))
2358 return -1;
2359
2360 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2361 strcpy(mode.name, mode_name);
2362
2363 mode.clock = fclock * 1000;
2364 } else
2365 return -1;
2366
2367 output->crtc_mode = mode;
2368
2369 return 0;
2370}
2371
Scott Moreau8ab5d452012-07-30 19:51:08 -06002372static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002373drm_output_set_transform(struct drm_configured_output *output)
2374{
2375 if (!output_transform) {
2376 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2377 return;
2378 }
2379
2380 if (!strcmp(output_transform, "normal"))
2381 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2382 else if (!strcmp(output_transform, "90"))
2383 output->transform = WL_OUTPUT_TRANSFORM_90;
2384 else if (!strcmp(output_transform, "180"))
2385 output->transform = WL_OUTPUT_TRANSFORM_180;
2386 else if (!strcmp(output_transform, "270"))
2387 output->transform = WL_OUTPUT_TRANSFORM_270;
2388 else if (!strcmp(output_transform, "flipped"))
2389 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2390 else if (!strcmp(output_transform, "flipped-90"))
2391 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2392 else if (!strcmp(output_transform, "flipped-180"))
2393 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2394 else if (!strcmp(output_transform, "flipped-270"))
2395 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2396 else {
2397 weston_log("Invalid transform \"%s\" for output %s\n",
2398 output_transform, output_name);
2399 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2400 }
2401
2402 free(output_transform);
2403 output_transform = NULL;
2404}
2405
2406static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002407output_section_done(void *data)
2408{
2409 struct drm_configured_output *output;
2410
2411 output = malloc(sizeof *output);
2412
Scott Moreau1bad5db2012-08-18 01:04:05 -06002413 if (!output || !output_name || (output_name[0] == 'X') ||
2414 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002415 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002416 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002417 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002418 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002419 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002420 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002421 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002422 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002423 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002424
2425 output->config = OUTPUT_CONFIG_INVALID;
2426 output->name = output_name;
2427 output->mode = output_mode;
2428
Scott Moreau1bad5db2012-08-18 01:04:05 -06002429 if (output_mode) {
2430 if (strcmp(output_mode, "off") == 0)
2431 output->config = OUTPUT_CONFIG_OFF;
2432 else if (strcmp(output_mode, "preferred") == 0)
2433 output->config = OUTPUT_CONFIG_PREFERRED;
2434 else if (strcmp(output_mode, "current") == 0)
2435 output->config = OUTPUT_CONFIG_CURRENT;
2436 else if (sscanf(output_mode, "%dx%d",
2437 &output->width, &output->height) == 2)
2438 output->config = OUTPUT_CONFIG_MODE;
2439 else if (check_for_modeline(output) == 0)
2440 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002441
Scott Moreau1bad5db2012-08-18 01:04:05 -06002442 if (output->config == OUTPUT_CONFIG_INVALID)
2443 weston_log("Invalid mode \"%s\" for output %s\n",
2444 output_mode, output_name);
2445 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002446 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002447
2448 drm_output_set_transform(output);
2449
2450 wl_list_insert(&configured_output_list, &output->link);
2451
2452 if (output_transform)
2453 free(output_transform);
2454 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002455}
2456
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002457WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002458backend_init(struct wl_display *display, int argc, char *argv[],
2459 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002460{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002461 int connector = 0, tty = 0;
2462 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002463
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002464 const struct weston_option drm_options[] = {
2465 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2466 { WESTON_OPTION_STRING, "seat", 0, &seat },
2467 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002468 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002469 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002470
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002471 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002472
Scott Moreau8ab5d452012-07-30 19:51:08 -06002473 wl_list_init(&configured_output_list);
2474
2475 const struct config_key drm_config_keys[] = {
2476 { "name", CONFIG_KEY_STRING, &output_name },
2477 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002478 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002479 };
2480
2481 const struct config_section config_section[] = {
2482 { "output", drm_config_keys,
2483 ARRAY_LENGTH(drm_config_keys), output_section_done },
2484 };
2485
2486 parse_config_file(config_file, config_section,
2487 ARRAY_LENGTH(config_section), NULL);
2488
Daniel Stonec1be8e52012-06-01 11:14:02 -04002489 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2490 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002491}