blob: f7b8d68e087e0332f6f21eca4fca45bfa116705b [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"
Tiago Vignattice03ec32011-12-19 01:14:03 +020043#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010044#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Kristian Høgsberg061c4252012-06-28 11:28:15 -040046static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060047static char *output_name;
48static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060049static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060050static struct wl_list configured_output_list;
51
52enum output_config {
53 OUTPUT_CONFIG_INVALID = 0,
54 OUTPUT_CONFIG_OFF,
55 OUTPUT_CONFIG_PREFERRED,
56 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060057 OUTPUT_CONFIG_MODE,
58 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060059};
60
61struct drm_configured_output {
62 char *name;
63 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060064 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060066 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060067 enum output_config config;
68 struct wl_list link;
69};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040070
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050072 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
74 struct udev *udev;
75 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010077 struct udev_monitor *udev_monitor;
78 struct wl_event_source *udev_drm_source;
79
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010081 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 int fd;
83 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020084 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050085 uint32_t *crtcs;
86 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050087 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010088 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050089 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020095 uint32_t min_width, max_width;
96 uint32_t min_height, max_height;
97 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050098
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200101 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102
Rob Clarkab5b1e32012-08-09 13:24:45 -0500103 int cursors_are_broken;
104
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200105 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400106};
107
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400108struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500109 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400110 drmModeModeInfo mode_info;
111};
112
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300113struct drm_output;
114
115struct drm_fb {
116 struct gbm_bo *bo;
117 struct drm_output *output;
118 uint32_t fb_id;
119 int is_client_buffer;
120 struct wl_buffer *buffer;
121 struct wl_listener buffer_destroy_listener;
122};
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
210 if (fb->buffer) {
211 weston_buffer_post_release(fb->buffer);
212 wl_list_remove(&fb->buffer_destroy_listener.link);
213 }
214
215 free(data);
216}
217
218static struct drm_fb *
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200219drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_compositor *compositor)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300220{
221 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200222 uint32_t width, height, stride, handle, format;
223 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300224 int ret;
225
226 if (fb)
227 return fb;
228
229 fb = malloc(sizeof *fb);
230
231 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232 fb->is_client_buffer = 0;
233 fb->buffer = NULL;
234
235 width = gbm_bo_get_width(bo);
236 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400237 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300238 handle = gbm_bo_get_handle(bo).u32;
239
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200240 if (compositor->min_width > width || width > compositor->max_width ||
241 compositor->min_height > height ||
242 height > compositor->max_height) {
243 weston_log("bo geometry out of bounds\n");
244 goto err_free;
245 }
246
247 ret = -1;
248
249 format = gbm_bo_get_format(bo);
250
251 if (format && !compositor->no_addfb2) {
252 handles[0] = handle;
253 pitches[0] = stride;
254 offsets[0] = 0;
255
256 ret = drmModeAddFB2(compositor->drm.fd, width, height,
257 format, handles, pitches, offsets,
258 &fb->fb_id, 0);
259 if (ret) {
260 weston_log("addfb2 failed: %m\n");
261 compositor->no_addfb2 = 1;
262 compositor->sprites_are_broken = 1;
263 }
264 }
265
266 if (ret)
267 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
268 stride, handle, &fb->fb_id);
269
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300270 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200271 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200272 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300273 }
274
275 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
276
277 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200278
279err_free:
280 free(fb);
281 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300282}
283
284static void
285fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
286{
287 struct drm_fb *fb = container_of(listener, struct drm_fb,
288 buffer_destroy_listener);
289
290 fb->buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300291}
292
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200293static void
294drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
295{
296 assert(fb->buffer == NULL);
297
298 fb->is_client_buffer = 1;
299 fb->buffer = buffer;
300 fb->buffer->busy_count++;
301 fb->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
302
303 wl_signal_add(&fb->buffer->resource.destroy_signal,
304 &fb->buffer_destroy_listener);
305}
306
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400307static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400308drm_output_prepare_scanout_surface(struct weston_output *_output,
309 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500310{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400311 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500312 struct drm_compositor *c =
313 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300314 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500315
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500316 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200317 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200318 es->geometry.width != output->base.current->width ||
319 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200320 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400321 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400322 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500323
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400324 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
325 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500326
Rob Bradford9b101872012-09-14 23:25:41 +0100327 /* Unable to use the buffer for scanout */
328 if (!bo)
329 return NULL;
330
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300331 /* Need to verify output->region contained in surface opaque
332 * region. Or maybe just that format doesn't have alpha.
333 * For now, scanout only if format is XRGB8888. */
334 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
335 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400336 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300337 }
338
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200339 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300340 if (!output->next) {
341 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400342 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300343 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500344
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 drm_fb_set_buffer(output->next, es->buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500346
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400347 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500348}
349
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500350static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400351drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400352{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200353 struct drm_compositor *c =
354 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300355 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400356
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200357 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400358
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 bo = gbm_surface_lock_front_buffer(output->surface);
360 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200361 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400362 return;
363 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300364
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200365 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200367 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368 gbm_surface_release_buffer(output->surface, bo);
369 return;
370 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400371}
372
373static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500374drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400375 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100376{
377 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500378 struct drm_compositor *compositor =
379 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500380 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400381 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500382 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100383
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300384 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400385 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300386 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400387 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100388
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400389 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300390 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400391 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300392 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400393 &output->connector_id, 1,
394 &mode->mode_info);
395 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200396 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400397 return;
398 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200399 }
400
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500401 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300402 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500403 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200404 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500405 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500406 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100407
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300408 output->page_flip_pending = 1;
409
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400410 drm_output_set_cursor(output);
411
Jesse Barnes58ef3792012-02-23 09:45:49 -0500412 /*
413 * Now, update all the sprite surfaces
414 */
415 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200416 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500417 drmVBlank vbl = {
418 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
419 .request.sequence = 1,
420 };
421
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200422 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200423 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500424 continue;
425
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200426 if (s->next && !compositor->sprites_hidden)
427 fb_id = s->next->fb_id;
428
Jesse Barnes58ef3792012-02-23 09:45:49 -0500429 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200430 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431 s->dest_x, s->dest_y,
432 s->dest_w, s->dest_h,
433 s->src_x, s->src_y,
434 s->src_w, s->src_h);
435 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200436 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500437 ret, strerror(errno));
438
Rob Clark5ca1a472012-08-08 20:27:37 -0500439 if (output->pipe > 0)
440 vbl.request.type |= DRM_VBLANK_SECONDARY;
441
Jesse Barnes58ef3792012-02-23 09:45:49 -0500442 /*
443 * Queue a vblank signal so we know when the surface
444 * becomes active on the display or has been replaced.
445 */
446 vbl.request.signal = (unsigned long)s;
447 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
448 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200449 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500450 ret, strerror(errno));
451 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300452
453 s->output = output;
454 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500455 }
456
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500457 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400458}
459
460static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500461vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
462 void *data)
463{
464 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300465 struct drm_output *output = s->output;
466 uint32_t msecs;
467
468 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500469
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200470 if (s->current)
471 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500472
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200473 s->current = s->next;
474 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300475
476 if (!output->page_flip_pending) {
477 msecs = sec * 1000 + usec / 1000;
478 weston_output_finish_frame(&output->base, msecs);
479 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500480}
481
482static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400483page_flip_handler(int fd, unsigned int frame,
484 unsigned int sec, unsigned int usec, void *data)
485{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200486 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400487 uint32_t msecs;
488
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300489 output->page_flip_pending = 0;
490
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300491 if (output->current) {
492 if (output->current->is_client_buffer)
493 gbm_bo_destroy(output->current->bo);
494 else
495 gbm_surface_release_buffer(output->surface,
496 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200497 }
498
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 output->current = output->next;
500 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300502 if (!output->vblank_pending) {
503 msecs = sec * 1000 + usec / 1000;
504 weston_output_finish_frame(&output->base, msecs);
505 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200506}
507
508static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500509drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
510{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400511 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500512
513 for (i = 0; i < s->count_formats; i++)
514 if (s->formats[i] == format)
515 return 1;
516
517 return 0;
518}
519
520static int
521drm_surface_transform_supported(struct weston_surface *es)
522{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400523 struct weston_matrix *matrix = &es->transform.matrix;
524 int i;
525
526 if (!es->transform.enabled)
527 return 1;
528
529 for (i = 0; i < 16; i++) {
530 switch (i) {
531 case 10:
532 case 15:
533 if (matrix->d[i] != 1.0)
534 return 0;
535 break;
536 case 0:
537 case 5:
538 case 12:
539 case 13:
540 break;
541 default:
542 if (matrix->d[i] != 0.0)
543 return 0;
544 break;
545 }
546 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500547
548 return 1;
549}
550
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400551static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500552drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400553 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500554{
555 struct weston_compositor *ec = output_base->compositor;
556 struct drm_compositor *c =(struct drm_compositor *) ec;
557 struct drm_sprite *s;
558 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500559 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500560 pixman_region32_t dest_rect, src_rect;
561 pixman_box32_t *box;
562 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400563 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500564
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500565 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400566 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500567
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300568 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400569 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300570
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400571 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400572 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573
Rob Clark702ffae2012-08-09 14:18:27 -0500574 if (wl_buffer_is_shm(es->buffer))
575 return NULL;
576
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400578 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500579
Jesse Barnes58ef3792012-02-23 09:45:49 -0500580 wl_list_for_each(s, &c->sprite_list, link) {
581 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
582 continue;
583
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200584 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500585 found = 1;
586 break;
587 }
588 }
589
590 /* No sprites available */
591 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400592 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500593
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400594 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
595 es->buffer, GBM_BO_USE_SCANOUT);
596 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400597 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400598
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200601 if (!drm_surface_format_supported(s, format)) {
602 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400603 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604 }
605
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200606 s->next = drm_fb_get_from_bo(bo, c);
607 if (!s->next) {
608 gbm_bo_destroy(bo);
609 return NULL;
610 }
611
612 drm_fb_set_buffer(s->next, es->buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400614 box = pixman_region32_extents(&es->transform.boundingbox);
615 s->plane.x = box->x1;
616 s->plane.y = box->y1;
617
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 /*
619 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200620 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 * for us already).
622 */
623 pixman_region32_init(&dest_rect);
624 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
625 &output_base->region);
626 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
627 box = pixman_region32_extents(&dest_rect);
628 s->dest_x = box->x1;
629 s->dest_y = box->y1;
630 s->dest_w = box->x2 - box->x1;
631 s->dest_h = box->y2 - box->y1;
632 pixman_region32_fini(&dest_rect);
633
634 pixman_region32_init(&src_rect);
635 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
636 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500637 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400638
639 weston_surface_from_global_fixed(es,
640 wl_fixed_from_int(box->x1),
641 wl_fixed_from_int(box->y1),
642 &sx1, &sy1);
643 weston_surface_from_global_fixed(es,
644 wl_fixed_from_int(box->x2),
645 wl_fixed_from_int(box->y2),
646 &sx2, &sy2);
647
648 if (sx1 < 0)
649 sx1 = 0;
650 if (sy1 < 0)
651 sy1 = 0;
652 if (sx2 > wl_fixed_from_int(es->geometry.width))
653 sx2 = wl_fixed_from_int(es->geometry.width);
654 if (sy2 > wl_fixed_from_int(es->geometry.height))
655 sy2 = wl_fixed_from_int(es->geometry.height);
656
657 s->src_x = sx1 << 8;
658 s->src_y = sy1 << 8;
659 s->src_w = (sx2 - sx1) << 8;
660 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500661 pixman_region32_fini(&src_rect);
662
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400663 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500664}
665
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400666static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400667drm_output_prepare_cursor_surface(struct weston_output *output_base,
668 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500669{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400670 struct drm_compositor *c =
671 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400672 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400673
674 if (output->cursor_surface)
675 return NULL;
676 if (es->output_mask != (1u << output_base->id))
677 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500678 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400679 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400680 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
681 es->geometry.width > 64 || es->geometry.height > 64)
682 return NULL;
683
684 output->cursor_surface = es;
685
686 return &output->cursor_plane;
687}
688
689static void
690drm_output_set_cursor(struct drm_output *output)
691{
692 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400693 struct drm_compositor *c =
694 (struct drm_compositor *) output->base.compositor;
695 EGLint handle, stride;
696 struct gbm_bo *bo;
697 uint32_t buf[64 * 64];
698 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400699 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500700
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400701 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400702 if (es == NULL) {
703 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
704 return;
705 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500706
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400707 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
708 pixman_region32_fini(&output->cursor_plane.damage);
709 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400710 output->current_cursor ^= 1;
711 bo = output->cursor_bo[output->current_cursor];
712 memset(buf, 0, sizeof buf);
713 stride = wl_shm_buffer_get_stride(es->buffer);
714 s = wl_shm_buffer_get_data(es->buffer);
715 for (i = 0; i < es->geometry.height; i++)
716 memcpy(buf + i * 64, s + i * stride,
717 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500718
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400719 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300720 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400721
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400722 handle = gbm_bo_get_handle(bo).s32;
723 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500724 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300725 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500726 c->cursors_are_broken = 1;
727 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400728 }
729
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400730 x = es->geometry.x - output->base.x;
731 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400732 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500733 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400734 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500735 c->cursors_are_broken = 1;
736 }
737
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400738 output->cursor_plane.x = x;
739 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400740 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500741}
742
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743static void
744drm_assign_planes(struct weston_output *output)
745{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400746 struct drm_compositor *c =
747 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200748 struct drm_output *drm_output = (struct drm_output *) output;
749 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400750 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500751 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400752 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500753
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200754 /* Reset the opaque region of the planes */
755 pixman_region32_fini(&drm_output->cursor_plane.opaque);
756 pixman_region32_init(&drm_output->cursor_plane.opaque);
757 pixman_region32_fini(&drm_output->fb_plane.opaque);
758 pixman_region32_init(&drm_output->fb_plane.opaque);
759
760 wl_list_for_each (s, &c->sprite_list, link) {
761 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
762 continue;
763
764 pixman_region32_fini(&s->plane.opaque);
765 pixman_region32_init(&s->plane.opaque);
766 }
767
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768 /*
769 * Find a surface for each sprite in the output using some heuristics:
770 * 1) size
771 * 2) frequency of update
772 * 3) opacity (though some hw might support alpha blending)
773 * 4) clipping (this can be fixed with color keys)
774 *
775 * The idea is to save on blitting since this should save power.
776 * If we can get a large video surface on the sprite for example,
777 * the main display surface may not need to update at all, and
778 * the client buffer can be used directly for the sprite surface
779 * as we do for flipping full screen surfaces.
780 */
781 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400782 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400783 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500784 pixman_region32_init(&surface_overlap);
785 pixman_region32_intersect(&surface_overlap, &overlap,
786 &es->transform.boundingbox);
787
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400788 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400789 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400790 next_plane = primary;
791 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400792 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400793 if (next_plane == NULL)
794 next_plane = drm_output_prepare_scanout_surface(output, es);
795 if (next_plane == NULL)
796 next_plane = drm_output_prepare_overlay_surface(output, es);
797 if (next_plane == NULL)
798 next_plane = primary;
799 weston_surface_move_to_plane(es, next_plane);
800 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 pixman_region32_union(&overlap, &overlap,
802 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400803
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804 pixman_region32_fini(&surface_overlap);
805 }
806 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807}
808
Matt Roper361d2ad2011-08-29 13:52:23 -0700809static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500810drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700811{
812 struct drm_output *output = (struct drm_output *) output_base;
813 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200814 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700815 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700816
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200817 if (output->backlight)
818 backlight_destroy(output->backlight);
819
Matt Roper361d2ad2011-08-29 13:52:23 -0700820 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400821 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700822
823 /* Restore original CRTC state */
824 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200825 origcrtc->x, origcrtc->y,
826 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700827 drmModeFreeCrtc(origcrtc);
828
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200829 c->crtc_allocator &= ~(1 << output->crtc_id);
830 c->connector_allocator &= ~(1 << output->connector_id);
831
John Kåre Alsaker94659272012-11-13 19:10:18 +0100832 gles2_renderer_output_destroy(output_base);
833
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400834 gbm_surface_destroy(output->surface);
835
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400836 weston_plane_release(&output->fb_plane);
837 weston_plane_release(&output->cursor_plane);
838
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500839 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200840 wl_list_remove(&output->base.link);
841
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400842 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700843 free(output);
844}
845
Alex Wub7b8bda2012-04-17 17:20:48 +0800846static struct drm_mode *
847choose_mode (struct drm_output *output, struct weston_mode *target_mode)
848{
849 struct drm_mode *tmp_mode = NULL, *mode;
850
851 if (output->base.current->width == target_mode->width &&
852 output->base.current->height == target_mode->height &&
853 (output->base.current->refresh == target_mode->refresh ||
854 target_mode->refresh == 0))
855 return (struct drm_mode *)output->base.current;
856
857 wl_list_for_each(mode, &output->base.mode_list, base.link) {
858 if (mode->mode_info.hdisplay == target_mode->width &&
859 mode->mode_info.vdisplay == target_mode->height) {
860 if (mode->mode_info.vrefresh == target_mode->refresh ||
861 target_mode->refresh == 0) {
862 return mode;
863 } else if (!tmp_mode)
864 tmp_mode = mode;
865 }
866 }
867
868 return tmp_mode;
869}
870
871static int
872drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
873{
874 struct drm_output *output;
875 struct drm_mode *drm_mode;
876 int ret;
877 struct drm_compositor *ec;
878 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800879
880 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200881 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800882 return -1;
883 }
884
885 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200886 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800887 return -1;
888 }
889
890 ec = (struct drm_compositor *)output_base->compositor;
891 output = (struct drm_output *)output_base;
892 drm_mode = choose_mode (output, mode);
893
894 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200895 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800896 return -1;
897 } else if (&drm_mode->base == output->base.current) {
898 return 0;
899 } else if (drm_mode->base.width == output->base.current->width &&
900 drm_mode->base.height == output->base.current->height) {
901 /* only change refresh value */
902 ret = drmModeSetCrtc(ec->drm.fd,
903 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300904 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800905 &output->connector_id, 1, &drm_mode->mode_info);
906
907 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200908 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800909 drm_mode->base.width,
910 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400911 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800912 ret = -1;
913 } else {
914 output->base.current->flags = 0;
915 output->base.current = &drm_mode->base;
916 drm_mode->base.flags =
917 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
918 ret = 0;
919 }
920
921 return ret;
922 }
923
924 drm_mode->base.flags =
925 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
926
927 surface = gbm_surface_create(ec->gbm,
928 drm_mode->base.width,
929 drm_mode->base.height,
930 GBM_FORMAT_XRGB8888,
931 GBM_BO_USE_SCANOUT |
932 GBM_BO_USE_RENDERING);
933 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200934 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800935 return -1;
936 }
937
John Kåre Alsaker94659272012-11-13 19:10:18 +0100938 gles2_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800939
John Kåre Alsaker94659272012-11-13 19:10:18 +0100940 if (!gles2_renderer_output_create(&output->base, surface)) {
941 weston_log("failed to create renderer output\n");
942 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800943 }
944
945 ret = drmModeSetCrtc(ec->drm.fd,
946 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300947 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800948 &output->connector_id, 1, &drm_mode->mode_info);
949 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200950 weston_log("failed to set mode\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +0100951 goto err_gles2;
Alex Wub7b8bda2012-04-17 17:20:48 +0800952 }
953
954 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300955 if (output->current) {
956 if (output->current->is_client_buffer)
957 gbm_bo_destroy(output->current->bo);
958 else
959 gbm_surface_release_buffer(output->surface,
960 output->current->bo);
961 }
962 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800963
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300964 if (output->next) {
965 if (output->next->is_client_buffer)
966 gbm_bo_destroy(output->next->bo);
967 else
968 gbm_surface_release_buffer(output->surface,
969 output->next->bo);
970 }
971 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800972
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800974 output->surface = surface;
975
976 /*update output*/
977 output->base.current = &drm_mode->base;
978 output->base.dirty = 1;
979 weston_output_move(&output->base, output->base.x, output->base.y);
980 return 0;
981
John Kåre Alsaker94659272012-11-13 19:10:18 +0100982err_gles2:
983 gles2_renderer_output_destroy(&output->base);
984err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +0800985 gbm_surface_destroy(surface);
986 return -1;
987}
988
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400989static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400990on_drm_input(int fd, uint32_t mask, void *data)
991{
992 drmEventContext evctx;
993
994 memset(&evctx, 0, sizeof evctx);
995 evctx.version = DRM_EVENT_CONTEXT_VERSION;
996 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500997 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400998 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400999
1000 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001001}
1002
1003static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001004init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001005{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001006 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001007 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001008 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001009 static const EGLint config_attribs[] = {
1010 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1011 EGL_RED_SIZE, 1,
1012 EGL_GREEN_SIZE, 1,
1013 EGL_BLUE_SIZE, 1,
1014 EGL_ALPHA_SIZE, 0,
1015 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1016 EGL_NONE
1017 };
1018
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001019 sysnum = udev_device_get_sysnum(device);
1020 if (sysnum)
1021 ec->drm.id = atoi(sysnum);
1022 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001023 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001024 return -1;
1025 }
1026
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001027 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001028 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001029 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001030 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001031 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001032 udev_device_get_devnode(device));
1033 return -1;
1034 }
1035
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001036 weston_log("using %s\n", filename);
1037
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001038 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001039 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001040 ec->base.egl_display = eglGetDisplay(ec->gbm);
1041 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001042 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001043 return -1;
1044 }
1045
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001046 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001047 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001048 return -1;
1049 }
1050
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001051 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1052 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001053 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001054 return -1;
1055 }
1056
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001057 return 0;
1058}
1059
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001060static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001061drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1062{
1063 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001064 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001065
1066 mode = malloc(sizeof *mode);
1067 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001068 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001069
1070 mode->base.flags = 0;
1071 mode->base.width = info->hdisplay;
1072 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001073
1074 /* Calculate higher precision (mHz) refresh rate */
1075 refresh = (info->clock * 1000000LL / info->htotal +
1076 info->vtotal / 2) / info->vtotal;
1077
1078 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1079 refresh *= 2;
1080 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1081 refresh /= 2;
1082 if (info->vscan > 1)
1083 refresh /= info->vscan;
1084
1085 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001086 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001087
1088 if (info->type & DRM_MODE_TYPE_PREFERRED)
1089 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1090
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001091 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1092
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001093 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001094}
1095
1096static int
1097drm_subpixel_to_wayland(int drm_value)
1098{
1099 switch (drm_value) {
1100 default:
1101 case DRM_MODE_SUBPIXEL_UNKNOWN:
1102 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1103 case DRM_MODE_SUBPIXEL_NONE:
1104 return WL_OUTPUT_SUBPIXEL_NONE;
1105 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1106 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1107 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1108 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1109 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1110 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1111 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1112 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1113 }
1114}
1115
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001116/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001117static uint32_t
1118drm_get_backlight(struct drm_output *output)
1119{
1120 long brightness, max_brightness, norm;
1121
1122 brightness = backlight_get_brightness(output->backlight);
1123 max_brightness = backlight_get_max_brightness(output->backlight);
1124
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001125 /* convert it on a scale of 0 to 255 */
1126 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001127
1128 return (uint32_t) norm;
1129}
1130
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001131/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001132static void
1133drm_set_backlight(struct weston_output *output_base, uint32_t value)
1134{
1135 struct drm_output *output = (struct drm_output *) output_base;
1136 long max_brightness, new_brightness;
1137
1138 if (!output->backlight)
1139 return;
1140
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001141 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001142 return;
1143
1144 max_brightness = backlight_get_max_brightness(output->backlight);
1145
1146 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001147 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001148
1149 backlight_set_brightness(output->backlight, new_brightness);
1150}
1151
1152static drmModePropertyPtr
1153drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1154{
1155 drmModePropertyPtr props;
1156 int i;
1157
1158 for (i = 0; i < connector->count_props; i++) {
1159 props = drmModeGetProperty(fd, connector->props[i]);
1160 if (!props)
1161 continue;
1162
1163 if (!strcmp(props->name, name))
1164 return props;
1165
1166 drmModeFreeProperty(props);
1167 }
1168
1169 return NULL;
1170}
1171
1172static void
1173drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1174{
1175 struct drm_output *output = (struct drm_output *) output_base;
1176 struct weston_compositor *ec = output_base->compositor;
1177 struct drm_compositor *c = (struct drm_compositor *) ec;
1178 drmModeConnectorPtr connector;
1179 drmModePropertyPtr prop;
1180
1181 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1182 if (!connector)
1183 return;
1184
1185 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1186 if (!prop) {
1187 drmModeFreeConnector(connector);
1188 return;
1189 }
1190
1191 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1192 prop->prop_id, level);
1193 drmModeFreeProperty(prop);
1194 drmModeFreeConnector(connector);
1195}
1196
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001197static const char *connector_type_names[] = {
1198 "None",
1199 "VGA",
1200 "DVI",
1201 "DVI",
1202 "DVI",
1203 "Composite",
1204 "TV",
1205 "LVDS",
1206 "CTV",
1207 "DIN",
1208 "DP",
1209 "HDMI",
1210 "HDMI",
1211 "TV",
1212 "eDP",
1213};
1214
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001215static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001216find_crtc_for_connector(struct drm_compositor *ec,
1217 drmModeRes *resources, drmModeConnector *connector)
1218{
1219 drmModeEncoder *encoder;
1220 uint32_t possible_crtcs;
1221 int i, j;
1222
1223 for (j = 0; j < connector->count_encoders; j++) {
1224 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1225 if (encoder == NULL) {
1226 weston_log("Failed to get encoder.\n");
1227 return -1;
1228 }
1229 possible_crtcs = encoder->possible_crtcs;
1230 drmModeFreeEncoder(encoder);
1231
1232 for (i = 0; i < resources->count_crtcs; i++) {
1233 if (possible_crtcs & (1 << i) &&
1234 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1235 return i;
1236 }
1237 }
1238
1239 return -1;
1240}
1241
1242static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001243create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001244 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001245 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001246 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001247{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001248 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001249 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1250 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001251 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001252 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001253 drmModeModeInfo crtc_mode;
1254 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001255 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001256 char name[32];
1257 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001258
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001259 i = find_crtc_for_connector(ec, resources, connector);
1260 if (i < 0) {
1261 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262 return -1;
1263 }
1264
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001265 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001266 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001267 return -1;
1268
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001269 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001270 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1271 output->base.make = "unknown";
1272 output->base.model = "unknown";
1273 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001274
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001275 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1276 type_name = connector_type_names[connector->connector_type];
1277 else
1278 type_name = "UNKNOWN";
1279 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1280 output->name = strdup(name);
1281
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001282 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001283 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001284 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001285 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001286 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001287
Matt Roper361d2ad2011-08-29 13:52:23 -07001288 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1289
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001290 /* Get the current mode on the crtc that's currently driving
1291 * this connector. */
1292 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001293 memset(&crtc_mode, 0, sizeof crtc_mode);
1294 if (encoder != NULL) {
1295 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1296 drmModeFreeEncoder(encoder);
1297 if (crtc == NULL)
1298 goto err_free;
1299 if (crtc->mode_valid)
1300 crtc_mode = crtc->mode;
1301 drmModeFreeCrtc(crtc);
1302 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001303
David Herrmann0f0d54e2011-12-08 17:05:45 +01001304 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001305 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1306 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001307 goto err_free;
1308 }
1309
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001310 preferred = NULL;
1311 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001312 configured = NULL;
1313
1314 wl_list_for_each(temp, &configured_output_list, link) {
1315 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001316 if (temp->mode)
1317 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001318 temp->name, temp->mode);
1319 o = temp;
1320 break;
1321 }
1322 }
1323
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001324 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001325 weston_log("Disabling output %s\n", o->name);
1326
1327 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1328 0, 0, 0, 0, 0, NULL);
1329 goto err_free;
1330 }
1331
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001332 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001333 if (o && o->config == OUTPUT_CONFIG_MODE &&
1334 o->width == drm_mode->base.width &&
1335 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001336 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001337 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001338 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001339 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001340 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001341 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001342
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001343 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001344 configured = drm_output_add_mode(output, &o->crtc_mode);
1345 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001346 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001347 current = configured;
1348 }
1349
Wang Quanxianacb805a2012-07-30 18:09:46 -04001350 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001351 current = drm_output_add_mode(output, &crtc_mode);
1352 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001353 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001354 }
1355
Scott Moreau8ab5d452012-07-30 19:51:08 -06001356 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1357 configured = current;
1358
Wang Quanxianacb805a2012-07-30 18:09:46 -04001359 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001360 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001361 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001362 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001363 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001364 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001365 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001366 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001367
1368 if (output->base.current == NULL) {
1369 weston_log("no available modes for %s\n", output->name);
1370 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001371 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001372
Wang Quanxianacb805a2012-07-30 18:09:46 -04001373 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1374
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001375 output->surface = gbm_surface_create(ec->gbm,
1376 output->base.current->width,
1377 output->base.current->height,
1378 GBM_FORMAT_XRGB8888,
1379 GBM_BO_USE_SCANOUT |
1380 GBM_BO_USE_RENDERING);
1381 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001382 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001383 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001384 }
1385
John Kåre Alsaker94659272012-11-13 19:10:18 +01001386 weston_output_init(&output->base, &ec->base, x, y,
1387 connector->mmWidth, connector->mmHeight,
1388 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1389
1390 if (gles2_renderer_output_create(&output->base, output->surface) < 0)
1391 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001392
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001393 output->cursor_bo[0] =
1394 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1395 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1396 output->cursor_bo[1] =
1397 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1398 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001399 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1400 weston_log("cursor buffers unavailable, using gl cursors\n");
1401 ec->cursors_are_broken = 1;
1402 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001403
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001404 output->backlight = backlight_init(drm_device,
1405 connector->connector_type);
1406 if (output->backlight) {
1407 output->base.set_backlight = drm_set_backlight;
1408 output->base.backlight_current = drm_get_backlight(output);
1409 }
1410
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001411 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1412
Alex Wubd3354b2012-04-17 17:20:49 +08001413 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001414 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001415 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001416 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001417 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001418 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001419
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001420 weston_plane_init(&output->cursor_plane, 0, 0);
1421 weston_plane_init(&output->fb_plane, 0, 0);
1422
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001423 weston_log("Output %s, (connector %d, crtc %d)\n",
1424 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001425 wl_list_for_each(m, &output->base.mode_list, link)
1426 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1427 m->width, m->height, m->refresh / 1000.0,
1428 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1429 ", preferred" : "",
1430 m->flags & WL_OUTPUT_MODE_CURRENT ?
1431 ", current" : "",
1432 connector->count_modes == 0 ?
1433 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001434
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001435 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001436
John Kåre Alsaker94659272012-11-13 19:10:18 +01001437err_output:
1438 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001439 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001440err_free:
1441 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1442 base.link) {
1443 wl_list_remove(&drm_mode->base.link);
1444 free(drm_mode);
1445 }
1446
1447 drmModeFreeCrtc(output->original_crtc);
1448 ec->crtc_allocator &= ~(1 << output->crtc_id);
1449 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001450 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001451 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001452
David Herrmann0f0d54e2011-12-08 17:05:45 +01001453 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001454}
1455
Jesse Barnes58ef3792012-02-23 09:45:49 -05001456static void
1457create_sprites(struct drm_compositor *ec)
1458{
1459 struct drm_sprite *sprite;
1460 drmModePlaneRes *plane_res;
1461 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001462 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001463
1464 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1465 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001466 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001467 strerror(errno));
1468 return;
1469 }
1470
1471 for (i = 0; i < plane_res->count_planes; i++) {
1472 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1473 if (!plane)
1474 continue;
1475
1476 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1477 plane->count_formats));
1478 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001479 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001480 __func__);
1481 free(plane);
1482 continue;
1483 }
1484
1485 memset(sprite, 0, sizeof *sprite);
1486
1487 sprite->possible_crtcs = plane->possible_crtcs;
1488 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001489 sprite->current = NULL;
1490 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001491 sprite->compositor = ec;
1492 sprite->count_formats = plane->count_formats;
1493 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001494 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001495 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001496 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001497
1498 wl_list_insert(&ec->sprite_list, &sprite->link);
1499 }
1500
1501 free(plane_res->planes);
1502 free(plane_res);
1503}
1504
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001505static void
1506destroy_sprites(struct drm_compositor *compositor)
1507{
1508 struct drm_sprite *sprite, *next;
1509 struct drm_output *output;
1510
1511 output = container_of(compositor->base.output_list.next,
1512 struct drm_output, base.link);
1513
1514 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1515 drmModeSetPlane(compositor->drm.fd,
1516 sprite->plane_id,
1517 output->crtc_id, 0, 0,
1518 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001519 if (sprite->current)
1520 gbm_bo_destroy(sprite->current->bo);
1521 if (sprite->next)
1522 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001523 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001524 free(sprite);
1525 }
1526}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001527
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001528static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001529create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001530 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001531{
1532 drmModeConnector *connector;
1533 drmModeRes *resources;
1534 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001535 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001536
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001537 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001538 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001539 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001540 return -1;
1541 }
1542
Jesse Barnes58ef3792012-02-23 09:45:49 -05001543 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001544 if (!ec->crtcs) {
1545 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001546 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001547 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001548
Rob Clark4339add2012-08-09 14:18:28 -05001549 ec->min_width = resources->min_width;
1550 ec->max_width = resources->max_width;
1551 ec->min_height = resources->min_height;
1552 ec->max_height = resources->max_height;
1553
Jesse Barnes58ef3792012-02-23 09:45:49 -05001554 ec->num_crtcs = resources->count_crtcs;
1555 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1556
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001557 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001558 connector = drmModeGetConnector(ec->drm.fd,
1559 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001560 if (connector == NULL)
1561 continue;
1562
1563 if (connector->connection == DRM_MODE_CONNECTED &&
1564 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001565 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001566 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001567 connector, x, y,
1568 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001569 drmModeFreeConnector(connector);
1570 continue;
1571 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001572
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001573 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001574 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001575 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001576 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001577
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001578 drmModeFreeConnector(connector);
1579 }
1580
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001581 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001582 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001583 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001584 return -1;
1585 }
1586
1587 drmModeFreeResources(resources);
1588
1589 return 0;
1590}
1591
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001592static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001593update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001594{
1595 drmModeConnector *connector;
1596 drmModeRes *resources;
1597 struct drm_output *output, *next;
1598 int x = 0, y = 0;
1599 int x_offset = 0, y_offset = 0;
1600 uint32_t connected = 0, disconnects = 0;
1601 int i;
1602
1603 resources = drmModeGetResources(ec->drm.fd);
1604 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001605 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001606 return;
1607 }
1608
1609 /* collect new connects */
1610 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001611 int connector_id = resources->connectors[i];
1612
1613 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001614 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001615 continue;
1616
David Herrmann7551cff2011-12-08 17:05:43 +01001617 if (connector->connection != DRM_MODE_CONNECTED) {
1618 drmModeFreeConnector(connector);
1619 continue;
1620 }
1621
Benjamin Franzke117483d2011-08-30 11:38:26 +02001622 connected |= (1 << connector_id);
1623
1624 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001625 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001626 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001627 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001628
1629 /* XXX: not yet needed, we die with 0 outputs */
1630 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001631 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001632 else
1633 x = 0;
1634 y = 0;
1635 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001636 connector, x, y,
1637 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001638 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001639
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001640 }
1641 drmModeFreeConnector(connector);
1642 }
1643 drmModeFreeResources(resources);
1644
1645 disconnects = ec->connector_allocator & ~connected;
1646 if (disconnects) {
1647 wl_list_for_each_safe(output, next, &ec->base.output_list,
1648 base.link) {
1649 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001650 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001651 output->base.x - x_offset,
1652 output->base.y - y_offset);
1653 }
1654
1655 if (disconnects & (1 << output->connector_id)) {
1656 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001657 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001658 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001659 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001660 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001661 }
1662 }
1663 }
1664
1665 /* FIXME: handle zero outputs, without terminating */
1666 if (ec->connector_allocator == 0)
1667 wl_display_terminate(ec->base.wl_display);
1668}
1669
1670static int
David Herrmannd7488c22012-03-11 20:05:21 +01001671udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001672{
David Herrmannd7488c22012-03-11 20:05:21 +01001673 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001674 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001675
1676 sysnum = udev_device_get_sysnum(device);
1677 if (!sysnum || atoi(sysnum) != ec->drm.id)
1678 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001679
David Herrmann6ac52db2012-03-11 20:05:22 +01001680 val = udev_device_get_property_value(device, "HOTPLUG");
1681 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001682 return 0;
1683
David Herrmann6ac52db2012-03-11 20:05:22 +01001684 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001685}
1686
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001687static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001688udev_drm_event(int fd, uint32_t mask, void *data)
1689{
1690 struct drm_compositor *ec = data;
1691 struct udev_device *event;
1692
1693 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001694
David Herrmannd7488c22012-03-11 20:05:21 +01001695 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001696 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001697
1698 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001699
1700 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001701}
1702
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001703static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001704drm_restore(struct weston_compositor *ec)
1705{
1706 struct drm_compositor *d = (struct drm_compositor *) ec;
1707
1708 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1709 weston_log("failed to drop master: %m\n");
1710 tty_reset(d->tty);
1711}
1712
Pekka Paalanen33156972012-08-03 13:30:30 -04001713static const char default_seat[] = "seat0";
1714
1715static void
1716device_added(struct udev_device *udev_device, struct drm_seat *master)
1717{
1718 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001719 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001720 const char *devnode;
1721 const char *device_seat;
1722 int fd;
1723
1724 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1725 if (!device_seat)
1726 device_seat = default_seat;
1727
1728 if (strcmp(device_seat, master->seat_id))
1729 return;
1730
1731 c = master->base.compositor;
1732 devnode = udev_device_get_devnode(udev_device);
1733
1734 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001735 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001736 * read. mtdev_get() also expects this. */
1737 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1738 if (fd < 0) {
1739 weston_log("opening input device '%s' failed.\n", devnode);
1740 return;
1741 }
1742
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001743 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001744 if (!device) {
1745 close(fd);
1746 weston_log("not using input device '%s'.\n", devnode);
1747 return;
1748 }
1749
1750 wl_list_insert(master->devices_list.prev, &device->link);
1751}
1752
1753static void
1754evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1755{
1756 struct drm_seat *seat = (struct drm_seat *) seat_base;
1757 struct udev_enumerate *e;
1758 struct udev_list_entry *entry;
1759 struct udev_device *device;
1760 const char *path, *sysname;
1761
1762 e = udev_enumerate_new(udev);
1763 udev_enumerate_add_match_subsystem(e, "input");
1764 udev_enumerate_scan_devices(e);
1765 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1766 path = udev_list_entry_get_name(entry);
1767 device = udev_device_new_from_syspath(udev, path);
1768
1769 sysname = udev_device_get_sysname(device);
1770 if (strncmp("event", sysname, 5) != 0) {
1771 udev_device_unref(device);
1772 continue;
1773 }
1774
1775 device_added(device, seat);
1776
1777 udev_device_unref(device);
1778 }
1779 udev_enumerate_unref(e);
1780
1781 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1782
1783 if (wl_list_empty(&seat->devices_list)) {
1784 weston_log(
1785 "warning: no input devices on entering Weston. "
1786 "Possible causes:\n"
1787 "\t- no permissions to read /dev/input/event*\n"
1788 "\t- seats misconfigured "
1789 "(Weston backend option 'seat', "
1790 "udev device property ID_SEAT)\n");
1791 }
1792}
1793
1794static int
1795evdev_udev_handler(int fd, uint32_t mask, void *data)
1796{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001797 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001798 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001799 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001800 const char *action;
1801 const char *devnode;
1802
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001803 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001804 if (!udev_device)
1805 return 1;
1806
1807 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001808 if (!action)
1809 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001810
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001811 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1812 goto out;
1813
1814 if (!strcmp(action, "add")) {
1815 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001816 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001817 else if (!strcmp(action, "remove")) {
1818 devnode = udev_device_get_devnode(udev_device);
1819 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1820 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001821 weston_log("input device %s, %s removed\n",
1822 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001823 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001824 break;
1825 }
1826 }
1827
1828out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001829 udev_device_unref(udev_device);
1830
1831 return 0;
1832}
1833
1834static int
1835evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1836{
1837 struct drm_seat *master = (struct drm_seat *) seat_base;
1838 struct wl_event_loop *loop;
1839 struct weston_compositor *c = master->base.compositor;
1840 int fd;
1841
1842 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1843 if (!master->udev_monitor) {
1844 weston_log("udev: failed to create the udev monitor\n");
1845 return 0;
1846 }
1847
1848 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1849 "input", NULL);
1850
1851 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1852 weston_log("udev: failed to bind the udev monitor\n");
1853 udev_monitor_unref(master->udev_monitor);
1854 return 0;
1855 }
1856
1857 loop = wl_display_get_event_loop(c->wl_display);
1858 fd = udev_monitor_get_fd(master->udev_monitor);
1859 master->udev_monitor_source =
1860 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1861 evdev_udev_handler, master);
1862 if (!master->udev_monitor_source) {
1863 udev_monitor_unref(master->udev_monitor);
1864 return 0;
1865 }
1866
1867 return 1;
1868}
1869
1870static void
1871evdev_disable_udev_monitor(struct weston_seat *seat_base)
1872{
1873 struct drm_seat *seat = (struct drm_seat *) seat_base;
1874
1875 if (!seat->udev_monitor)
1876 return;
1877
1878 udev_monitor_unref(seat->udev_monitor);
1879 seat->udev_monitor = NULL;
1880 wl_event_source_remove(seat->udev_monitor_source);
1881 seat->udev_monitor_source = NULL;
1882}
1883
1884static void
1885drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1886{
1887 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001888 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001889
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001890 wl_list_for_each(device, &seat->devices_list, link)
1891 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001892}
1893
1894static void
1895evdev_input_create(struct weston_compositor *c, struct udev *udev,
1896 const char *seat_id)
1897{
1898 struct drm_seat *seat;
1899
1900 seat = malloc(sizeof *seat);
1901 if (seat == NULL)
1902 return;
1903
1904 memset(seat, 0, sizeof *seat);
1905 weston_seat_init(&seat->base, c);
1906 seat->base.led_update = drm_led_update;
1907
1908 wl_list_init(&seat->devices_list);
1909 seat->seat_id = strdup(seat_id);
1910 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1911 free(seat->seat_id);
1912 free(seat);
1913 return;
1914 }
1915
1916 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001917}
1918
1919static void
1920evdev_remove_devices(struct weston_seat *seat_base)
1921{
1922 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001923 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001924
1925 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001926 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001927
Pekka Paalanend8583512012-08-03 14:39:11 +03001928 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001929 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001930}
1931
1932static void
1933evdev_input_destroy(struct weston_seat *seat_base)
1934{
1935 struct drm_seat *seat = (struct drm_seat *) seat_base;
1936
1937 evdev_remove_devices(seat_base);
1938 evdev_disable_udev_monitor(&seat->base);
1939
1940 weston_seat_release(seat_base);
1941 free(seat->seat_id);
1942 free(seat);
1943}
1944
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001945static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001946drm_free_configured_output(struct drm_configured_output *output)
1947{
1948 free(output->name);
1949 free(output->mode);
1950 free(output);
1951}
1952
1953static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001954drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001955{
1956 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001957 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001958 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001959
Daniel Stone37816df2012-05-16 18:45:18 +01001960 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1961 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001962 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001963 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001964
1965 wl_event_source_remove(d->udev_drm_source);
1966 wl_event_source_remove(d->drm_source);
1967
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001968 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001969
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001970 gles2_renderer_destroy(ec);
1971
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001972 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001973 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001974 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001975 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001976 eglReleaseThread();
1977
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001978 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001979 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001980 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001981 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001982 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001983
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001984 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001985}
1986
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001987static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001988drm_compositor_set_modes(struct drm_compositor *compositor)
1989{
1990 struct drm_output *output;
1991 struct drm_mode *drm_mode;
1992 int ret;
1993
1994 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1995 drm_mode = (struct drm_mode *) output->base.current;
1996 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001997 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001998 &output->connector_id, 1,
1999 &drm_mode->mode_info);
2000 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002001 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002002 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002003 drm_mode->base.width, drm_mode->base.height,
2004 output->base.x, output->base.y);
2005 }
2006 }
2007}
2008
2009static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002010vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002011{
2012 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002013 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002014 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002015 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002016
2017 switch (event) {
2018 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002019 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002020 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002021 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002022 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002023 wl_display_terminate(compositor->wl_display);
2024 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002025 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002026 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002027 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002028 wl_list_for_each(seat, &compositor->seat_list, link) {
2029 evdev_add_devices(ec->udev, seat);
2030 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002031 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002032 break;
2033 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002034 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002035 wl_list_for_each(seat, &compositor->seat_list, link) {
2036 evdev_disable_udev_monitor(seat);
2037 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002038 }
2039
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002040 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002041 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002042 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002043
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002044 /* If we have a repaint scheduled (either from a
2045 * pending pageflip or the idle handler), make sure we
2046 * cancel that so we don't try to pageflip when we're
2047 * vt switched away. The SLEEPING state will prevent
2048 * further attemps at repainting. When we switch
2049 * back, we schedule a repaint, which will process
2050 * pending frame callbacks. */
2051
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002052 wl_list_for_each(output, &ec->base.output_list, base.link) {
2053 output->base.repaint_needed = 0;
2054 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002055 }
2056
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002057 output = container_of(ec->base.output_list.next,
2058 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002059
2060 wl_list_for_each(sprite, &ec->sprite_list, link)
2061 drmModeSetPlane(ec->drm.fd,
2062 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002063 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002064 0, 0, 0, 0, 0, 0, 0, 0);
2065
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002066 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002067 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002068
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002069 break;
2070 };
2071}
2072
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002073static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002074switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002075{
2076 struct drm_compositor *ec = data;
2077
Daniel Stone325fc2d2012-05-30 16:31:58 +01002078 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002079}
2080
David Herrmann0af066f2012-10-29 19:21:16 +01002081/*
2082 * Find primary GPU
2083 * Some systems may have multiple DRM devices attached to a single seat. This
2084 * function loops over all devices and tries to find a PCI device with the
2085 * boot_vga sysfs attribute set to 1.
2086 * If no such device is found, the first DRM device reported by udev is used.
2087 */
2088static struct udev_device*
2089find_primary_gpu(struct drm_compositor *ec, const char *seat)
2090{
2091 struct udev_enumerate *e;
2092 struct udev_list_entry *entry;
2093 const char *path, *device_seat, *id;
2094 struct udev_device *device, *drm_device, *pci;
2095
2096 e = udev_enumerate_new(ec->udev);
2097 udev_enumerate_add_match_subsystem(e, "drm");
2098 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2099
2100 udev_enumerate_scan_devices(e);
2101 drm_device = NULL;
2102 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2103 path = udev_list_entry_get_name(entry);
2104 device = udev_device_new_from_syspath(ec->udev, path);
2105 if (!device)
2106 continue;
2107 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2108 if (!device_seat)
2109 device_seat = default_seat;
2110 if (strcmp(device_seat, seat)) {
2111 udev_device_unref(device);
2112 continue;
2113 }
2114
2115 pci = udev_device_get_parent_with_subsystem_devtype(device,
2116 "pci", NULL);
2117 if (pci) {
2118 id = udev_device_get_sysattr_value(pci, "boot_vga");
2119 if (id && !strcmp(id, "1")) {
2120 if (drm_device)
2121 udev_device_unref(drm_device);
2122 drm_device = device;
2123 break;
2124 }
2125 }
2126
2127 if (!drm_device)
2128 drm_device = device;
2129 else
2130 udev_device_unref(device);
2131 }
2132
2133 udev_enumerate_unref(e);
2134 return drm_device;
2135}
2136
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002137static void
2138hide_sprites_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2139 void *data)
2140{
2141 struct drm_compositor *c = data;
2142
2143 c->sprites_hidden ^= 1;
2144}
2145
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002146static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002147drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002148 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002149 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002150{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002151 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002152 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002153 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002154 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002155 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002156 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002157
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002158 weston_log("initializing drm backend\n");
2159
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002160 ec = malloc(sizeof *ec);
2161 if (ec == NULL)
2162 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002163 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002164
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002165 /* KMS support for sprites is not complete yet, so disable the
2166 * functionality for now. */
2167 ec->sprites_are_broken = 1;
2168
Daniel Stone725c2c32012-06-22 14:04:36 +01002169 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002170 config_file) < 0) {
2171 weston_log("weston_compositor_init failed\n");
2172 goto err_base;
2173 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002174
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002175 ec->udev = udev_new();
2176 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002177 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002178 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002179 }
2180
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002181 ec->base.wl_display = display;
2182 ec->tty = tty_create(&ec->base, vt_func, tty);
2183 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002184 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002185 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002186 }
2187
David Herrmann0af066f2012-10-29 19:21:16 +01002188 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002189 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002190 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002191 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002192 }
David Herrmann0af066f2012-10-29 19:21:16 +01002193 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002194
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002195 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002196 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002197 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002198 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002199
2200 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002201 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002202
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002203 ec->base.focus = 1;
2204
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002205 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002206
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002207 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002208 weston_compositor_add_key_binding(&ec->base, key,
2209 MODIFIER_CTRL | MODIFIER_ALT,
2210 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002211
Jesse Barnes58ef3792012-02-23 09:45:49 -05002212 wl_list_init(&ec->sprite_list);
2213 create_sprites(ec);
2214
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002215 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002216 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002217 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002218 }
2219
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002220 path = NULL;
2221
Tiago Vignattice03ec32011-12-19 01:14:03 +02002222 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002223
2224 loop = wl_display_get_event_loop(ec->base.wl_display);
2225 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002226 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002227 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002228
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002229 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2230 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002231 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002232 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002233 }
2234 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2235 "drm", NULL);
2236 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002237 wl_event_loop_add_fd(loop,
2238 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002239 WL_EVENT_READABLE, udev_drm_event, ec);
2240
2241 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002242 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002243 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002244 }
2245
Daniel Stonea96b93c2012-06-22 14:04:37 +01002246 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002247
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002248 weston_compositor_add_debug_binding(&ec->base, KEY_O,
2249 hide_sprites_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002250
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002251 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002252
2253err_udev_monitor:
2254 wl_event_source_remove(ec->udev_drm_source);
2255 udev_monitor_unref(ec->udev_monitor);
2256err_drm_source:
2257 wl_event_source_remove(ec->drm_source);
2258 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2259 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002260 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2261 EGL_NO_CONTEXT);
2262 eglTerminate(ec->base.egl_display);
2263 eglReleaseThread();
2264 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002265err_sprite:
2266 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002267err_udev_dev:
2268 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002269err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002270 tty_destroy(ec->tty);
2271err_udev:
2272 udev_unref(ec->udev);
2273err_compositor:
2274 weston_compositor_shutdown(&ec->base);
2275err_base:
2276 free(ec);
2277 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002278}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002279
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002280static int
2281set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2282{
2283 mode->flags = 0;
2284
2285 if (strcmp(hsync, "+hsync") == 0)
2286 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2287 else if (strcmp(hsync, "-hsync") == 0)
2288 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2289 else
2290 return -1;
2291
2292 if (strcmp(vsync, "+vsync") == 0)
2293 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2294 else if (strcmp(vsync, "-vsync") == 0)
2295 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2296 else
2297 return -1;
2298
2299 return 0;
2300}
2301
2302static int
2303check_for_modeline(struct drm_configured_output *output)
2304{
2305 drmModeModeInfo mode;
2306 char hsync[16];
2307 char vsync[16];
2308 char mode_name[16];
2309 float fclock;
2310
2311 mode.type = DRM_MODE_TYPE_USERDEF;
2312 mode.hskew = 0;
2313 mode.vscan = 0;
2314 mode.vrefresh = 0;
2315
2316 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2317 &fclock, &mode.hdisplay,
2318 &mode.hsync_start,
2319 &mode.hsync_end, &mode.htotal,
2320 &mode.vdisplay,
2321 &mode.vsync_start,
2322 &mode.vsync_end, &mode.vtotal,
2323 hsync, vsync) == 11) {
2324 if (set_sync_flags(&mode, hsync, vsync))
2325 return -1;
2326
2327 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2328 strcpy(mode.name, mode_name);
2329
2330 mode.clock = fclock * 1000;
2331 } else
2332 return -1;
2333
2334 output->crtc_mode = mode;
2335
2336 return 0;
2337}
2338
Scott Moreau8ab5d452012-07-30 19:51:08 -06002339static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002340drm_output_set_transform(struct drm_configured_output *output)
2341{
2342 if (!output_transform) {
2343 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2344 return;
2345 }
2346
2347 if (!strcmp(output_transform, "normal"))
2348 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2349 else if (!strcmp(output_transform, "90"))
2350 output->transform = WL_OUTPUT_TRANSFORM_90;
2351 else if (!strcmp(output_transform, "180"))
2352 output->transform = WL_OUTPUT_TRANSFORM_180;
2353 else if (!strcmp(output_transform, "270"))
2354 output->transform = WL_OUTPUT_TRANSFORM_270;
2355 else if (!strcmp(output_transform, "flipped"))
2356 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2357 else if (!strcmp(output_transform, "flipped-90"))
2358 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2359 else if (!strcmp(output_transform, "flipped-180"))
2360 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2361 else if (!strcmp(output_transform, "flipped-270"))
2362 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2363 else {
2364 weston_log("Invalid transform \"%s\" for output %s\n",
2365 output_transform, output_name);
2366 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2367 }
2368
2369 free(output_transform);
2370 output_transform = NULL;
2371}
2372
2373static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002374output_section_done(void *data)
2375{
2376 struct drm_configured_output *output;
2377
2378 output = malloc(sizeof *output);
2379
Scott Moreau1bad5db2012-08-18 01:04:05 -06002380 if (!output || !output_name || (output_name[0] == 'X') ||
2381 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002382 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002383 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002384 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002385 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002386 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002387 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002388 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002389 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002390 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002391
2392 output->config = OUTPUT_CONFIG_INVALID;
2393 output->name = output_name;
2394 output->mode = output_mode;
2395
Scott Moreau1bad5db2012-08-18 01:04:05 -06002396 if (output_mode) {
2397 if (strcmp(output_mode, "off") == 0)
2398 output->config = OUTPUT_CONFIG_OFF;
2399 else if (strcmp(output_mode, "preferred") == 0)
2400 output->config = OUTPUT_CONFIG_PREFERRED;
2401 else if (strcmp(output_mode, "current") == 0)
2402 output->config = OUTPUT_CONFIG_CURRENT;
2403 else if (sscanf(output_mode, "%dx%d",
2404 &output->width, &output->height) == 2)
2405 output->config = OUTPUT_CONFIG_MODE;
2406 else if (check_for_modeline(output) == 0)
2407 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002408
Scott Moreau1bad5db2012-08-18 01:04:05 -06002409 if (output->config == OUTPUT_CONFIG_INVALID)
2410 weston_log("Invalid mode \"%s\" for output %s\n",
2411 output_mode, output_name);
2412 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002413 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002414
2415 drm_output_set_transform(output);
2416
2417 wl_list_insert(&configured_output_list, &output->link);
2418
2419 if (output_transform)
2420 free(output_transform);
2421 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002422}
2423
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002424WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002425backend_init(struct wl_display *display, int argc, char *argv[],
2426 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002427{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002428 int connector = 0, tty = 0;
2429 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002430
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002431 const struct weston_option drm_options[] = {
2432 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2433 { WESTON_OPTION_STRING, "seat", 0, &seat },
2434 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002435 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002436 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002437
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002438 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002439
Scott Moreau8ab5d452012-07-30 19:51:08 -06002440 wl_list_init(&configured_output_list);
2441
2442 const struct config_key drm_config_keys[] = {
2443 { "name", CONFIG_KEY_STRING, &output_name },
2444 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002445 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002446 };
2447
2448 const struct config_section config_section[] = {
2449 { "output", drm_config_keys,
2450 ARRAY_LENGTH(drm_config_keys), output_section_done },
2451 };
2452
2453 parse_config_file(config_file, config_section,
2454 ARRAY_LENGTH(config_section), NULL);
2455
Daniel Stonec1be8e52012-06-01 11:14:02 -04002456 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2457 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002458}