blob: 42546fffe27db4b603256911bfc467ec7a480e6c [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020043#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010044#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Kristian Høgsberg061c4252012-06-28 11:28:15 -040046static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060047static char *output_name;
48static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060049static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060050static struct wl_list configured_output_list;
51
52enum output_config {
53 OUTPUT_CONFIG_INVALID = 0,
54 OUTPUT_CONFIG_OFF,
55 OUTPUT_CONFIG_PREFERRED,
56 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060057 OUTPUT_CONFIG_MODE,
58 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060059};
60
61struct drm_configured_output {
62 char *name;
63 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060064 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060066 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060067 enum output_config config;
68 struct wl_list link;
69};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040070
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050072 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
74 struct udev *udev;
75 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010077 struct udev_monitor *udev_monitor;
78 struct wl_event_source *udev_drm_source;
79
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010081 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 int fd;
83 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020084 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050085 uint32_t *crtcs;
86 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050087 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010088 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050089 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020095 uint32_t min_width, max_width;
96 uint32_t min_height, max_height;
97 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050098
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200101 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102
Rob Clarkab5b1e32012-08-09 13:24:45 -0500103 int cursors_are_broken;
104
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200105 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400106};
107
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400108struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500109 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400110 drmModeModeInfo mode_info;
111};
112
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300113struct drm_output;
114
115struct drm_fb {
116 struct gbm_bo *bo;
117 struct drm_output *output;
118 uint32_t fb_id;
119 int is_client_buffer;
120 struct wl_buffer *buffer;
121 struct wl_listener buffer_destroy_listener;
122};
123
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400124struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500125 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400127 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400128 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500129 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400130 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700131 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200132
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300133 int vblank_pending;
134 int page_flip_pending;
135
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400136 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400137 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400138 struct weston_plane cursor_plane;
139 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400140 struct weston_surface *cursor_surface;
141 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300142 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200143 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144};
145
Jesse Barnes58ef3792012-02-23 09:45:49 -0500146/*
147 * An output has a primary display plane plus zero or more sprites for
148 * blending display contents.
149 */
150struct drm_sprite {
151 struct wl_list link;
152
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400153 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500154
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200155 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300156 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500157 struct drm_compositor *compositor;
158
Jesse Barnes58ef3792012-02-23 09:45:49 -0500159 uint32_t possible_crtcs;
160 uint32_t plane_id;
161 uint32_t count_formats;
162
163 int32_t src_x, src_y;
164 uint32_t src_w, src_h;
165 uint32_t dest_x, dest_y;
166 uint32_t dest_w, dest_h;
167
168 uint32_t formats[];
169};
170
Pekka Paalanen33156972012-08-03 13:30:30 -0400171struct drm_seat {
172 struct weston_seat base;
173 struct wl_list devices_list;
174 struct udev_monitor *udev_monitor;
175 struct wl_event_source *udev_monitor_source;
176 char *seat_id;
177};
178
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400179static void
180drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400181
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
184{
185 struct weston_compositor *ec = output_base->compositor;
186 struct drm_compositor *c =(struct drm_compositor *) ec;
187 struct drm_output *output = (struct drm_output *) output_base;
188 int crtc;
189
190 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
191 if (c->crtcs[crtc] != output->crtc_id)
192 continue;
193
194 if (supported & (1 << crtc))
195 return -1;
196 }
197
198 return 0;
199}
200
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300201static void
202drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
203{
204 struct drm_fb *fb = data;
205 struct gbm_device *gbm = gbm_bo_get_device(bo);
206
207 if (fb->fb_id)
208 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
209
210 if (fb->buffer) {
211 weston_buffer_post_release(fb->buffer);
212 wl_list_remove(&fb->buffer_destroy_listener.link);
213 }
214
215 free(data);
216}
217
218static struct drm_fb *
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200219drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_compositor *compositor)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300220{
221 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200222 uint32_t width, height, stride, handle, format;
223 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300224 int ret;
225
226 if (fb)
227 return fb;
228
229 fb = malloc(sizeof *fb);
230
231 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232 fb->is_client_buffer = 0;
233 fb->buffer = NULL;
234
235 width = gbm_bo_get_width(bo);
236 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400237 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300238 handle = gbm_bo_get_handle(bo).u32;
239
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200240 if (compositor->min_width > width || width > compositor->max_width ||
241 compositor->min_height > height ||
242 height > compositor->max_height) {
243 weston_log("bo geometry out of bounds\n");
244 goto err_free;
245 }
246
247 ret = -1;
248
249 format = gbm_bo_get_format(bo);
250
251 if (format && !compositor->no_addfb2) {
252 handles[0] = handle;
253 pitches[0] = stride;
254 offsets[0] = 0;
255
256 ret = drmModeAddFB2(compositor->drm.fd, width, height,
257 format, handles, pitches, offsets,
258 &fb->fb_id, 0);
259 if (ret) {
260 weston_log("addfb2 failed: %m\n");
261 compositor->no_addfb2 = 1;
262 compositor->sprites_are_broken = 1;
263 }
264 }
265
266 if (ret)
267 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
268 stride, handle, &fb->fb_id);
269
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300270 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200271 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200272 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300273 }
274
275 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
276
277 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200278
279err_free:
280 free(fb);
281 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300282}
283
284static void
285fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
286{
287 struct drm_fb *fb = container_of(listener, struct drm_fb,
288 buffer_destroy_listener);
289
290 fb->buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300291}
292
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200293static void
294drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
295{
296 assert(fb->buffer == NULL);
297
298 fb->is_client_buffer = 1;
299 fb->buffer = buffer;
300 fb->buffer->busy_count++;
301 fb->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
302
303 wl_signal_add(&fb->buffer->resource.destroy_signal,
304 &fb->buffer_destroy_listener);
305}
306
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400307static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400308drm_output_prepare_scanout_surface(struct weston_output *_output,
309 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500310{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400311 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500312 struct drm_compositor *c =
313 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300314 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500315
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500316 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200317 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200318 es->geometry.width != output->base.current->width ||
319 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200320 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400321 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400322 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500323
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400324 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
325 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500326
Rob Bradford9b101872012-09-14 23:25:41 +0100327 /* Unable to use the buffer for scanout */
328 if (!bo)
329 return NULL;
330
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300331 /* Need to verify output->region contained in surface opaque
332 * region. Or maybe just that format doesn't have alpha.
333 * For now, scanout only if format is XRGB8888. */
334 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
335 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400336 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300337 }
338
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200339 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300340 if (!output->next) {
341 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400342 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300343 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500344
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200345 drm_fb_set_buffer(output->next, es->buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500346
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400347 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500348}
349
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500350static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400351drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400352{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200353 struct drm_compositor *c =
354 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300355 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400356
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200357 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400358
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 bo = gbm_surface_lock_front_buffer(output->surface);
360 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200361 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400362 return;
363 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300364
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200365 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200367 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368 gbm_surface_release_buffer(output->surface, bo);
369 return;
370 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400371}
372
373static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500374drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400375 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100376{
377 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500378 struct drm_compositor *compositor =
379 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500380 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400381 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500382 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100383
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300384 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400385 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300386 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400387 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100388
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400389 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300390 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400391 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300392 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400393 &output->connector_id, 1,
394 &mode->mode_info);
395 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200396 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400397 return;
398 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200399 }
400
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500401 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300402 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500403 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200404 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500405 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500406 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100407
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300408 output->page_flip_pending = 1;
409
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400410 drm_output_set_cursor(output);
411
Jesse Barnes58ef3792012-02-23 09:45:49 -0500412 /*
413 * Now, update all the sprite surfaces
414 */
415 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200416 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500417 drmVBlank vbl = {
418 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
419 .request.sequence = 1,
420 };
421
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200422 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200423 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500424 continue;
425
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200426 if (s->next && !compositor->sprites_hidden)
427 fb_id = s->next->fb_id;
428
Jesse Barnes58ef3792012-02-23 09:45:49 -0500429 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200430 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431 s->dest_x, s->dest_y,
432 s->dest_w, s->dest_h,
433 s->src_x, s->src_y,
434 s->src_w, s->src_h);
435 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200436 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500437 ret, strerror(errno));
438
Rob Clark5ca1a472012-08-08 20:27:37 -0500439 if (output->pipe > 0)
440 vbl.request.type |= DRM_VBLANK_SECONDARY;
441
Jesse Barnes58ef3792012-02-23 09:45:49 -0500442 /*
443 * Queue a vblank signal so we know when the surface
444 * becomes active on the display or has been replaced.
445 */
446 vbl.request.signal = (unsigned long)s;
447 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
448 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200449 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500450 ret, strerror(errno));
451 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300452
453 s->output = output;
454 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500455 }
456
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500457 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400458}
459
460static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500461vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
462 void *data)
463{
464 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300465 struct drm_output *output = s->output;
466 uint32_t msecs;
467
468 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500469
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200470 if (s->current)
471 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500472
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200473 s->current = s->next;
474 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300475
476 if (!output->page_flip_pending) {
477 msecs = sec * 1000 + usec / 1000;
478 weston_output_finish_frame(&output->base, msecs);
479 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500480}
481
482static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400483page_flip_handler(int fd, unsigned int frame,
484 unsigned int sec, unsigned int usec, void *data)
485{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200486 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400487 uint32_t msecs;
488
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300489 output->page_flip_pending = 0;
490
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300491 if (output->current) {
492 if (output->current->is_client_buffer)
493 gbm_bo_destroy(output->current->bo);
494 else
495 gbm_surface_release_buffer(output->surface,
496 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200497 }
498
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499 output->current = output->next;
500 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300502 if (!output->vblank_pending) {
503 msecs = sec * 1000 + usec / 1000;
504 weston_output_finish_frame(&output->base, msecs);
505 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200506}
507
508static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500509drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
510{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400511 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500512
513 for (i = 0; i < s->count_formats; i++)
514 if (s->formats[i] == format)
515 return 1;
516
517 return 0;
518}
519
520static int
521drm_surface_transform_supported(struct weston_surface *es)
522{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400523 struct weston_matrix *matrix = &es->transform.matrix;
524 int i;
525
526 if (!es->transform.enabled)
527 return 1;
528
529 for (i = 0; i < 16; i++) {
530 switch (i) {
531 case 10:
532 case 15:
533 if (matrix->d[i] != 1.0)
534 return 0;
535 break;
536 case 0:
537 case 5:
538 case 12:
539 case 13:
540 break;
541 default:
542 if (matrix->d[i] != 0.0)
543 return 0;
544 break;
545 }
546 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500547
548 return 1;
549}
550
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400551static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500552drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400553 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500554{
555 struct weston_compositor *ec = output_base->compositor;
556 struct drm_compositor *c =(struct drm_compositor *) ec;
557 struct drm_sprite *s;
558 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500559 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500560 pixman_region32_t dest_rect, src_rect;
561 pixman_box32_t *box;
562 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400563 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500564
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500565 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400566 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500567
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300568 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400569 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300570
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400571 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400572 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573
Rob Clark702ffae2012-08-09 14:18:27 -0500574 if (wl_buffer_is_shm(es->buffer))
575 return NULL;
576
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400578 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500579
Jesse Barnes58ef3792012-02-23 09:45:49 -0500580 wl_list_for_each(s, &c->sprite_list, link) {
581 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
582 continue;
583
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200584 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500585 found = 1;
586 break;
587 }
588 }
589
590 /* No sprites available */
591 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400592 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500593
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400594 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
595 es->buffer, GBM_BO_USE_SCANOUT);
596 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400597 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400598
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200601 if (!drm_surface_format_supported(s, format)) {
602 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400603 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604 }
605
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200606 s->next = drm_fb_get_from_bo(bo, c);
607 if (!s->next) {
608 gbm_bo_destroy(bo);
609 return NULL;
610 }
611
612 drm_fb_set_buffer(s->next, es->buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400614 box = pixman_region32_extents(&es->transform.boundingbox);
615 s->plane.x = box->x1;
616 s->plane.y = box->y1;
617
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 /*
619 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200620 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 * for us already).
622 */
623 pixman_region32_init(&dest_rect);
624 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
625 &output_base->region);
626 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
627 box = pixman_region32_extents(&dest_rect);
628 s->dest_x = box->x1;
629 s->dest_y = box->y1;
630 s->dest_w = box->x2 - box->x1;
631 s->dest_h = box->y2 - box->y1;
632 pixman_region32_fini(&dest_rect);
633
634 pixman_region32_init(&src_rect);
635 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
636 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500637 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400638
639 weston_surface_from_global_fixed(es,
640 wl_fixed_from_int(box->x1),
641 wl_fixed_from_int(box->y1),
642 &sx1, &sy1);
643 weston_surface_from_global_fixed(es,
644 wl_fixed_from_int(box->x2),
645 wl_fixed_from_int(box->y2),
646 &sx2, &sy2);
647
648 if (sx1 < 0)
649 sx1 = 0;
650 if (sy1 < 0)
651 sy1 = 0;
652 if (sx2 > wl_fixed_from_int(es->geometry.width))
653 sx2 = wl_fixed_from_int(es->geometry.width);
654 if (sy2 > wl_fixed_from_int(es->geometry.height))
655 sy2 = wl_fixed_from_int(es->geometry.height);
656
657 s->src_x = sx1 << 8;
658 s->src_y = sy1 << 8;
659 s->src_w = (sx2 - sx1) << 8;
660 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500661 pixman_region32_fini(&src_rect);
662
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400663 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500664}
665
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400666static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400667drm_output_prepare_cursor_surface(struct weston_output *output_base,
668 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500669{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400670 struct drm_compositor *c =
671 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400672 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400673
674 if (output->cursor_surface)
675 return NULL;
676 if (es->output_mask != (1u << output_base->id))
677 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500678 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400679 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400680 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
681 es->geometry.width > 64 || es->geometry.height > 64)
682 return NULL;
683
684 output->cursor_surface = es;
685
686 return &output->cursor_plane;
687}
688
689static void
690drm_output_set_cursor(struct drm_output *output)
691{
692 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400693 struct drm_compositor *c =
694 (struct drm_compositor *) output->base.compositor;
695 EGLint handle, stride;
696 struct gbm_bo *bo;
697 uint32_t buf[64 * 64];
698 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400699 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500700
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400701 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400702 if (es == NULL) {
703 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
704 return;
705 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500706
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400707 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
708 pixman_region32_fini(&output->cursor_plane.damage);
709 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400710 output->current_cursor ^= 1;
711 bo = output->cursor_bo[output->current_cursor];
712 memset(buf, 0, sizeof buf);
713 stride = wl_shm_buffer_get_stride(es->buffer);
714 s = wl_shm_buffer_get_data(es->buffer);
715 for (i = 0; i < es->geometry.height; i++)
716 memcpy(buf + i * 64, s + i * stride,
717 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500718
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400719 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300720 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400721
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400722 handle = gbm_bo_get_handle(bo).s32;
723 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500724 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300725 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500726 c->cursors_are_broken = 1;
727 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400728 }
729
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400730 x = es->geometry.x - output->base.x;
731 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400732 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500733 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400734 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500735 c->cursors_are_broken = 1;
736 }
737
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400738 output->cursor_plane.x = x;
739 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400740 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500741}
742
Jesse Barnes58ef3792012-02-23 09:45:49 -0500743static void
744drm_assign_planes(struct weston_output *output)
745{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400746 struct drm_compositor *c =
747 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200748 struct drm_output *drm_output = (struct drm_output *) output;
749 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400750 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500751 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400752 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500753
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200754 /* Reset the opaque region of the planes */
755 pixman_region32_fini(&drm_output->cursor_plane.opaque);
756 pixman_region32_init(&drm_output->cursor_plane.opaque);
757 pixman_region32_fini(&drm_output->fb_plane.opaque);
758 pixman_region32_init(&drm_output->fb_plane.opaque);
759
760 wl_list_for_each (s, &c->sprite_list, link) {
761 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
762 continue;
763
764 pixman_region32_fini(&s->plane.opaque);
765 pixman_region32_init(&s->plane.opaque);
766 }
767
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768 /*
769 * Find a surface for each sprite in the output using some heuristics:
770 * 1) size
771 * 2) frequency of update
772 * 3) opacity (though some hw might support alpha blending)
773 * 4) clipping (this can be fixed with color keys)
774 *
775 * The idea is to save on blitting since this should save power.
776 * If we can get a large video surface on the sprite for example,
777 * the main display surface may not need to update at all, and
778 * the client buffer can be used directly for the sprite surface
779 * as we do for flipping full screen surfaces.
780 */
781 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400782 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400783 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500784 pixman_region32_init(&surface_overlap);
785 pixman_region32_intersect(&surface_overlap, &overlap,
786 &es->transform.boundingbox);
787
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400788 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400789 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400790 next_plane = primary;
791 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400792 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400793 if (next_plane == NULL)
794 next_plane = drm_output_prepare_scanout_surface(output, es);
795 if (next_plane == NULL)
796 next_plane = drm_output_prepare_overlay_surface(output, es);
797 if (next_plane == NULL)
798 next_plane = primary;
799 weston_surface_move_to_plane(es, next_plane);
800 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 pixman_region32_union(&overlap, &overlap,
802 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400803
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804 pixman_region32_fini(&surface_overlap);
805 }
806 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500807}
808
Matt Roper361d2ad2011-08-29 13:52:23 -0700809static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500810drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700811{
812 struct drm_output *output = (struct drm_output *) output_base;
813 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200814 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700815 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700816
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200817 if (output->backlight)
818 backlight_destroy(output->backlight);
819
Matt Roper361d2ad2011-08-29 13:52:23 -0700820 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400821 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700822
823 /* Restore original CRTC state */
824 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200825 origcrtc->x, origcrtc->y,
826 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700827 drmModeFreeCrtc(origcrtc);
828
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200829 c->crtc_allocator &= ~(1 << output->crtc_id);
830 c->connector_allocator &= ~(1 << output->connector_id);
831
John Kåre Alsaker94659272012-11-13 19:10:18 +0100832 gles2_renderer_output_destroy(output_base);
833
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400834 gbm_surface_destroy(output->surface);
835
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400836 weston_plane_release(&output->fb_plane);
837 weston_plane_release(&output->cursor_plane);
838
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500839 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200840 wl_list_remove(&output->base.link);
841
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400842 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700843 free(output);
844}
845
Alex Wub7b8bda2012-04-17 17:20:48 +0800846static struct drm_mode *
847choose_mode (struct drm_output *output, struct weston_mode *target_mode)
848{
849 struct drm_mode *tmp_mode = NULL, *mode;
850
851 if (output->base.current->width == target_mode->width &&
852 output->base.current->height == target_mode->height &&
853 (output->base.current->refresh == target_mode->refresh ||
854 target_mode->refresh == 0))
855 return (struct drm_mode *)output->base.current;
856
857 wl_list_for_each(mode, &output->base.mode_list, base.link) {
858 if (mode->mode_info.hdisplay == target_mode->width &&
859 mode->mode_info.vdisplay == target_mode->height) {
860 if (mode->mode_info.vrefresh == target_mode->refresh ||
861 target_mode->refresh == 0) {
862 return mode;
863 } else if (!tmp_mode)
864 tmp_mode = mode;
865 }
866 }
867
868 return tmp_mode;
869}
870
871static int
872drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
873{
874 struct drm_output *output;
875 struct drm_mode *drm_mode;
876 int ret;
877 struct drm_compositor *ec;
878 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800879
880 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200881 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800882 return -1;
883 }
884
885 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200886 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800887 return -1;
888 }
889
890 ec = (struct drm_compositor *)output_base->compositor;
891 output = (struct drm_output *)output_base;
892 drm_mode = choose_mode (output, mode);
893
894 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200895 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800896 return -1;
897 } else if (&drm_mode->base == output->base.current) {
898 return 0;
899 } else if (drm_mode->base.width == output->base.current->width &&
900 drm_mode->base.height == output->base.current->height) {
901 /* only change refresh value */
902 ret = drmModeSetCrtc(ec->drm.fd,
903 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300904 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800905 &output->connector_id, 1, &drm_mode->mode_info);
906
907 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200908 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800909 drm_mode->base.width,
910 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400911 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800912 ret = -1;
913 } else {
914 output->base.current->flags = 0;
915 output->base.current = &drm_mode->base;
916 drm_mode->base.flags =
917 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
918 ret = 0;
919 }
920
921 return ret;
922 }
923
924 drm_mode->base.flags =
925 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
926
927 surface = gbm_surface_create(ec->gbm,
928 drm_mode->base.width,
929 drm_mode->base.height,
930 GBM_FORMAT_XRGB8888,
931 GBM_BO_USE_SCANOUT |
932 GBM_BO_USE_RENDERING);
933 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200934 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800935 return -1;
936 }
937
John Kåre Alsaker94659272012-11-13 19:10:18 +0100938 gles2_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800939
John Kåre Alsaker94659272012-11-13 19:10:18 +0100940 if (!gles2_renderer_output_create(&output->base, surface)) {
941 weston_log("failed to create renderer output\n");
942 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800943 }
944
945 ret = drmModeSetCrtc(ec->drm.fd,
946 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300947 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800948 &output->connector_id, 1, &drm_mode->mode_info);
949 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200950 weston_log("failed to set mode\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +0100951 goto err_gles2;
Alex Wub7b8bda2012-04-17 17:20:48 +0800952 }
953
954 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300955 if (output->current) {
956 if (output->current->is_client_buffer)
957 gbm_bo_destroy(output->current->bo);
958 else
959 gbm_surface_release_buffer(output->surface,
960 output->current->bo);
961 }
962 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800963
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300964 if (output->next) {
965 if (output->next->is_client_buffer)
966 gbm_bo_destroy(output->next->bo);
967 else
968 gbm_surface_release_buffer(output->surface,
969 output->next->bo);
970 }
971 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800972
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800974 output->surface = surface;
975
976 /*update output*/
977 output->base.current = &drm_mode->base;
978 output->base.dirty = 1;
979 weston_output_move(&output->base, output->base.x, output->base.y);
980 return 0;
981
John Kåre Alsaker94659272012-11-13 19:10:18 +0100982err_gles2:
983 gles2_renderer_output_destroy(&output->base);
984err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +0800985 gbm_surface_destroy(surface);
986 return -1;
987}
988
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400989static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400990on_drm_input(int fd, uint32_t mask, void *data)
991{
992 drmEventContext evctx;
993
994 memset(&evctx, 0, sizeof evctx);
995 evctx.version = DRM_EVENT_CONTEXT_VERSION;
996 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500997 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400998 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400999
1000 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001001}
1002
1003static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001004init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001005{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001006 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001007 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001008
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001009 sysnum = udev_device_get_sysnum(device);
1010 if (sysnum)
1011 ec->drm.id = atoi(sysnum);
1012 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001013 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001014 return -1;
1015 }
1016
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001017 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001018 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001019 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001020 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001021 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001022 udev_device_get_devnode(device));
1023 return -1;
1024 }
1025
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001026 weston_log("using %s\n", filename);
1027
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001028 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001029 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001030
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001031 if (gles2_renderer_create(&ec->base, ec->gbm, gles2_renderer_opaque_attribs,
1032 NULL) < 0) {
1033 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001034 return -1;
1035 }
1036
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001037 return 0;
1038}
1039
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001040static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001041drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1042{
1043 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001044 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001045
1046 mode = malloc(sizeof *mode);
1047 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001048 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001049
1050 mode->base.flags = 0;
1051 mode->base.width = info->hdisplay;
1052 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001053
1054 /* Calculate higher precision (mHz) refresh rate */
1055 refresh = (info->clock * 1000000LL / info->htotal +
1056 info->vtotal / 2) / info->vtotal;
1057
1058 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1059 refresh *= 2;
1060 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1061 refresh /= 2;
1062 if (info->vscan > 1)
1063 refresh /= info->vscan;
1064
1065 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001066 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001067
1068 if (info->type & DRM_MODE_TYPE_PREFERRED)
1069 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1070
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001071 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1072
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001073 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001074}
1075
1076static int
1077drm_subpixel_to_wayland(int drm_value)
1078{
1079 switch (drm_value) {
1080 default:
1081 case DRM_MODE_SUBPIXEL_UNKNOWN:
1082 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1083 case DRM_MODE_SUBPIXEL_NONE:
1084 return WL_OUTPUT_SUBPIXEL_NONE;
1085 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1086 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1087 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1088 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1089 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1090 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1091 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1092 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1093 }
1094}
1095
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001096/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001097static uint32_t
1098drm_get_backlight(struct drm_output *output)
1099{
1100 long brightness, max_brightness, norm;
1101
1102 brightness = backlight_get_brightness(output->backlight);
1103 max_brightness = backlight_get_max_brightness(output->backlight);
1104
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001105 /* convert it on a scale of 0 to 255 */
1106 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001107
1108 return (uint32_t) norm;
1109}
1110
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001111/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001112static void
1113drm_set_backlight(struct weston_output *output_base, uint32_t value)
1114{
1115 struct drm_output *output = (struct drm_output *) output_base;
1116 long max_brightness, new_brightness;
1117
1118 if (!output->backlight)
1119 return;
1120
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001121 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001122 return;
1123
1124 max_brightness = backlight_get_max_brightness(output->backlight);
1125
1126 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001127 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001128
1129 backlight_set_brightness(output->backlight, new_brightness);
1130}
1131
1132static drmModePropertyPtr
1133drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1134{
1135 drmModePropertyPtr props;
1136 int i;
1137
1138 for (i = 0; i < connector->count_props; i++) {
1139 props = drmModeGetProperty(fd, connector->props[i]);
1140 if (!props)
1141 continue;
1142
1143 if (!strcmp(props->name, name))
1144 return props;
1145
1146 drmModeFreeProperty(props);
1147 }
1148
1149 return NULL;
1150}
1151
1152static void
1153drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1154{
1155 struct drm_output *output = (struct drm_output *) output_base;
1156 struct weston_compositor *ec = output_base->compositor;
1157 struct drm_compositor *c = (struct drm_compositor *) ec;
1158 drmModeConnectorPtr connector;
1159 drmModePropertyPtr prop;
1160
1161 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1162 if (!connector)
1163 return;
1164
1165 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1166 if (!prop) {
1167 drmModeFreeConnector(connector);
1168 return;
1169 }
1170
1171 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1172 prop->prop_id, level);
1173 drmModeFreeProperty(prop);
1174 drmModeFreeConnector(connector);
1175}
1176
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001177static const char *connector_type_names[] = {
1178 "None",
1179 "VGA",
1180 "DVI",
1181 "DVI",
1182 "DVI",
1183 "Composite",
1184 "TV",
1185 "LVDS",
1186 "CTV",
1187 "DIN",
1188 "DP",
1189 "HDMI",
1190 "HDMI",
1191 "TV",
1192 "eDP",
1193};
1194
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001195static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001196find_crtc_for_connector(struct drm_compositor *ec,
1197 drmModeRes *resources, drmModeConnector *connector)
1198{
1199 drmModeEncoder *encoder;
1200 uint32_t possible_crtcs;
1201 int i, j;
1202
1203 for (j = 0; j < connector->count_encoders; j++) {
1204 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1205 if (encoder == NULL) {
1206 weston_log("Failed to get encoder.\n");
1207 return -1;
1208 }
1209 possible_crtcs = encoder->possible_crtcs;
1210 drmModeFreeEncoder(encoder);
1211
1212 for (i = 0; i < resources->count_crtcs; i++) {
1213 if (possible_crtcs & (1 << i) &&
1214 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1215 return i;
1216 }
1217 }
1218
1219 return -1;
1220}
1221
1222static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001223create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001224 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001225 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001226 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001227{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001228 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001229 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1230 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001231 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001232 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001233 drmModeModeInfo crtc_mode;
1234 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001235 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001236 char name[32];
1237 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001238
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001239 i = find_crtc_for_connector(ec, resources, connector);
1240 if (i < 0) {
1241 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001242 return -1;
1243 }
1244
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001245 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001246 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001247 return -1;
1248
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001249 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001250 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1251 output->base.make = "unknown";
1252 output->base.model = "unknown";
1253 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001254
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001255 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1256 type_name = connector_type_names[connector->connector_type];
1257 else
1258 type_name = "UNKNOWN";
1259 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1260 output->name = strdup(name);
1261
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001263 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001264 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001265 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001266 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001267
Matt Roper361d2ad2011-08-29 13:52:23 -07001268 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1269
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001270 /* Get the current mode on the crtc that's currently driving
1271 * this connector. */
1272 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001273 memset(&crtc_mode, 0, sizeof crtc_mode);
1274 if (encoder != NULL) {
1275 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1276 drmModeFreeEncoder(encoder);
1277 if (crtc == NULL)
1278 goto err_free;
1279 if (crtc->mode_valid)
1280 crtc_mode = crtc->mode;
1281 drmModeFreeCrtc(crtc);
1282 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001283
David Herrmann0f0d54e2011-12-08 17:05:45 +01001284 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001285 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1286 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001287 goto err_free;
1288 }
1289
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001290 preferred = NULL;
1291 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001292 configured = NULL;
1293
1294 wl_list_for_each(temp, &configured_output_list, link) {
1295 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001296 if (temp->mode)
1297 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001298 temp->name, temp->mode);
1299 o = temp;
1300 break;
1301 }
1302 }
1303
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001304 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001305 weston_log("Disabling output %s\n", o->name);
1306
1307 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1308 0, 0, 0, 0, 0, NULL);
1309 goto err_free;
1310 }
1311
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001312 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001313 if (o && o->config == OUTPUT_CONFIG_MODE &&
1314 o->width == drm_mode->base.width &&
1315 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001316 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001317 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001318 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001319 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001320 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001321 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001322
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001323 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001324 configured = drm_output_add_mode(output, &o->crtc_mode);
1325 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001326 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001327 current = configured;
1328 }
1329
Wang Quanxianacb805a2012-07-30 18:09:46 -04001330 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001331 current = drm_output_add_mode(output, &crtc_mode);
1332 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001333 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001334 }
1335
Scott Moreau8ab5d452012-07-30 19:51:08 -06001336 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1337 configured = current;
1338
Wang Quanxianacb805a2012-07-30 18:09:46 -04001339 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001340 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001341 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001342 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001343 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001344 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001345 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001346 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001347
1348 if (output->base.current == NULL) {
1349 weston_log("no available modes for %s\n", output->name);
1350 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001351 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001352
Wang Quanxianacb805a2012-07-30 18:09:46 -04001353 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1354
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001355 output->surface = gbm_surface_create(ec->gbm,
1356 output->base.current->width,
1357 output->base.current->height,
1358 GBM_FORMAT_XRGB8888,
1359 GBM_BO_USE_SCANOUT |
1360 GBM_BO_USE_RENDERING);
1361 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001362 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001363 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001364 }
1365
John Kåre Alsaker94659272012-11-13 19:10:18 +01001366 weston_output_init(&output->base, &ec->base, x, y,
1367 connector->mmWidth, connector->mmHeight,
1368 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1369
1370 if (gles2_renderer_output_create(&output->base, output->surface) < 0)
1371 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001372
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001373 output->cursor_bo[0] =
1374 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1375 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1376 output->cursor_bo[1] =
1377 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1378 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001379 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1380 weston_log("cursor buffers unavailable, using gl cursors\n");
1381 ec->cursors_are_broken = 1;
1382 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001383
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001384 output->backlight = backlight_init(drm_device,
1385 connector->connector_type);
1386 if (output->backlight) {
1387 output->base.set_backlight = drm_set_backlight;
1388 output->base.backlight_current = drm_get_backlight(output);
1389 }
1390
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001391 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1392
Alex Wubd3354b2012-04-17 17:20:49 +08001393 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001394 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001395 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001396 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001397 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001398 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001399
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001400 weston_plane_init(&output->cursor_plane, 0, 0);
1401 weston_plane_init(&output->fb_plane, 0, 0);
1402
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001403 weston_log("Output %s, (connector %d, crtc %d)\n",
1404 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001405 wl_list_for_each(m, &output->base.mode_list, link)
1406 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1407 m->width, m->height, m->refresh / 1000.0,
1408 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1409 ", preferred" : "",
1410 m->flags & WL_OUTPUT_MODE_CURRENT ?
1411 ", current" : "",
1412 connector->count_modes == 0 ?
1413 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001414
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001415 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001416
John Kåre Alsaker94659272012-11-13 19:10:18 +01001417err_output:
1418 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001419 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001420err_free:
1421 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1422 base.link) {
1423 wl_list_remove(&drm_mode->base.link);
1424 free(drm_mode);
1425 }
1426
1427 drmModeFreeCrtc(output->original_crtc);
1428 ec->crtc_allocator &= ~(1 << output->crtc_id);
1429 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001430 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001431 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001432
David Herrmann0f0d54e2011-12-08 17:05:45 +01001433 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001434}
1435
Jesse Barnes58ef3792012-02-23 09:45:49 -05001436static void
1437create_sprites(struct drm_compositor *ec)
1438{
1439 struct drm_sprite *sprite;
1440 drmModePlaneRes *plane_res;
1441 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001442 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001443
1444 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1445 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001446 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001447 strerror(errno));
1448 return;
1449 }
1450
1451 for (i = 0; i < plane_res->count_planes; i++) {
1452 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1453 if (!plane)
1454 continue;
1455
1456 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1457 plane->count_formats));
1458 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001459 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001460 __func__);
1461 free(plane);
1462 continue;
1463 }
1464
1465 memset(sprite, 0, sizeof *sprite);
1466
1467 sprite->possible_crtcs = plane->possible_crtcs;
1468 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001469 sprite->current = NULL;
1470 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001471 sprite->compositor = ec;
1472 sprite->count_formats = plane->count_formats;
1473 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001474 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001475 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001476 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001477
1478 wl_list_insert(&ec->sprite_list, &sprite->link);
1479 }
1480
1481 free(plane_res->planes);
1482 free(plane_res);
1483}
1484
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001485static void
1486destroy_sprites(struct drm_compositor *compositor)
1487{
1488 struct drm_sprite *sprite, *next;
1489 struct drm_output *output;
1490
1491 output = container_of(compositor->base.output_list.next,
1492 struct drm_output, base.link);
1493
1494 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1495 drmModeSetPlane(compositor->drm.fd,
1496 sprite->plane_id,
1497 output->crtc_id, 0, 0,
1498 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001499 if (sprite->current)
1500 gbm_bo_destroy(sprite->current->bo);
1501 if (sprite->next)
1502 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001503 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001504 free(sprite);
1505 }
1506}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001507
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001508static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001509create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001510 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001511{
1512 drmModeConnector *connector;
1513 drmModeRes *resources;
1514 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001515 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001516
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001517 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001518 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001519 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001520 return -1;
1521 }
1522
Jesse Barnes58ef3792012-02-23 09:45:49 -05001523 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001524 if (!ec->crtcs) {
1525 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001526 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001527 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001528
Rob Clark4339add2012-08-09 14:18:28 -05001529 ec->min_width = resources->min_width;
1530 ec->max_width = resources->max_width;
1531 ec->min_height = resources->min_height;
1532 ec->max_height = resources->max_height;
1533
Jesse Barnes58ef3792012-02-23 09:45:49 -05001534 ec->num_crtcs = resources->count_crtcs;
1535 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1536
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001537 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001538 connector = drmModeGetConnector(ec->drm.fd,
1539 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001540 if (connector == NULL)
1541 continue;
1542
1543 if (connector->connection == DRM_MODE_CONNECTED &&
1544 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001545 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001546 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001547 connector, x, y,
1548 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001549 drmModeFreeConnector(connector);
1550 continue;
1551 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001552
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001553 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001554 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001555 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001556 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001557
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001558 drmModeFreeConnector(connector);
1559 }
1560
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001561 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001562 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001563 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001564 return -1;
1565 }
1566
1567 drmModeFreeResources(resources);
1568
1569 return 0;
1570}
1571
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001572static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001573update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001574{
1575 drmModeConnector *connector;
1576 drmModeRes *resources;
1577 struct drm_output *output, *next;
1578 int x = 0, y = 0;
1579 int x_offset = 0, y_offset = 0;
1580 uint32_t connected = 0, disconnects = 0;
1581 int i;
1582
1583 resources = drmModeGetResources(ec->drm.fd);
1584 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001585 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001586 return;
1587 }
1588
1589 /* collect new connects */
1590 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001591 int connector_id = resources->connectors[i];
1592
1593 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001594 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001595 continue;
1596
David Herrmann7551cff2011-12-08 17:05:43 +01001597 if (connector->connection != DRM_MODE_CONNECTED) {
1598 drmModeFreeConnector(connector);
1599 continue;
1600 }
1601
Benjamin Franzke117483d2011-08-30 11:38:26 +02001602 connected |= (1 << connector_id);
1603
1604 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001605 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001606 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001607 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001608
1609 /* XXX: not yet needed, we die with 0 outputs */
1610 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001611 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001612 else
1613 x = 0;
1614 y = 0;
1615 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001616 connector, x, y,
1617 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001618 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001619
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001620 }
1621 drmModeFreeConnector(connector);
1622 }
1623 drmModeFreeResources(resources);
1624
1625 disconnects = ec->connector_allocator & ~connected;
1626 if (disconnects) {
1627 wl_list_for_each_safe(output, next, &ec->base.output_list,
1628 base.link) {
1629 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001630 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001631 output->base.x - x_offset,
1632 output->base.y - y_offset);
1633 }
1634
1635 if (disconnects & (1 << output->connector_id)) {
1636 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001637 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001638 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001639 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001640 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001641 }
1642 }
1643 }
1644
1645 /* FIXME: handle zero outputs, without terminating */
1646 if (ec->connector_allocator == 0)
1647 wl_display_terminate(ec->base.wl_display);
1648}
1649
1650static int
David Herrmannd7488c22012-03-11 20:05:21 +01001651udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001652{
David Herrmannd7488c22012-03-11 20:05:21 +01001653 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001654 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001655
1656 sysnum = udev_device_get_sysnum(device);
1657 if (!sysnum || atoi(sysnum) != ec->drm.id)
1658 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001659
David Herrmann6ac52db2012-03-11 20:05:22 +01001660 val = udev_device_get_property_value(device, "HOTPLUG");
1661 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001662 return 0;
1663
David Herrmann6ac52db2012-03-11 20:05:22 +01001664 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001665}
1666
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001667static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001668udev_drm_event(int fd, uint32_t mask, void *data)
1669{
1670 struct drm_compositor *ec = data;
1671 struct udev_device *event;
1672
1673 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001674
David Herrmannd7488c22012-03-11 20:05:21 +01001675 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001676 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001677
1678 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001679
1680 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001681}
1682
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001683static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001684drm_restore(struct weston_compositor *ec)
1685{
1686 struct drm_compositor *d = (struct drm_compositor *) ec;
1687
1688 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1689 weston_log("failed to drop master: %m\n");
1690 tty_reset(d->tty);
1691}
1692
Pekka Paalanen33156972012-08-03 13:30:30 -04001693static const char default_seat[] = "seat0";
1694
1695static void
1696device_added(struct udev_device *udev_device, struct drm_seat *master)
1697{
1698 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001699 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001700 const char *devnode;
1701 const char *device_seat;
1702 int fd;
1703
1704 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1705 if (!device_seat)
1706 device_seat = default_seat;
1707
1708 if (strcmp(device_seat, master->seat_id))
1709 return;
1710
1711 c = master->base.compositor;
1712 devnode = udev_device_get_devnode(udev_device);
1713
1714 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001715 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001716 * read. mtdev_get() also expects this. */
1717 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1718 if (fd < 0) {
1719 weston_log("opening input device '%s' failed.\n", devnode);
1720 return;
1721 }
1722
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001723 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001724 if (!device) {
1725 close(fd);
1726 weston_log("not using input device '%s'.\n", devnode);
1727 return;
1728 }
1729
1730 wl_list_insert(master->devices_list.prev, &device->link);
1731}
1732
1733static void
1734evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1735{
1736 struct drm_seat *seat = (struct drm_seat *) seat_base;
1737 struct udev_enumerate *e;
1738 struct udev_list_entry *entry;
1739 struct udev_device *device;
1740 const char *path, *sysname;
1741
1742 e = udev_enumerate_new(udev);
1743 udev_enumerate_add_match_subsystem(e, "input");
1744 udev_enumerate_scan_devices(e);
1745 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1746 path = udev_list_entry_get_name(entry);
1747 device = udev_device_new_from_syspath(udev, path);
1748
1749 sysname = udev_device_get_sysname(device);
1750 if (strncmp("event", sysname, 5) != 0) {
1751 udev_device_unref(device);
1752 continue;
1753 }
1754
1755 device_added(device, seat);
1756
1757 udev_device_unref(device);
1758 }
1759 udev_enumerate_unref(e);
1760
1761 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1762
1763 if (wl_list_empty(&seat->devices_list)) {
1764 weston_log(
1765 "warning: no input devices on entering Weston. "
1766 "Possible causes:\n"
1767 "\t- no permissions to read /dev/input/event*\n"
1768 "\t- seats misconfigured "
1769 "(Weston backend option 'seat', "
1770 "udev device property ID_SEAT)\n");
1771 }
1772}
1773
1774static int
1775evdev_udev_handler(int fd, uint32_t mask, void *data)
1776{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001777 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001778 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001779 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001780 const char *action;
1781 const char *devnode;
1782
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001783 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001784 if (!udev_device)
1785 return 1;
1786
1787 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001788 if (!action)
1789 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001790
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001791 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1792 goto out;
1793
1794 if (!strcmp(action, "add")) {
1795 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001796 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001797 else if (!strcmp(action, "remove")) {
1798 devnode = udev_device_get_devnode(udev_device);
1799 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1800 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001801 weston_log("input device %s, %s removed\n",
1802 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001803 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001804 break;
1805 }
1806 }
1807
1808out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001809 udev_device_unref(udev_device);
1810
1811 return 0;
1812}
1813
1814static int
1815evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1816{
1817 struct drm_seat *master = (struct drm_seat *) seat_base;
1818 struct wl_event_loop *loop;
1819 struct weston_compositor *c = master->base.compositor;
1820 int fd;
1821
1822 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1823 if (!master->udev_monitor) {
1824 weston_log("udev: failed to create the udev monitor\n");
1825 return 0;
1826 }
1827
1828 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1829 "input", NULL);
1830
1831 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1832 weston_log("udev: failed to bind the udev monitor\n");
1833 udev_monitor_unref(master->udev_monitor);
1834 return 0;
1835 }
1836
1837 loop = wl_display_get_event_loop(c->wl_display);
1838 fd = udev_monitor_get_fd(master->udev_monitor);
1839 master->udev_monitor_source =
1840 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1841 evdev_udev_handler, master);
1842 if (!master->udev_monitor_source) {
1843 udev_monitor_unref(master->udev_monitor);
1844 return 0;
1845 }
1846
1847 return 1;
1848}
1849
1850static void
1851evdev_disable_udev_monitor(struct weston_seat *seat_base)
1852{
1853 struct drm_seat *seat = (struct drm_seat *) seat_base;
1854
1855 if (!seat->udev_monitor)
1856 return;
1857
1858 udev_monitor_unref(seat->udev_monitor);
1859 seat->udev_monitor = NULL;
1860 wl_event_source_remove(seat->udev_monitor_source);
1861 seat->udev_monitor_source = NULL;
1862}
1863
1864static void
1865drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1866{
1867 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001868 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001869
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001870 wl_list_for_each(device, &seat->devices_list, link)
1871 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001872}
1873
1874static void
1875evdev_input_create(struct weston_compositor *c, struct udev *udev,
1876 const char *seat_id)
1877{
1878 struct drm_seat *seat;
1879
1880 seat = malloc(sizeof *seat);
1881 if (seat == NULL)
1882 return;
1883
1884 memset(seat, 0, sizeof *seat);
1885 weston_seat_init(&seat->base, c);
1886 seat->base.led_update = drm_led_update;
1887
1888 wl_list_init(&seat->devices_list);
1889 seat->seat_id = strdup(seat_id);
1890 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1891 free(seat->seat_id);
1892 free(seat);
1893 return;
1894 }
1895
1896 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001897}
1898
1899static void
1900evdev_remove_devices(struct weston_seat *seat_base)
1901{
1902 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001903 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001904
1905 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001906 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001907
Pekka Paalanend8583512012-08-03 14:39:11 +03001908 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001909 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001910}
1911
1912static void
1913evdev_input_destroy(struct weston_seat *seat_base)
1914{
1915 struct drm_seat *seat = (struct drm_seat *) seat_base;
1916
1917 evdev_remove_devices(seat_base);
1918 evdev_disable_udev_monitor(&seat->base);
1919
1920 weston_seat_release(seat_base);
1921 free(seat->seat_id);
1922 free(seat);
1923}
1924
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001925static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001926drm_free_configured_output(struct drm_configured_output *output)
1927{
1928 free(output->name);
1929 free(output->mode);
1930 free(output);
1931}
1932
1933static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001934drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001935{
1936 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001937 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001938 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001939
Daniel Stone37816df2012-05-16 18:45:18 +01001940 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1941 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001942 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001943 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001944
1945 wl_event_source_remove(d->udev_drm_source);
1946 wl_event_source_remove(d->drm_source);
1947
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001948 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001949
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001950 gles2_renderer_destroy(ec);
1951
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001952 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001953 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001954 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001955 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001956 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001957
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001958 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001959}
1960
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001961static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001962drm_compositor_set_modes(struct drm_compositor *compositor)
1963{
1964 struct drm_output *output;
1965 struct drm_mode *drm_mode;
1966 int ret;
1967
1968 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1969 drm_mode = (struct drm_mode *) output->base.current;
1970 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001971 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001972 &output->connector_id, 1,
1973 &drm_mode->mode_info);
1974 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001975 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001976 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001977 drm_mode->base.width, drm_mode->base.height,
1978 output->base.x, output->base.y);
1979 }
1980 }
1981}
1982
1983static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001984vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001985{
1986 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001987 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001988 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001989 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001990
1991 switch (event) {
1992 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03001993 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001994 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001995 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001996 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001997 wl_display_terminate(compositor->wl_display);
1998 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001999 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002000 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002001 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002002 wl_list_for_each(seat, &compositor->seat_list, link) {
2003 evdev_add_devices(ec->udev, seat);
2004 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002005 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002006 break;
2007 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002008 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002009 wl_list_for_each(seat, &compositor->seat_list, link) {
2010 evdev_disable_udev_monitor(seat);
2011 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002012 }
2013
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002014 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002015 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002016 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002017
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002018 /* If we have a repaint scheduled (either from a
2019 * pending pageflip or the idle handler), make sure we
2020 * cancel that so we don't try to pageflip when we're
2021 * vt switched away. The SLEEPING state will prevent
2022 * further attemps at repainting. When we switch
2023 * back, we schedule a repaint, which will process
2024 * pending frame callbacks. */
2025
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002026 wl_list_for_each(output, &ec->base.output_list, base.link) {
2027 output->base.repaint_needed = 0;
2028 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002029 }
2030
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002031 output = container_of(ec->base.output_list.next,
2032 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002033
2034 wl_list_for_each(sprite, &ec->sprite_list, link)
2035 drmModeSetPlane(ec->drm.fd,
2036 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002037 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002038 0, 0, 0, 0, 0, 0, 0, 0);
2039
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002040 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002041 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002042
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002043 break;
2044 };
2045}
2046
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002047static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002048switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002049{
2050 struct drm_compositor *ec = data;
2051
Daniel Stone325fc2d2012-05-30 16:31:58 +01002052 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002053}
2054
David Herrmann0af066f2012-10-29 19:21:16 +01002055/*
2056 * Find primary GPU
2057 * Some systems may have multiple DRM devices attached to a single seat. This
2058 * function loops over all devices and tries to find a PCI device with the
2059 * boot_vga sysfs attribute set to 1.
2060 * If no such device is found, the first DRM device reported by udev is used.
2061 */
2062static struct udev_device*
2063find_primary_gpu(struct drm_compositor *ec, const char *seat)
2064{
2065 struct udev_enumerate *e;
2066 struct udev_list_entry *entry;
2067 const char *path, *device_seat, *id;
2068 struct udev_device *device, *drm_device, *pci;
2069
2070 e = udev_enumerate_new(ec->udev);
2071 udev_enumerate_add_match_subsystem(e, "drm");
2072 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2073
2074 udev_enumerate_scan_devices(e);
2075 drm_device = NULL;
2076 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2077 path = udev_list_entry_get_name(entry);
2078 device = udev_device_new_from_syspath(ec->udev, path);
2079 if (!device)
2080 continue;
2081 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2082 if (!device_seat)
2083 device_seat = default_seat;
2084 if (strcmp(device_seat, seat)) {
2085 udev_device_unref(device);
2086 continue;
2087 }
2088
2089 pci = udev_device_get_parent_with_subsystem_devtype(device,
2090 "pci", NULL);
2091 if (pci) {
2092 id = udev_device_get_sysattr_value(pci, "boot_vga");
2093 if (id && !strcmp(id, "1")) {
2094 if (drm_device)
2095 udev_device_unref(drm_device);
2096 drm_device = device;
2097 break;
2098 }
2099 }
2100
2101 if (!drm_device)
2102 drm_device = device;
2103 else
2104 udev_device_unref(device);
2105 }
2106
2107 udev_enumerate_unref(e);
2108 return drm_device;
2109}
2110
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002111static void
2112hide_sprites_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2113 void *data)
2114{
2115 struct drm_compositor *c = data;
2116
2117 c->sprites_hidden ^= 1;
2118}
2119
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002120static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002121drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002122 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002123 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002124{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002125 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002126 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002127 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002128 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002129 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002130 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002131
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002132 weston_log("initializing drm backend\n");
2133
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002134 ec = malloc(sizeof *ec);
2135 if (ec == NULL)
2136 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002137 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002138
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002139 /* KMS support for sprites is not complete yet, so disable the
2140 * functionality for now. */
2141 ec->sprites_are_broken = 1;
2142
Daniel Stone725c2c32012-06-22 14:04:36 +01002143 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002144 config_file) < 0) {
2145 weston_log("weston_compositor_init failed\n");
2146 goto err_base;
2147 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002148
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002149 ec->udev = udev_new();
2150 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002151 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002152 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002153 }
2154
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002155 ec->base.wl_display = display;
2156 ec->tty = tty_create(&ec->base, vt_func, tty);
2157 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002158 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002159 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002160 }
2161
David Herrmann0af066f2012-10-29 19:21:16 +01002162 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002163 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002164 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002165 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002166 }
David Herrmann0af066f2012-10-29 19:21:16 +01002167 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002168
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002169 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002170 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002171 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002172 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002173
2174 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002175 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002176
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002177 ec->base.focus = 1;
2178
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002179 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002180
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002181 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002182 weston_compositor_add_key_binding(&ec->base, key,
2183 MODIFIER_CTRL | MODIFIER_ALT,
2184 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002185
Jesse Barnes58ef3792012-02-23 09:45:49 -05002186 wl_list_init(&ec->sprite_list);
2187 create_sprites(ec);
2188
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002189 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002190 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002191 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002192 }
2193
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002194 path = NULL;
2195
Tiago Vignattice03ec32011-12-19 01:14:03 +02002196 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002197
2198 loop = wl_display_get_event_loop(ec->base.wl_display);
2199 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002200 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002201 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002202
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002203 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2204 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002205 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002206 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002207 }
2208 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2209 "drm", NULL);
2210 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002211 wl_event_loop_add_fd(loop,
2212 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002213 WL_EVENT_READABLE, udev_drm_event, ec);
2214
2215 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002216 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002217 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002218 }
2219
Daniel Stonea96b93c2012-06-22 14:04:37 +01002220 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002221
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002222 weston_compositor_add_debug_binding(&ec->base, KEY_O,
2223 hide_sprites_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002224
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002225 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002226
2227err_udev_monitor:
2228 wl_event_source_remove(ec->udev_drm_source);
2229 udev_monitor_unref(ec->udev_monitor);
2230err_drm_source:
2231 wl_event_source_remove(ec->drm_source);
2232 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2233 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002234err_sprite:
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002235 gles2_renderer_destroy(&ec->base);
2236 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002237 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002238err_udev_dev:
2239 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002240err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002241 tty_destroy(ec->tty);
2242err_udev:
2243 udev_unref(ec->udev);
2244err_compositor:
2245 weston_compositor_shutdown(&ec->base);
2246err_base:
2247 free(ec);
2248 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002249}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002250
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002251static int
2252set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2253{
2254 mode->flags = 0;
2255
2256 if (strcmp(hsync, "+hsync") == 0)
2257 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2258 else if (strcmp(hsync, "-hsync") == 0)
2259 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2260 else
2261 return -1;
2262
2263 if (strcmp(vsync, "+vsync") == 0)
2264 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2265 else if (strcmp(vsync, "-vsync") == 0)
2266 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2267 else
2268 return -1;
2269
2270 return 0;
2271}
2272
2273static int
2274check_for_modeline(struct drm_configured_output *output)
2275{
2276 drmModeModeInfo mode;
2277 char hsync[16];
2278 char vsync[16];
2279 char mode_name[16];
2280 float fclock;
2281
2282 mode.type = DRM_MODE_TYPE_USERDEF;
2283 mode.hskew = 0;
2284 mode.vscan = 0;
2285 mode.vrefresh = 0;
2286
2287 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2288 &fclock, &mode.hdisplay,
2289 &mode.hsync_start,
2290 &mode.hsync_end, &mode.htotal,
2291 &mode.vdisplay,
2292 &mode.vsync_start,
2293 &mode.vsync_end, &mode.vtotal,
2294 hsync, vsync) == 11) {
2295 if (set_sync_flags(&mode, hsync, vsync))
2296 return -1;
2297
2298 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2299 strcpy(mode.name, mode_name);
2300
2301 mode.clock = fclock * 1000;
2302 } else
2303 return -1;
2304
2305 output->crtc_mode = mode;
2306
2307 return 0;
2308}
2309
Scott Moreau8ab5d452012-07-30 19:51:08 -06002310static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002311drm_output_set_transform(struct drm_configured_output *output)
2312{
2313 if (!output_transform) {
2314 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2315 return;
2316 }
2317
2318 if (!strcmp(output_transform, "normal"))
2319 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2320 else if (!strcmp(output_transform, "90"))
2321 output->transform = WL_OUTPUT_TRANSFORM_90;
2322 else if (!strcmp(output_transform, "180"))
2323 output->transform = WL_OUTPUT_TRANSFORM_180;
2324 else if (!strcmp(output_transform, "270"))
2325 output->transform = WL_OUTPUT_TRANSFORM_270;
2326 else if (!strcmp(output_transform, "flipped"))
2327 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2328 else if (!strcmp(output_transform, "flipped-90"))
2329 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2330 else if (!strcmp(output_transform, "flipped-180"))
2331 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2332 else if (!strcmp(output_transform, "flipped-270"))
2333 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2334 else {
2335 weston_log("Invalid transform \"%s\" for output %s\n",
2336 output_transform, output_name);
2337 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2338 }
2339
2340 free(output_transform);
2341 output_transform = NULL;
2342}
2343
2344static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002345output_section_done(void *data)
2346{
2347 struct drm_configured_output *output;
2348
2349 output = malloc(sizeof *output);
2350
Scott Moreau1bad5db2012-08-18 01:04:05 -06002351 if (!output || !output_name || (output_name[0] == 'X') ||
2352 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002353 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002354 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002355 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002356 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002357 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002358 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002359 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002360 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002361 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002362
2363 output->config = OUTPUT_CONFIG_INVALID;
2364 output->name = output_name;
2365 output->mode = output_mode;
2366
Scott Moreau1bad5db2012-08-18 01:04:05 -06002367 if (output_mode) {
2368 if (strcmp(output_mode, "off") == 0)
2369 output->config = OUTPUT_CONFIG_OFF;
2370 else if (strcmp(output_mode, "preferred") == 0)
2371 output->config = OUTPUT_CONFIG_PREFERRED;
2372 else if (strcmp(output_mode, "current") == 0)
2373 output->config = OUTPUT_CONFIG_CURRENT;
2374 else if (sscanf(output_mode, "%dx%d",
2375 &output->width, &output->height) == 2)
2376 output->config = OUTPUT_CONFIG_MODE;
2377 else if (check_for_modeline(output) == 0)
2378 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002379
Scott Moreau1bad5db2012-08-18 01:04:05 -06002380 if (output->config == OUTPUT_CONFIG_INVALID)
2381 weston_log("Invalid mode \"%s\" for output %s\n",
2382 output_mode, output_name);
2383 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002384 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002385
2386 drm_output_set_transform(output);
2387
2388 wl_list_insert(&configured_output_list, &output->link);
2389
2390 if (output_transform)
2391 free(output_transform);
2392 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002393}
2394
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002395WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002396backend_init(struct wl_display *display, int argc, char *argv[],
2397 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002398{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002399 int connector = 0, tty = 0;
2400 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002401
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002402 const struct weston_option drm_options[] = {
2403 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2404 { WESTON_OPTION_STRING, "seat", 0, &seat },
2405 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002406 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002407 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002408
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002409 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002410
Scott Moreau8ab5d452012-07-30 19:51:08 -06002411 wl_list_init(&configured_output_list);
2412
2413 const struct config_key drm_config_keys[] = {
2414 { "name", CONFIG_KEY_STRING, &output_name },
2415 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002416 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002417 };
2418
2419 const struct config_section config_section[] = {
2420 { "output", drm_config_keys,
2421 ARRAY_LENGTH(drm_config_keys), output_section_done },
2422 };
2423
2424 parse_config_file(config_file, config_section,
2425 ARRAY_LENGTH(config_section), NULL);
2426
Daniel Stonec1be8e52012-06-01 11:14:02 -04002427 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2428 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002429}