blob: 5fe234d1a9b60b85e00805d6f4ab4121ab6d2375 [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
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400832 eglDestroySurface(c->base.egl_display, output->base.egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400833 gbm_surface_destroy(output->surface);
834
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835 weston_plane_release(&output->fb_plane);
836 weston_plane_release(&output->cursor_plane);
837
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500838 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200839 wl_list_remove(&output->base.link);
840
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400841 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700842 free(output);
843}
844
Alex Wub7b8bda2012-04-17 17:20:48 +0800845static struct drm_mode *
846choose_mode (struct drm_output *output, struct weston_mode *target_mode)
847{
848 struct drm_mode *tmp_mode = NULL, *mode;
849
850 if (output->base.current->width == target_mode->width &&
851 output->base.current->height == target_mode->height &&
852 (output->base.current->refresh == target_mode->refresh ||
853 target_mode->refresh == 0))
854 return (struct drm_mode *)output->base.current;
855
856 wl_list_for_each(mode, &output->base.mode_list, base.link) {
857 if (mode->mode_info.hdisplay == target_mode->width &&
858 mode->mode_info.vdisplay == target_mode->height) {
859 if (mode->mode_info.vrefresh == target_mode->refresh ||
860 target_mode->refresh == 0) {
861 return mode;
862 } else if (!tmp_mode)
863 tmp_mode = mode;
864 }
865 }
866
867 return tmp_mode;
868}
869
870static int
871drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
872{
873 struct drm_output *output;
874 struct drm_mode *drm_mode;
875 int ret;
876 struct drm_compositor *ec;
877 struct gbm_surface *surface;
878 EGLSurface egl_surface;
879
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
938 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400939 eglCreateWindowSurface(ec->base.egl_display,
940 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800941 surface, NULL);
942
943 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200944 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800945 goto err;
946 }
947
948 ret = drmModeSetCrtc(ec->drm.fd,
949 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300950 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800951 &output->connector_id, 1, &drm_mode->mode_info);
952 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200953 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800954 goto err;
955 }
956
957 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300958 if (output->current) {
959 if (output->current->is_client_buffer)
960 gbm_bo_destroy(output->current->bo);
961 else
962 gbm_surface_release_buffer(output->surface,
963 output->current->bo);
964 }
965 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800966
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300967 if (output->next) {
968 if (output->next->is_client_buffer)
969 gbm_bo_destroy(output->next->bo);
970 else
971 gbm_surface_release_buffer(output->surface,
972 output->next->bo);
973 }
974 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800975
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400976 eglDestroySurface(ec->base.egl_display, output->base.egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800977 gbm_surface_destroy(output->surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400978 output->base.egl_surface = egl_surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800979 output->surface = surface;
980
981 /*update output*/
982 output->base.current = &drm_mode->base;
983 output->base.dirty = 1;
984 weston_output_move(&output->base, output->base.x, output->base.y);
985 return 0;
986
987err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400988 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800989 gbm_surface_destroy(surface);
990 return -1;
991}
992
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400993static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400994on_drm_input(int fd, uint32_t mask, void *data)
995{
996 drmEventContext evctx;
997
998 memset(&evctx, 0, sizeof evctx);
999 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1000 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001001 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001002 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001003
1004 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001005}
1006
1007static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001008init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001009{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001010 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001011 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001012 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001013 static const EGLint config_attribs[] = {
1014 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1015 EGL_RED_SIZE, 1,
1016 EGL_GREEN_SIZE, 1,
1017 EGL_BLUE_SIZE, 1,
1018 EGL_ALPHA_SIZE, 0,
1019 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1020 EGL_NONE
1021 };
1022
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001023 sysnum = udev_device_get_sysnum(device);
1024 if (sysnum)
1025 ec->drm.id = atoi(sysnum);
1026 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001027 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001028 return -1;
1029 }
1030
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001031 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001032 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001033 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001034 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001035 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001036 udev_device_get_devnode(device));
1037 return -1;
1038 }
1039
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001040 weston_log("using %s\n", filename);
1041
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001042 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001043 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001044 ec->base.egl_display = eglGetDisplay(ec->gbm);
1045 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001046 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001047 return -1;
1048 }
1049
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001050 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001051 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001052 return -1;
1053 }
1054
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001055 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1056 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001057 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001058 return -1;
1059 }
1060
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001061 return 0;
1062}
1063
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001064static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001065drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1066{
1067 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001068 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001069
1070 mode = malloc(sizeof *mode);
1071 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001072 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001073
1074 mode->base.flags = 0;
1075 mode->base.width = info->hdisplay;
1076 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001077
1078 /* Calculate higher precision (mHz) refresh rate */
1079 refresh = (info->clock * 1000000LL / info->htotal +
1080 info->vtotal / 2) / info->vtotal;
1081
1082 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1083 refresh *= 2;
1084 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1085 refresh /= 2;
1086 if (info->vscan > 1)
1087 refresh /= info->vscan;
1088
1089 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001090 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001091
1092 if (info->type & DRM_MODE_TYPE_PREFERRED)
1093 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1094
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001095 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1096
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001097 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001098}
1099
1100static int
1101drm_subpixel_to_wayland(int drm_value)
1102{
1103 switch (drm_value) {
1104 default:
1105 case DRM_MODE_SUBPIXEL_UNKNOWN:
1106 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1107 case DRM_MODE_SUBPIXEL_NONE:
1108 return WL_OUTPUT_SUBPIXEL_NONE;
1109 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1110 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1111 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1112 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1113 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1114 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1115 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1116 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1117 }
1118}
1119
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001120/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001121static uint32_t
1122drm_get_backlight(struct drm_output *output)
1123{
1124 long brightness, max_brightness, norm;
1125
1126 brightness = backlight_get_brightness(output->backlight);
1127 max_brightness = backlight_get_max_brightness(output->backlight);
1128
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001129 /* convert it on a scale of 0 to 255 */
1130 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001131
1132 return (uint32_t) norm;
1133}
1134
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001135/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001136static void
1137drm_set_backlight(struct weston_output *output_base, uint32_t value)
1138{
1139 struct drm_output *output = (struct drm_output *) output_base;
1140 long max_brightness, new_brightness;
1141
1142 if (!output->backlight)
1143 return;
1144
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001145 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001146 return;
1147
1148 max_brightness = backlight_get_max_brightness(output->backlight);
1149
1150 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001151 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001152
1153 backlight_set_brightness(output->backlight, new_brightness);
1154}
1155
1156static drmModePropertyPtr
1157drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1158{
1159 drmModePropertyPtr props;
1160 int i;
1161
1162 for (i = 0; i < connector->count_props; i++) {
1163 props = drmModeGetProperty(fd, connector->props[i]);
1164 if (!props)
1165 continue;
1166
1167 if (!strcmp(props->name, name))
1168 return props;
1169
1170 drmModeFreeProperty(props);
1171 }
1172
1173 return NULL;
1174}
1175
1176static void
1177drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1178{
1179 struct drm_output *output = (struct drm_output *) output_base;
1180 struct weston_compositor *ec = output_base->compositor;
1181 struct drm_compositor *c = (struct drm_compositor *) ec;
1182 drmModeConnectorPtr connector;
1183 drmModePropertyPtr prop;
1184
1185 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1186 if (!connector)
1187 return;
1188
1189 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1190 if (!prop) {
1191 drmModeFreeConnector(connector);
1192 return;
1193 }
1194
1195 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1196 prop->prop_id, level);
1197 drmModeFreeProperty(prop);
1198 drmModeFreeConnector(connector);
1199}
1200
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001201static const char *connector_type_names[] = {
1202 "None",
1203 "VGA",
1204 "DVI",
1205 "DVI",
1206 "DVI",
1207 "Composite",
1208 "TV",
1209 "LVDS",
1210 "CTV",
1211 "DIN",
1212 "DP",
1213 "HDMI",
1214 "HDMI",
1215 "TV",
1216 "eDP",
1217};
1218
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001219static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001220find_crtc_for_connector(struct drm_compositor *ec,
1221 drmModeRes *resources, drmModeConnector *connector)
1222{
1223 drmModeEncoder *encoder;
1224 uint32_t possible_crtcs;
1225 int i, j;
1226
1227 for (j = 0; j < connector->count_encoders; j++) {
1228 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1229 if (encoder == NULL) {
1230 weston_log("Failed to get encoder.\n");
1231 return -1;
1232 }
1233 possible_crtcs = encoder->possible_crtcs;
1234 drmModeFreeEncoder(encoder);
1235
1236 for (i = 0; i < resources->count_crtcs; i++) {
1237 if (possible_crtcs & (1 << i) &&
1238 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1239 return i;
1240 }
1241 }
1242
1243 return -1;
1244}
1245
1246static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001247create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001248 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001249 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001250 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001251{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001252 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001253 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1254 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001255 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001256 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001257 drmModeModeInfo crtc_mode;
1258 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001259 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001260 char name[32];
1261 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001263 i = find_crtc_for_connector(ec, resources, connector);
1264 if (i < 0) {
1265 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001266 return -1;
1267 }
1268
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001269 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001270 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001271 return -1;
1272
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001273 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001274 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1275 output->base.make = "unknown";
1276 output->base.model = "unknown";
1277 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001278
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001279 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1280 type_name = connector_type_names[connector->connector_type];
1281 else
1282 type_name = "UNKNOWN";
1283 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1284 output->name = strdup(name);
1285
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001286 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001287 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001288 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001289 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001290 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001291
Matt Roper361d2ad2011-08-29 13:52:23 -07001292 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1293
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001294 /* Get the current mode on the crtc that's currently driving
1295 * this connector. */
1296 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001297 memset(&crtc_mode, 0, sizeof crtc_mode);
1298 if (encoder != NULL) {
1299 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1300 drmModeFreeEncoder(encoder);
1301 if (crtc == NULL)
1302 goto err_free;
1303 if (crtc->mode_valid)
1304 crtc_mode = crtc->mode;
1305 drmModeFreeCrtc(crtc);
1306 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001307
David Herrmann0f0d54e2011-12-08 17:05:45 +01001308 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001309 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1310 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001311 goto err_free;
1312 }
1313
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001314 preferred = NULL;
1315 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001316 configured = NULL;
1317
1318 wl_list_for_each(temp, &configured_output_list, link) {
1319 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001320 if (temp->mode)
1321 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001322 temp->name, temp->mode);
1323 o = temp;
1324 break;
1325 }
1326 }
1327
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001328 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001329 weston_log("Disabling output %s\n", o->name);
1330
1331 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1332 0, 0, 0, 0, 0, NULL);
1333 goto err_free;
1334 }
1335
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001336 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001337 if (o && o->config == OUTPUT_CONFIG_MODE &&
1338 o->width == drm_mode->base.width &&
1339 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001340 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001341 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001342 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001343 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001344 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001345 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001346
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001347 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001348 configured = drm_output_add_mode(output, &o->crtc_mode);
1349 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001350 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001351 current = configured;
1352 }
1353
Wang Quanxianacb805a2012-07-30 18:09:46 -04001354 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001355 current = drm_output_add_mode(output, &crtc_mode);
1356 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001357 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001358 }
1359
Scott Moreau8ab5d452012-07-30 19:51:08 -06001360 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1361 configured = current;
1362
Wang Quanxianacb805a2012-07-30 18:09:46 -04001363 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001364 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001365 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001366 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001367 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001368 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001369 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001370 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001371
1372 if (output->base.current == NULL) {
1373 weston_log("no available modes for %s\n", output->name);
1374 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001375 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001376
Wang Quanxianacb805a2012-07-30 18:09:46 -04001377 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1378
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001379 output->surface = gbm_surface_create(ec->gbm,
1380 output->base.current->width,
1381 output->base.current->height,
1382 GBM_FORMAT_XRGB8888,
1383 GBM_BO_USE_SCANOUT |
1384 GBM_BO_USE_RENDERING);
1385 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001386 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001387 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001388 }
1389
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001390 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001391 eglCreateWindowSurface(ec->base.egl_display,
1392 ec->base.egl_config,
1393 output->surface,
1394 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001395 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001396 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001397 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001398 }
1399
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001400 output->cursor_bo[0] =
1401 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1402 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1403 output->cursor_bo[1] =
1404 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1405 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001406 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1407 weston_log("cursor buffers unavailable, using gl cursors\n");
1408 ec->cursors_are_broken = 1;
1409 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001410
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001411 output->backlight = backlight_init(drm_device,
1412 connector->connector_type);
1413 if (output->backlight) {
1414 output->base.set_backlight = drm_set_backlight;
1415 output->base.backlight_current = drm_get_backlight(output);
1416 }
1417
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001418 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001419 connector->mmWidth, connector->mmHeight,
1420 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001421
1422 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1423
Alex Wubd3354b2012-04-17 17:20:49 +08001424 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001425 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001426 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001427 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001428 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001429 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001430
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001431 weston_plane_init(&output->cursor_plane, 0, 0);
1432 weston_plane_init(&output->fb_plane, 0, 0);
1433
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001434 weston_log("Output %s, (connector %d, crtc %d)\n",
1435 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001436 wl_list_for_each(m, &output->base.mode_list, link)
1437 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1438 m->width, m->height, m->refresh / 1000.0,
1439 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1440 ", preferred" : "",
1441 m->flags & WL_OUTPUT_MODE_CURRENT ?
1442 ", current" : "",
1443 connector->count_modes == 0 ?
1444 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001445
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001446 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001447
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001448err_surface:
1449 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001450err_free:
1451 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1452 base.link) {
1453 wl_list_remove(&drm_mode->base.link);
1454 free(drm_mode);
1455 }
1456
1457 drmModeFreeCrtc(output->original_crtc);
1458 ec->crtc_allocator &= ~(1 << output->crtc_id);
1459 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001460 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001461 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001462
David Herrmann0f0d54e2011-12-08 17:05:45 +01001463 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001464}
1465
Jesse Barnes58ef3792012-02-23 09:45:49 -05001466static void
1467create_sprites(struct drm_compositor *ec)
1468{
1469 struct drm_sprite *sprite;
1470 drmModePlaneRes *plane_res;
1471 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001472 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001473
1474 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1475 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001476 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001477 strerror(errno));
1478 return;
1479 }
1480
1481 for (i = 0; i < plane_res->count_planes; i++) {
1482 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1483 if (!plane)
1484 continue;
1485
1486 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1487 plane->count_formats));
1488 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001489 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001490 __func__);
1491 free(plane);
1492 continue;
1493 }
1494
1495 memset(sprite, 0, sizeof *sprite);
1496
1497 sprite->possible_crtcs = plane->possible_crtcs;
1498 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001499 sprite->current = NULL;
1500 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001501 sprite->compositor = ec;
1502 sprite->count_formats = plane->count_formats;
1503 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001504 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001505 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001506 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001507
1508 wl_list_insert(&ec->sprite_list, &sprite->link);
1509 }
1510
1511 free(plane_res->planes);
1512 free(plane_res);
1513}
1514
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001515static void
1516destroy_sprites(struct drm_compositor *compositor)
1517{
1518 struct drm_sprite *sprite, *next;
1519 struct drm_output *output;
1520
1521 output = container_of(compositor->base.output_list.next,
1522 struct drm_output, base.link);
1523
1524 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1525 drmModeSetPlane(compositor->drm.fd,
1526 sprite->plane_id,
1527 output->crtc_id, 0, 0,
1528 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001529 if (sprite->current)
1530 gbm_bo_destroy(sprite->current->bo);
1531 if (sprite->next)
1532 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001533 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001534 free(sprite);
1535 }
1536}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001537
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001538static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001539create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001540 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001541{
1542 drmModeConnector *connector;
1543 drmModeRes *resources;
1544 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001545 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001546
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001547 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001548 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001549 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001550 return -1;
1551 }
1552
Jesse Barnes58ef3792012-02-23 09:45:49 -05001553 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001554 if (!ec->crtcs) {
1555 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001556 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001557 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001558
Rob Clark4339add2012-08-09 14:18:28 -05001559 ec->min_width = resources->min_width;
1560 ec->max_width = resources->max_width;
1561 ec->min_height = resources->min_height;
1562 ec->max_height = resources->max_height;
1563
Jesse Barnes58ef3792012-02-23 09:45:49 -05001564 ec->num_crtcs = resources->count_crtcs;
1565 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1566
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001567 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001568 connector = drmModeGetConnector(ec->drm.fd,
1569 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001570 if (connector == NULL)
1571 continue;
1572
1573 if (connector->connection == DRM_MODE_CONNECTED &&
1574 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001575 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001576 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001577 connector, x, y,
1578 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001579 drmModeFreeConnector(connector);
1580 continue;
1581 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001582
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001583 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001584 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001585 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001586 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001587
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001588 drmModeFreeConnector(connector);
1589 }
1590
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001591 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001592 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001593 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001594 return -1;
1595 }
1596
1597 drmModeFreeResources(resources);
1598
1599 return 0;
1600}
1601
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001602static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001603update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001604{
1605 drmModeConnector *connector;
1606 drmModeRes *resources;
1607 struct drm_output *output, *next;
1608 int x = 0, y = 0;
1609 int x_offset = 0, y_offset = 0;
1610 uint32_t connected = 0, disconnects = 0;
1611 int i;
1612
1613 resources = drmModeGetResources(ec->drm.fd);
1614 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001615 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001616 return;
1617 }
1618
1619 /* collect new connects */
1620 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001621 int connector_id = resources->connectors[i];
1622
1623 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001624 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001625 continue;
1626
David Herrmann7551cff2011-12-08 17:05:43 +01001627 if (connector->connection != DRM_MODE_CONNECTED) {
1628 drmModeFreeConnector(connector);
1629 continue;
1630 }
1631
Benjamin Franzke117483d2011-08-30 11:38:26 +02001632 connected |= (1 << connector_id);
1633
1634 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001635 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001636 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001637 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001638
1639 /* XXX: not yet needed, we die with 0 outputs */
1640 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001641 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001642 else
1643 x = 0;
1644 y = 0;
1645 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001646 connector, x, y,
1647 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001648 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001649
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001650 }
1651 drmModeFreeConnector(connector);
1652 }
1653 drmModeFreeResources(resources);
1654
1655 disconnects = ec->connector_allocator & ~connected;
1656 if (disconnects) {
1657 wl_list_for_each_safe(output, next, &ec->base.output_list,
1658 base.link) {
1659 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001660 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001661 output->base.x - x_offset,
1662 output->base.y - y_offset);
1663 }
1664
1665 if (disconnects & (1 << output->connector_id)) {
1666 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001667 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001668 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001669 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001670 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001671 }
1672 }
1673 }
1674
1675 /* FIXME: handle zero outputs, without terminating */
1676 if (ec->connector_allocator == 0)
1677 wl_display_terminate(ec->base.wl_display);
1678}
1679
1680static int
David Herrmannd7488c22012-03-11 20:05:21 +01001681udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001682{
David Herrmannd7488c22012-03-11 20:05:21 +01001683 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001684 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001685
1686 sysnum = udev_device_get_sysnum(device);
1687 if (!sysnum || atoi(sysnum) != ec->drm.id)
1688 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001689
David Herrmann6ac52db2012-03-11 20:05:22 +01001690 val = udev_device_get_property_value(device, "HOTPLUG");
1691 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001692 return 0;
1693
David Herrmann6ac52db2012-03-11 20:05:22 +01001694 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001695}
1696
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001697static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001698udev_drm_event(int fd, uint32_t mask, void *data)
1699{
1700 struct drm_compositor *ec = data;
1701 struct udev_device *event;
1702
1703 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001704
David Herrmannd7488c22012-03-11 20:05:21 +01001705 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001706 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001707
1708 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001709
1710 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001711}
1712
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001713static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001714drm_restore(struct weston_compositor *ec)
1715{
1716 struct drm_compositor *d = (struct drm_compositor *) ec;
1717
1718 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1719 weston_log("failed to drop master: %m\n");
1720 tty_reset(d->tty);
1721}
1722
Pekka Paalanen33156972012-08-03 13:30:30 -04001723static const char default_seat[] = "seat0";
1724
1725static void
1726device_added(struct udev_device *udev_device, struct drm_seat *master)
1727{
1728 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001729 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001730 const char *devnode;
1731 const char *device_seat;
1732 int fd;
1733
1734 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1735 if (!device_seat)
1736 device_seat = default_seat;
1737
1738 if (strcmp(device_seat, master->seat_id))
1739 return;
1740
1741 c = master->base.compositor;
1742 devnode = udev_device_get_devnode(udev_device);
1743
1744 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001745 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001746 * read. mtdev_get() also expects this. */
1747 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1748 if (fd < 0) {
1749 weston_log("opening input device '%s' failed.\n", devnode);
1750 return;
1751 }
1752
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001753 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001754 if (!device) {
1755 close(fd);
1756 weston_log("not using input device '%s'.\n", devnode);
1757 return;
1758 }
1759
1760 wl_list_insert(master->devices_list.prev, &device->link);
1761}
1762
1763static void
1764evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1765{
1766 struct drm_seat *seat = (struct drm_seat *) seat_base;
1767 struct udev_enumerate *e;
1768 struct udev_list_entry *entry;
1769 struct udev_device *device;
1770 const char *path, *sysname;
1771
1772 e = udev_enumerate_new(udev);
1773 udev_enumerate_add_match_subsystem(e, "input");
1774 udev_enumerate_scan_devices(e);
1775 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1776 path = udev_list_entry_get_name(entry);
1777 device = udev_device_new_from_syspath(udev, path);
1778
1779 sysname = udev_device_get_sysname(device);
1780 if (strncmp("event", sysname, 5) != 0) {
1781 udev_device_unref(device);
1782 continue;
1783 }
1784
1785 device_added(device, seat);
1786
1787 udev_device_unref(device);
1788 }
1789 udev_enumerate_unref(e);
1790
1791 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1792
1793 if (wl_list_empty(&seat->devices_list)) {
1794 weston_log(
1795 "warning: no input devices on entering Weston. "
1796 "Possible causes:\n"
1797 "\t- no permissions to read /dev/input/event*\n"
1798 "\t- seats misconfigured "
1799 "(Weston backend option 'seat', "
1800 "udev device property ID_SEAT)\n");
1801 }
1802}
1803
1804static int
1805evdev_udev_handler(int fd, uint32_t mask, void *data)
1806{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001807 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001808 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001809 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001810 const char *action;
1811 const char *devnode;
1812
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001813 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001814 if (!udev_device)
1815 return 1;
1816
1817 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001818 if (!action)
1819 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001820
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001821 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1822 goto out;
1823
1824 if (!strcmp(action, "add")) {
1825 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001826 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001827 else if (!strcmp(action, "remove")) {
1828 devnode = udev_device_get_devnode(udev_device);
1829 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1830 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001831 weston_log("input device %s, %s removed\n",
1832 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001833 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001834 break;
1835 }
1836 }
1837
1838out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001839 udev_device_unref(udev_device);
1840
1841 return 0;
1842}
1843
1844static int
1845evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1846{
1847 struct drm_seat *master = (struct drm_seat *) seat_base;
1848 struct wl_event_loop *loop;
1849 struct weston_compositor *c = master->base.compositor;
1850 int fd;
1851
1852 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1853 if (!master->udev_monitor) {
1854 weston_log("udev: failed to create the udev monitor\n");
1855 return 0;
1856 }
1857
1858 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1859 "input", NULL);
1860
1861 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1862 weston_log("udev: failed to bind the udev monitor\n");
1863 udev_monitor_unref(master->udev_monitor);
1864 return 0;
1865 }
1866
1867 loop = wl_display_get_event_loop(c->wl_display);
1868 fd = udev_monitor_get_fd(master->udev_monitor);
1869 master->udev_monitor_source =
1870 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1871 evdev_udev_handler, master);
1872 if (!master->udev_monitor_source) {
1873 udev_monitor_unref(master->udev_monitor);
1874 return 0;
1875 }
1876
1877 return 1;
1878}
1879
1880static void
1881evdev_disable_udev_monitor(struct weston_seat *seat_base)
1882{
1883 struct drm_seat *seat = (struct drm_seat *) seat_base;
1884
1885 if (!seat->udev_monitor)
1886 return;
1887
1888 udev_monitor_unref(seat->udev_monitor);
1889 seat->udev_monitor = NULL;
1890 wl_event_source_remove(seat->udev_monitor_source);
1891 seat->udev_monitor_source = NULL;
1892}
1893
1894static void
1895drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1896{
1897 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001898 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001899
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001900 wl_list_for_each(device, &seat->devices_list, link)
1901 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001902}
1903
1904static void
1905evdev_input_create(struct weston_compositor *c, struct udev *udev,
1906 const char *seat_id)
1907{
1908 struct drm_seat *seat;
1909
1910 seat = malloc(sizeof *seat);
1911 if (seat == NULL)
1912 return;
1913
1914 memset(seat, 0, sizeof *seat);
1915 weston_seat_init(&seat->base, c);
1916 seat->base.led_update = drm_led_update;
1917
1918 wl_list_init(&seat->devices_list);
1919 seat->seat_id = strdup(seat_id);
1920 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1921 free(seat->seat_id);
1922 free(seat);
1923 return;
1924 }
1925
1926 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001927}
1928
1929static void
1930evdev_remove_devices(struct weston_seat *seat_base)
1931{
1932 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001933 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001934
1935 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001936 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001937
Pekka Paalanend8583512012-08-03 14:39:11 +03001938 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001939 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001940}
1941
1942static void
1943evdev_input_destroy(struct weston_seat *seat_base)
1944{
1945 struct drm_seat *seat = (struct drm_seat *) seat_base;
1946
1947 evdev_remove_devices(seat_base);
1948 evdev_disable_udev_monitor(&seat->base);
1949
1950 weston_seat_release(seat_base);
1951 free(seat->seat_id);
1952 free(seat);
1953}
1954
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001955static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001956drm_free_configured_output(struct drm_configured_output *output)
1957{
1958 free(output->name);
1959 free(output->mode);
1960 free(output);
1961}
1962
1963static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001964drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001965{
1966 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001967 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001968 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001969
Daniel Stone37816df2012-05-16 18:45:18 +01001970 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1971 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001972 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001973 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001974
1975 wl_event_source_remove(d->udev_drm_source);
1976 wl_event_source_remove(d->drm_source);
1977
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001978 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001979
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001980 gles2_renderer_destroy(ec);
1981
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001982 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001983 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001984 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001985 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001986 eglReleaseThread();
1987
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001988 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001989 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001990 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001991 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001992 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001993
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001994 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001995}
1996
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001997static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001998drm_compositor_set_modes(struct drm_compositor *compositor)
1999{
2000 struct drm_output *output;
2001 struct drm_mode *drm_mode;
2002 int ret;
2003
2004 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2005 drm_mode = (struct drm_mode *) output->base.current;
2006 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002007 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002008 &output->connector_id, 1,
2009 &drm_mode->mode_info);
2010 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002011 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002012 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002013 drm_mode->base.width, drm_mode->base.height,
2014 output->base.x, output->base.y);
2015 }
2016 }
2017}
2018
2019static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002020vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002021{
2022 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002023 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002024 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002025 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002026
2027 switch (event) {
2028 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002029 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002030 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002031 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002032 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002033 wl_display_terminate(compositor->wl_display);
2034 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002035 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002036 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002037 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002038 wl_list_for_each(seat, &compositor->seat_list, link) {
2039 evdev_add_devices(ec->udev, seat);
2040 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002041 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002042 break;
2043 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002044 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002045 wl_list_for_each(seat, &compositor->seat_list, link) {
2046 evdev_disable_udev_monitor(seat);
2047 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002048 }
2049
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002050 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002051 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002052 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002053
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002054 /* If we have a repaint scheduled (either from a
2055 * pending pageflip or the idle handler), make sure we
2056 * cancel that so we don't try to pageflip when we're
2057 * vt switched away. The SLEEPING state will prevent
2058 * further attemps at repainting. When we switch
2059 * back, we schedule a repaint, which will process
2060 * pending frame callbacks. */
2061
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002062 wl_list_for_each(output, &ec->base.output_list, base.link) {
2063 output->base.repaint_needed = 0;
2064 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002065 }
2066
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002067 output = container_of(ec->base.output_list.next,
2068 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002069
2070 wl_list_for_each(sprite, &ec->sprite_list, link)
2071 drmModeSetPlane(ec->drm.fd,
2072 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002073 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002074 0, 0, 0, 0, 0, 0, 0, 0);
2075
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002076 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002077 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002078
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002079 break;
2080 };
2081}
2082
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002083static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002084switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002085{
2086 struct drm_compositor *ec = data;
2087
Daniel Stone325fc2d2012-05-30 16:31:58 +01002088 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002089}
2090
David Herrmann0af066f2012-10-29 19:21:16 +01002091/*
2092 * Find primary GPU
2093 * Some systems may have multiple DRM devices attached to a single seat. This
2094 * function loops over all devices and tries to find a PCI device with the
2095 * boot_vga sysfs attribute set to 1.
2096 * If no such device is found, the first DRM device reported by udev is used.
2097 */
2098static struct udev_device*
2099find_primary_gpu(struct drm_compositor *ec, const char *seat)
2100{
2101 struct udev_enumerate *e;
2102 struct udev_list_entry *entry;
2103 const char *path, *device_seat, *id;
2104 struct udev_device *device, *drm_device, *pci;
2105
2106 e = udev_enumerate_new(ec->udev);
2107 udev_enumerate_add_match_subsystem(e, "drm");
2108 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2109
2110 udev_enumerate_scan_devices(e);
2111 drm_device = NULL;
2112 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2113 path = udev_list_entry_get_name(entry);
2114 device = udev_device_new_from_syspath(ec->udev, path);
2115 if (!device)
2116 continue;
2117 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2118 if (!device_seat)
2119 device_seat = default_seat;
2120 if (strcmp(device_seat, seat)) {
2121 udev_device_unref(device);
2122 continue;
2123 }
2124
2125 pci = udev_device_get_parent_with_subsystem_devtype(device,
2126 "pci", NULL);
2127 if (pci) {
2128 id = udev_device_get_sysattr_value(pci, "boot_vga");
2129 if (id && !strcmp(id, "1")) {
2130 if (drm_device)
2131 udev_device_unref(drm_device);
2132 drm_device = device;
2133 break;
2134 }
2135 }
2136
2137 if (!drm_device)
2138 drm_device = device;
2139 else
2140 udev_device_unref(device);
2141 }
2142
2143 udev_enumerate_unref(e);
2144 return drm_device;
2145}
2146
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002147static void
2148hide_sprites_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2149 void *data)
2150{
2151 struct drm_compositor *c = data;
2152
2153 c->sprites_hidden ^= 1;
2154}
2155
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002156static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002157drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002158 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002159 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002160{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002161 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002162 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002163 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002164 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002165 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002166 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002167
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002168 weston_log("initializing drm backend\n");
2169
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002170 ec = malloc(sizeof *ec);
2171 if (ec == NULL)
2172 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002173 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002174
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002175 /* KMS support for sprites is not complete yet, so disable the
2176 * functionality for now. */
2177 ec->sprites_are_broken = 1;
2178
Daniel Stone725c2c32012-06-22 14:04:36 +01002179 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002180 config_file) < 0) {
2181 weston_log("weston_compositor_init failed\n");
2182 goto err_base;
2183 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002184
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002185 ec->udev = udev_new();
2186 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002187 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002188 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002189 }
2190
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002191 ec->base.wl_display = display;
2192 ec->tty = tty_create(&ec->base, vt_func, tty);
2193 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002194 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002195 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002196 }
2197
David Herrmann0af066f2012-10-29 19:21:16 +01002198 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002199 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002200 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002201 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002202 }
David Herrmann0af066f2012-10-29 19:21:16 +01002203 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002205 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002206 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002207 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002208 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002209
2210 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002211 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002212
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002213 ec->base.focus = 1;
2214
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002215 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002216
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002217 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002218 weston_compositor_add_key_binding(&ec->base, key,
2219 MODIFIER_CTRL | MODIFIER_ALT,
2220 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002221
Jesse Barnes58ef3792012-02-23 09:45:49 -05002222 wl_list_init(&ec->sprite_list);
2223 create_sprites(ec);
2224
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002225 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002226 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002227 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002228 }
2229
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002230 if (gles2_renderer_init(&ec->base) < 0)
2231 goto err_egl;
2232
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002233 path = NULL;
2234
Tiago Vignattice03ec32011-12-19 01:14:03 +02002235 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002236
2237 loop = wl_display_get_event_loop(ec->base.wl_display);
2238 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002239 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002240 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002241
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002242 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2243 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002244 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002245 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002246 }
2247 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2248 "drm", NULL);
2249 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002250 wl_event_loop_add_fd(loop,
2251 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002252 WL_EVENT_READABLE, udev_drm_event, ec);
2253
2254 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002255 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002256 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002257 }
2258
Daniel Stonea96b93c2012-06-22 14:04:37 +01002259 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002260
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002261 weston_compositor_add_debug_binding(&ec->base, KEY_O,
2262 hide_sprites_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002263
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002264 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002265
2266err_udev_monitor:
2267 wl_event_source_remove(ec->udev_drm_source);
2268 udev_monitor_unref(ec->udev_monitor);
2269err_drm_source:
2270 wl_event_source_remove(ec->drm_source);
2271 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2272 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002273err_egl:
2274 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2275 EGL_NO_CONTEXT);
2276 eglTerminate(ec->base.egl_display);
2277 eglReleaseThread();
2278 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002279err_sprite:
2280 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002281err_udev_dev:
2282 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002283err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002284 tty_destroy(ec->tty);
2285err_udev:
2286 udev_unref(ec->udev);
2287err_compositor:
2288 weston_compositor_shutdown(&ec->base);
2289err_base:
2290 free(ec);
2291 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002292}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002293
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002294static int
2295set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2296{
2297 mode->flags = 0;
2298
2299 if (strcmp(hsync, "+hsync") == 0)
2300 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2301 else if (strcmp(hsync, "-hsync") == 0)
2302 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2303 else
2304 return -1;
2305
2306 if (strcmp(vsync, "+vsync") == 0)
2307 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2308 else if (strcmp(vsync, "-vsync") == 0)
2309 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2310 else
2311 return -1;
2312
2313 return 0;
2314}
2315
2316static int
2317check_for_modeline(struct drm_configured_output *output)
2318{
2319 drmModeModeInfo mode;
2320 char hsync[16];
2321 char vsync[16];
2322 char mode_name[16];
2323 float fclock;
2324
2325 mode.type = DRM_MODE_TYPE_USERDEF;
2326 mode.hskew = 0;
2327 mode.vscan = 0;
2328 mode.vrefresh = 0;
2329
2330 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2331 &fclock, &mode.hdisplay,
2332 &mode.hsync_start,
2333 &mode.hsync_end, &mode.htotal,
2334 &mode.vdisplay,
2335 &mode.vsync_start,
2336 &mode.vsync_end, &mode.vtotal,
2337 hsync, vsync) == 11) {
2338 if (set_sync_flags(&mode, hsync, vsync))
2339 return -1;
2340
2341 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2342 strcpy(mode.name, mode_name);
2343
2344 mode.clock = fclock * 1000;
2345 } else
2346 return -1;
2347
2348 output->crtc_mode = mode;
2349
2350 return 0;
2351}
2352
Scott Moreau8ab5d452012-07-30 19:51:08 -06002353static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002354drm_output_set_transform(struct drm_configured_output *output)
2355{
2356 if (!output_transform) {
2357 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2358 return;
2359 }
2360
2361 if (!strcmp(output_transform, "normal"))
2362 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2363 else if (!strcmp(output_transform, "90"))
2364 output->transform = WL_OUTPUT_TRANSFORM_90;
2365 else if (!strcmp(output_transform, "180"))
2366 output->transform = WL_OUTPUT_TRANSFORM_180;
2367 else if (!strcmp(output_transform, "270"))
2368 output->transform = WL_OUTPUT_TRANSFORM_270;
2369 else if (!strcmp(output_transform, "flipped"))
2370 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2371 else if (!strcmp(output_transform, "flipped-90"))
2372 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2373 else if (!strcmp(output_transform, "flipped-180"))
2374 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2375 else if (!strcmp(output_transform, "flipped-270"))
2376 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2377 else {
2378 weston_log("Invalid transform \"%s\" for output %s\n",
2379 output_transform, output_name);
2380 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2381 }
2382
2383 free(output_transform);
2384 output_transform = NULL;
2385}
2386
2387static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002388output_section_done(void *data)
2389{
2390 struct drm_configured_output *output;
2391
2392 output = malloc(sizeof *output);
2393
Scott Moreau1bad5db2012-08-18 01:04:05 -06002394 if (!output || !output_name || (output_name[0] == 'X') ||
2395 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002396 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002397 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002398 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002399 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002400 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002401 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002402 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002403 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002404 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002405
2406 output->config = OUTPUT_CONFIG_INVALID;
2407 output->name = output_name;
2408 output->mode = output_mode;
2409
Scott Moreau1bad5db2012-08-18 01:04:05 -06002410 if (output_mode) {
2411 if (strcmp(output_mode, "off") == 0)
2412 output->config = OUTPUT_CONFIG_OFF;
2413 else if (strcmp(output_mode, "preferred") == 0)
2414 output->config = OUTPUT_CONFIG_PREFERRED;
2415 else if (strcmp(output_mode, "current") == 0)
2416 output->config = OUTPUT_CONFIG_CURRENT;
2417 else if (sscanf(output_mode, "%dx%d",
2418 &output->width, &output->height) == 2)
2419 output->config = OUTPUT_CONFIG_MODE;
2420 else if (check_for_modeline(output) == 0)
2421 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002422
Scott Moreau1bad5db2012-08-18 01:04:05 -06002423 if (output->config == OUTPUT_CONFIG_INVALID)
2424 weston_log("Invalid mode \"%s\" for output %s\n",
2425 output_mode, output_name);
2426 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002427 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002428
2429 drm_output_set_transform(output);
2430
2431 wl_list_insert(&configured_output_list, &output->link);
2432
2433 if (output_transform)
2434 free(output_transform);
2435 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002436}
2437
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002438WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002439backend_init(struct wl_display *display, int argc, char *argv[],
2440 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002441{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002442 int connector = 0, tty = 0;
2443 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002444
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002445 const struct weston_option drm_options[] = {
2446 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2447 { WESTON_OPTION_STRING, "seat", 0, &seat },
2448 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002449 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002450 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002451
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002452 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002453
Scott Moreau8ab5d452012-07-30 19:51:08 -06002454 wl_list_init(&configured_output_list);
2455
2456 const struct config_key drm_config_keys[] = {
2457 { "name", CONFIG_KEY_STRING, &output_name },
2458 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002459 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002460 };
2461
2462 const struct config_section config_section[] = {
2463 { "output", drm_config_keys,
2464 ARRAY_LENGTH(drm_config_keys), output_section_done },
2465 };
2466
2467 parse_config_file(config_file, config_section,
2468 ARRAY_LENGTH(config_section), NULL);
2469
Daniel Stonec1be8e52012-06-01 11:14:02 -04002470 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2471 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002472}