blob: 2066dd482f2ccf9f317692ba2300cc168eae40ad [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010043#include "gl-renderer.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020044#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010045#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046
Kristian Høgsberg061c4252012-06-28 11:28:15 -040047static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060048static char *output_name;
49static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060050static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060051static struct wl_list configured_output_list;
52
53enum output_config {
54 OUTPUT_CONFIG_INVALID = 0,
55 OUTPUT_CONFIG_OFF,
56 OUTPUT_CONFIG_PREFERRED,
57 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060058 OUTPUT_CONFIG_MODE,
59 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060060};
61
62struct drm_configured_output {
63 char *name;
64 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060065 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060066 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060067 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060068 enum output_config config;
69 struct wl_list link;
70};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040071
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040072struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050073 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
75 struct udev *udev;
76 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040077
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010078 struct udev_monitor *udev_monitor;
79 struct wl_event_source *udev_drm_source;
80
Benjamin Franzke2af7f102011-03-02 11:14:59 +010081 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010082 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 int fd;
84 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020085 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050086 uint32_t *crtcs;
87 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050088 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010089 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050090 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020091
Rob Clark4339add2012-08-09 14:18:28 -050092 /* we need these parameters in order to not fail drmModeAddFB2()
93 * due to out of bounds dimensions, and then mistakenly set
94 * sprites_are_broken:
95 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020096 uint32_t min_width, max_width;
97 uint32_t min_height, max_height;
98 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050099
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500101 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200102 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103
Rob Clarkab5b1e32012-08-09 13:24:45 -0500104 int cursors_are_broken;
105
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400107};
108
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500110 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400111 drmModeModeInfo mode_info;
112};
113
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114struct drm_output;
115
116struct drm_fb {
117 struct gbm_bo *bo;
118 struct drm_output *output;
119 uint32_t fb_id;
120 int is_client_buffer;
121 struct wl_buffer *buffer;
122 struct wl_listener buffer_destroy_listener;
123};
124
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500126 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400127
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400128 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400129 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500130 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400131 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700132 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200133
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300134 int vblank_pending;
135 int page_flip_pending;
136
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400137 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400138 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400139 struct weston_plane cursor_plane;
140 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400141 struct weston_surface *cursor_surface;
142 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300143 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200144 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400145};
146
Jesse Barnes58ef3792012-02-23 09:45:49 -0500147/*
148 * An output has a primary display plane plus zero or more sprites for
149 * blending display contents.
150 */
151struct drm_sprite {
152 struct wl_list link;
153
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400154 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500155
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200156 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300157 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500158 struct drm_compositor *compositor;
159
Jesse Barnes58ef3792012-02-23 09:45:49 -0500160 uint32_t possible_crtcs;
161 uint32_t plane_id;
162 uint32_t count_formats;
163
164 int32_t src_x, src_y;
165 uint32_t src_w, src_h;
166 uint32_t dest_x, dest_y;
167 uint32_t dest_w, dest_h;
168
169 uint32_t formats[];
170};
171
Pekka Paalanen33156972012-08-03 13:30:30 -0400172struct drm_seat {
173 struct weston_seat base;
174 struct wl_list devices_list;
175 struct udev_monitor *udev_monitor;
176 struct wl_event_source *udev_monitor_source;
177 char *seat_id;
178};
179
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400180static void
181drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400182
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
185{
186 struct weston_compositor *ec = output_base->compositor;
187 struct drm_compositor *c =(struct drm_compositor *) ec;
188 struct drm_output *output = (struct drm_output *) output_base;
189 int crtc;
190
191 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
192 if (c->crtcs[crtc] != output->crtc_id)
193 continue;
194
195 if (supported & (1 << crtc))
196 return -1;
197 }
198
199 return 0;
200}
201
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300202static void
203drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
204{
205 struct drm_fb *fb = data;
206 struct gbm_device *gbm = gbm_bo_get_device(bo);
207
208 if (fb->fb_id)
209 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
210
211 if (fb->buffer) {
212 weston_buffer_post_release(fb->buffer);
213 wl_list_remove(&fb->buffer_destroy_listener.link);
214 }
215
216 free(data);
217}
218
219static struct drm_fb *
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200220drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_compositor *compositor)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300221{
222 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200223 uint32_t width, height, stride, handle, format;
224 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300225 int ret;
226
227 if (fb)
228 return fb;
229
230 fb = malloc(sizeof *fb);
231
232 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300233 fb->is_client_buffer = 0;
234 fb->buffer = NULL;
235
236 width = gbm_bo_get_width(bo);
237 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400238 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300239 handle = gbm_bo_get_handle(bo).u32;
240
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200241 if (compositor->min_width > width || width > compositor->max_width ||
242 compositor->min_height > height ||
243 height > compositor->max_height) {
244 weston_log("bo geometry out of bounds\n");
245 goto err_free;
246 }
247
248 ret = -1;
249
250 format = gbm_bo_get_format(bo);
251
252 if (format && !compositor->no_addfb2) {
253 handles[0] = handle;
254 pitches[0] = stride;
255 offsets[0] = 0;
256
257 ret = drmModeAddFB2(compositor->drm.fd, width, height,
258 format, handles, pitches, offsets,
259 &fb->fb_id, 0);
260 if (ret) {
261 weston_log("addfb2 failed: %m\n");
262 compositor->no_addfb2 = 1;
263 compositor->sprites_are_broken = 1;
264 }
265 }
266
267 if (ret)
268 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
269 stride, handle, &fb->fb_id);
270
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300271 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200272 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200273 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300274 }
275
276 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
277
278 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200279
280err_free:
281 free(fb);
282 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300283}
284
285static void
286fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
287{
288 struct drm_fb *fb = container_of(listener, struct drm_fb,
289 buffer_destroy_listener);
290
291 fb->buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300292}
293
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200294static void
295drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
296{
297 assert(fb->buffer == NULL);
298
299 fb->is_client_buffer = 1;
300 fb->buffer = buffer;
301 fb->buffer->busy_count++;
302 fb->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
303
304 wl_signal_add(&fb->buffer->resource.destroy_signal,
305 &fb->buffer_destroy_listener);
306}
307
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400308static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400309drm_output_prepare_scanout_surface(struct weston_output *_output,
310 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500311{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400312 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500313 struct drm_compositor *c =
314 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300315 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500316
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500317 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200318 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200319 es->buffer == NULL ||
320 es->buffer->width != output->base.current->width ||
321 es->buffer->height != output->base.current->height ||
322 output->base.transform != es->buffer_transform ||
323 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400324 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500325
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400326 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
327 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500328
Rob Bradford9b101872012-09-14 23:25:41 +0100329 /* Unable to use the buffer for scanout */
330 if (!bo)
331 return NULL;
332
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300333 /* Need to verify output->region contained in surface opaque
334 * region. Or maybe just that format doesn't have alpha.
335 * For now, scanout only if format is XRGB8888. */
336 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
337 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400338 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300339 }
340
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200341 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300342 if (!output->next) {
343 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400344 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300345 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500346
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200347 drm_fb_set_buffer(output->next, es->buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500348
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400349 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500350}
351
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500352static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400353drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400354{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200355 struct drm_compositor *c =
356 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300357 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400358
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200359 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400360
Ander Conselvan de Oliveira0a887722012-11-22 15:57:00 +0200361 pixman_region32_subtract(&c->base.primary_plane.damage,
362 &c->base.primary_plane.damage, damage);
363
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300364 bo = gbm_surface_lock_front_buffer(output->surface);
365 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200366 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400367 return;
368 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300369
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200370 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300371 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200372 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300373 gbm_surface_release_buffer(output->surface, bo);
374 return;
375 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400376}
377
378static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500379drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400380 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100381{
382 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500383 struct drm_compositor *compositor =
384 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500385 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400386 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500387 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100388
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300389 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400390 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300391 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400392 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100393
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400394 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300395 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400396 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300397 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400398 &output->connector_id, 1,
399 &mode->mode_info);
400 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200401 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400402 return;
403 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200404 }
405
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500406 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300407 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500408 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200409 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500410 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500411 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100412
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300413 output->page_flip_pending = 1;
414
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400415 drm_output_set_cursor(output);
416
Jesse Barnes58ef3792012-02-23 09:45:49 -0500417 /*
418 * Now, update all the sprite surfaces
419 */
420 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200421 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500422 drmVBlank vbl = {
423 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
424 .request.sequence = 1,
425 };
426
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200427 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200428 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500429 continue;
430
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200431 if (s->next && !compositor->sprites_hidden)
432 fb_id = s->next->fb_id;
433
Jesse Barnes58ef3792012-02-23 09:45:49 -0500434 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200435 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500436 s->dest_x, s->dest_y,
437 s->dest_w, s->dest_h,
438 s->src_x, s->src_y,
439 s->src_w, s->src_h);
440 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200441 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500442 ret, strerror(errno));
443
Rob Clark5ca1a472012-08-08 20:27:37 -0500444 if (output->pipe > 0)
445 vbl.request.type |= DRM_VBLANK_SECONDARY;
446
Jesse Barnes58ef3792012-02-23 09:45:49 -0500447 /*
448 * Queue a vblank signal so we know when the surface
449 * becomes active on the display or has been replaced.
450 */
451 vbl.request.signal = (unsigned long)s;
452 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
453 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200454 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500455 ret, strerror(errno));
456 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300457
458 s->output = output;
459 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500460 }
461
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500462 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400463}
464
465static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500466vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
467 void *data)
468{
469 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300470 struct drm_output *output = s->output;
471 uint32_t msecs;
472
473 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500474
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200475 if (s->current)
476 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500477
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200478 s->current = s->next;
479 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300480
481 if (!output->page_flip_pending) {
482 msecs = sec * 1000 + usec / 1000;
483 weston_output_finish_frame(&output->base, msecs);
484 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500485}
486
487static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400488page_flip_handler(int fd, unsigned int frame,
489 unsigned int sec, unsigned int usec, void *data)
490{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200491 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400492 uint32_t msecs;
493
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300494 output->page_flip_pending = 0;
495
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300496 if (output->current) {
497 if (output->current->is_client_buffer)
498 gbm_bo_destroy(output->current->bo);
499 else
500 gbm_surface_release_buffer(output->surface,
501 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200502 }
503
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300504 output->current = output->next;
505 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400506
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300507 if (!output->vblank_pending) {
508 msecs = sec * 1000 + usec / 1000;
509 weston_output_finish_frame(&output->base, msecs);
510 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200511}
512
513static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500514drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
515{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400516 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500517
518 for (i = 0; i < s->count_formats; i++)
519 if (s->formats[i] == format)
520 return 1;
521
522 return 0;
523}
524
525static int
526drm_surface_transform_supported(struct weston_surface *es)
527{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400528 struct weston_matrix *matrix = &es->transform.matrix;
529 int i;
530
531 if (!es->transform.enabled)
532 return 1;
533
534 for (i = 0; i < 16; i++) {
535 switch (i) {
536 case 10:
537 case 15:
538 if (matrix->d[i] != 1.0)
539 return 0;
540 break;
541 case 0:
542 case 5:
543 case 12:
544 case 13:
545 break;
546 default:
547 if (matrix->d[i] != 0.0)
548 return 0;
549 break;
550 }
551 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500552
553 return 1;
554}
555
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400556static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500557drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400558 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500559{
560 struct weston_compositor *ec = output_base->compositor;
561 struct drm_compositor *c =(struct drm_compositor *) ec;
562 struct drm_sprite *s;
563 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500564 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500565 pixman_region32_t dest_rect, src_rect;
566 pixman_box32_t *box;
567 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400568 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500569
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200570 if (output_base->transform != WL_OUTPUT_TRANSFORM_NORMAL)
571 return NULL;
572
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500573 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400574 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500575
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300576 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400577 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300578
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400579 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400580 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500581
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200582 if (es->alpha != 1.0f)
583 return NULL;
584
Rob Clark702ffae2012-08-09 14:18:27 -0500585 if (wl_buffer_is_shm(es->buffer))
586 return NULL;
587
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400589 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500590
Jesse Barnes58ef3792012-02-23 09:45:49 -0500591 wl_list_for_each(s, &c->sprite_list, link) {
592 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
593 continue;
594
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200595 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500596 found = 1;
597 break;
598 }
599 }
600
601 /* No sprites available */
602 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400603 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400605 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
606 es->buffer, GBM_BO_USE_SCANOUT);
607 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400608 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400609
Jesse Barnes58ef3792012-02-23 09:45:49 -0500610 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200612 if (!drm_surface_format_supported(s, format)) {
613 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400614 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615 }
616
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200617 s->next = drm_fb_get_from_bo(bo, c);
618 if (!s->next) {
619 gbm_bo_destroy(bo);
620 return NULL;
621 }
622
623 drm_fb_set_buffer(s->next, es->buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400625 box = pixman_region32_extents(&es->transform.boundingbox);
626 s->plane.x = box->x1;
627 s->plane.y = box->y1;
628
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629 /*
630 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200631 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 * for us already).
633 */
634 pixman_region32_init(&dest_rect);
635 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
636 &output_base->region);
637 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
638 box = pixman_region32_extents(&dest_rect);
639 s->dest_x = box->x1;
640 s->dest_y = box->y1;
641 s->dest_w = box->x2 - box->x1;
642 s->dest_h = box->y2 - box->y1;
643 pixman_region32_fini(&dest_rect);
644
645 pixman_region32_init(&src_rect);
646 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
647 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500648 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400649
650 weston_surface_from_global_fixed(es,
651 wl_fixed_from_int(box->x1),
652 wl_fixed_from_int(box->y1),
653 &sx1, &sy1);
654 weston_surface_from_global_fixed(es,
655 wl_fixed_from_int(box->x2),
656 wl_fixed_from_int(box->y2),
657 &sx2, &sy2);
658
659 if (sx1 < 0)
660 sx1 = 0;
661 if (sy1 < 0)
662 sy1 = 0;
663 if (sx2 > wl_fixed_from_int(es->geometry.width))
664 sx2 = wl_fixed_from_int(es->geometry.width);
665 if (sy2 > wl_fixed_from_int(es->geometry.height))
666 sy2 = wl_fixed_from_int(es->geometry.height);
667
668 s->src_x = sx1 << 8;
669 s->src_y = sy1 << 8;
670 s->src_w = (sx2 - sx1) << 8;
671 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500672 pixman_region32_fini(&src_rect);
673
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400674 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500675}
676
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400677static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400678drm_output_prepare_cursor_surface(struct weston_output *output_base,
679 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500680{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400681 struct drm_compositor *c =
682 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400683 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400684
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200685 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
686 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400687 if (output->cursor_surface)
688 return NULL;
689 if (es->output_mask != (1u << output_base->id))
690 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500691 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400692 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400693 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
694 es->geometry.width > 64 || es->geometry.height > 64)
695 return NULL;
696
697 output->cursor_surface = es;
698
699 return &output->cursor_plane;
700}
701
702static void
703drm_output_set_cursor(struct drm_output *output)
704{
705 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400706 struct drm_compositor *c =
707 (struct drm_compositor *) output->base.compositor;
708 EGLint handle, stride;
709 struct gbm_bo *bo;
710 uint32_t buf[64 * 64];
711 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400712 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500713
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400714 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400715 if (es == NULL) {
716 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
717 return;
718 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500719
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400720 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
721 pixman_region32_fini(&output->cursor_plane.damage);
722 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400723 output->current_cursor ^= 1;
724 bo = output->cursor_bo[output->current_cursor];
725 memset(buf, 0, sizeof buf);
726 stride = wl_shm_buffer_get_stride(es->buffer);
727 s = wl_shm_buffer_get_data(es->buffer);
728 for (i = 0; i < es->geometry.height; i++)
729 memcpy(buf + i * 64, s + i * stride,
730 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500731
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400732 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300733 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400734
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400735 handle = gbm_bo_get_handle(bo).s32;
736 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500737 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300738 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500739 c->cursors_are_broken = 1;
740 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400741 }
742
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400743 x = es->geometry.x - output->base.x;
744 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400745 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500746 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400747 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500748 c->cursors_are_broken = 1;
749 }
750
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400751 output->cursor_plane.x = x;
752 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400753 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500754}
755
Jesse Barnes58ef3792012-02-23 09:45:49 -0500756static void
757drm_assign_planes(struct weston_output *output)
758{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400759 struct drm_compositor *c =
760 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200761 struct drm_output *drm_output = (struct drm_output *) output;
762 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400763 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500764 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400765 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200767 /* Reset the opaque region of the planes */
768 pixman_region32_fini(&drm_output->cursor_plane.opaque);
769 pixman_region32_init(&drm_output->cursor_plane.opaque);
770 pixman_region32_fini(&drm_output->fb_plane.opaque);
771 pixman_region32_init(&drm_output->fb_plane.opaque);
772
773 wl_list_for_each (s, &c->sprite_list, link) {
774 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
775 continue;
776
777 pixman_region32_fini(&s->plane.opaque);
778 pixman_region32_init(&s->plane.opaque);
779 }
780
Jesse Barnes58ef3792012-02-23 09:45:49 -0500781 /*
782 * Find a surface for each sprite in the output using some heuristics:
783 * 1) size
784 * 2) frequency of update
785 * 3) opacity (though some hw might support alpha blending)
786 * 4) clipping (this can be fixed with color keys)
787 *
788 * The idea is to save on blitting since this should save power.
789 * If we can get a large video surface on the sprite for example,
790 * the main display surface may not need to update at all, and
791 * the client buffer can be used directly for the sprite surface
792 * as we do for flipping full screen surfaces.
793 */
794 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400795 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400796 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797 pixman_region32_init(&surface_overlap);
798 pixman_region32_intersect(&surface_overlap, &overlap,
799 &es->transform.boundingbox);
800
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400801 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400802 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400803 next_plane = primary;
804 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400805 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400806 if (next_plane == NULL)
807 next_plane = drm_output_prepare_scanout_surface(output, es);
808 if (next_plane == NULL)
809 next_plane = drm_output_prepare_overlay_surface(output, es);
810 if (next_plane == NULL)
811 next_plane = primary;
812 weston_surface_move_to_plane(es, next_plane);
813 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814 pixman_region32_union(&overlap, &overlap,
815 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400816
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817 pixman_region32_fini(&surface_overlap);
818 }
819 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500820}
821
Matt Roper361d2ad2011-08-29 13:52:23 -0700822static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500823drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700824{
825 struct drm_output *output = (struct drm_output *) output_base;
826 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200827 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700828 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700829
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200830 if (output->backlight)
831 backlight_destroy(output->backlight);
832
Matt Roper361d2ad2011-08-29 13:52:23 -0700833 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400834 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700835
836 /* Restore original CRTC state */
837 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200838 origcrtc->x, origcrtc->y,
839 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700840 drmModeFreeCrtc(origcrtc);
841
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200842 c->crtc_allocator &= ~(1 << output->crtc_id);
843 c->connector_allocator &= ~(1 << output->connector_id);
844
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100845 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100846
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400847 gbm_surface_destroy(output->surface);
848
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400849 weston_plane_release(&output->fb_plane);
850 weston_plane_release(&output->cursor_plane);
851
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500852 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200853 wl_list_remove(&output->base.link);
854
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400855 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700856 free(output);
857}
858
Alex Wub7b8bda2012-04-17 17:20:48 +0800859static struct drm_mode *
860choose_mode (struct drm_output *output, struct weston_mode *target_mode)
861{
862 struct drm_mode *tmp_mode = NULL, *mode;
863
864 if (output->base.current->width == target_mode->width &&
865 output->base.current->height == target_mode->height &&
866 (output->base.current->refresh == target_mode->refresh ||
867 target_mode->refresh == 0))
868 return (struct drm_mode *)output->base.current;
869
870 wl_list_for_each(mode, &output->base.mode_list, base.link) {
871 if (mode->mode_info.hdisplay == target_mode->width &&
872 mode->mode_info.vdisplay == target_mode->height) {
873 if (mode->mode_info.vrefresh == target_mode->refresh ||
874 target_mode->refresh == 0) {
875 return mode;
876 } else if (!tmp_mode)
877 tmp_mode = mode;
878 }
879 }
880
881 return tmp_mode;
882}
883
884static int
885drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
886{
887 struct drm_output *output;
888 struct drm_mode *drm_mode;
889 int ret;
890 struct drm_compositor *ec;
891 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800892
893 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200894 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800895 return -1;
896 }
897
898 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200899 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800900 return -1;
901 }
902
903 ec = (struct drm_compositor *)output_base->compositor;
904 output = (struct drm_output *)output_base;
905 drm_mode = choose_mode (output, mode);
906
907 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200908 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800909 return -1;
910 } else if (&drm_mode->base == output->base.current) {
911 return 0;
912 } else if (drm_mode->base.width == output->base.current->width &&
913 drm_mode->base.height == output->base.current->height) {
914 /* only change refresh value */
915 ret = drmModeSetCrtc(ec->drm.fd,
916 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300917 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800918 &output->connector_id, 1, &drm_mode->mode_info);
919
920 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200921 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800922 drm_mode->base.width,
923 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400924 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800925 ret = -1;
926 } else {
927 output->base.current->flags = 0;
928 output->base.current = &drm_mode->base;
929 drm_mode->base.flags =
930 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
931 ret = 0;
932 }
933
934 return ret;
935 }
936
937 drm_mode->base.flags =
938 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
939
940 surface = gbm_surface_create(ec->gbm,
941 drm_mode->base.width,
942 drm_mode->base.height,
943 GBM_FORMAT_XRGB8888,
944 GBM_BO_USE_SCANOUT |
945 GBM_BO_USE_RENDERING);
946 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200947 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800948 return -1;
949 }
950
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100951 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800952
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100953 if (!gl_renderer_output_create(&output->base, surface)) {
John Kåre Alsaker94659272012-11-13 19:10:18 +0100954 weston_log("failed to create renderer output\n");
955 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800956 }
957
958 ret = drmModeSetCrtc(ec->drm.fd,
959 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300960 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800961 &output->connector_id, 1, &drm_mode->mode_info);
962 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200963 weston_log("failed to set mode\n");
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100964 goto err_gl;
Alex Wub7b8bda2012-04-17 17:20:48 +0800965 }
966
967 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300968 if (output->current) {
969 if (output->current->is_client_buffer)
970 gbm_bo_destroy(output->current->bo);
971 else
972 gbm_surface_release_buffer(output->surface,
973 output->current->bo);
974 }
975 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800976
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300977 if (output->next) {
978 if (output->next->is_client_buffer)
979 gbm_bo_destroy(output->next->bo);
980 else
981 gbm_surface_release_buffer(output->surface,
982 output->next->bo);
983 }
984 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800985
Alex Wub7b8bda2012-04-17 17:20:48 +0800986 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800987 output->surface = surface;
988
989 /*update output*/
990 output->base.current = &drm_mode->base;
991 output->base.dirty = 1;
992 weston_output_move(&output->base, output->base.x, output->base.y);
993 return 0;
994
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100995err_gl:
996 gl_renderer_output_destroy(&output->base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100997err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +0800998 gbm_surface_destroy(surface);
999 return -1;
1000}
1001
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001002static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001003on_drm_input(int fd, uint32_t mask, void *data)
1004{
1005 drmEventContext evctx;
1006
1007 memset(&evctx, 0, sizeof evctx);
1008 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1009 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001010 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001011 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001012
1013 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001014}
1015
1016static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001017init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001018{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001019 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001020 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001021
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001022 sysnum = udev_device_get_sysnum(device);
1023 if (sysnum)
1024 ec->drm.id = atoi(sysnum);
1025 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001026 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001027 return -1;
1028 }
1029
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001030 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001031 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001032 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001033 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001034 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001035 udev_device_get_devnode(device));
1036 return -1;
1037 }
1038
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001039 weston_log("using %s\n", filename);
1040
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001041 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001042 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001043
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001044 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001045 NULL) < 0) {
1046 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001047 return -1;
1048 }
1049
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001050 return 0;
1051}
1052
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001053static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001054drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1055{
1056 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001057 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001058
1059 mode = malloc(sizeof *mode);
1060 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001061 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001062
1063 mode->base.flags = 0;
1064 mode->base.width = info->hdisplay;
1065 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001066
1067 /* Calculate higher precision (mHz) refresh rate */
1068 refresh = (info->clock * 1000000LL / info->htotal +
1069 info->vtotal / 2) / info->vtotal;
1070
1071 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1072 refresh *= 2;
1073 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1074 refresh /= 2;
1075 if (info->vscan > 1)
1076 refresh /= info->vscan;
1077
1078 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001079 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001080
1081 if (info->type & DRM_MODE_TYPE_PREFERRED)
1082 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1083
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001084 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1085
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001086 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001087}
1088
1089static int
1090drm_subpixel_to_wayland(int drm_value)
1091{
1092 switch (drm_value) {
1093 default:
1094 case DRM_MODE_SUBPIXEL_UNKNOWN:
1095 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1096 case DRM_MODE_SUBPIXEL_NONE:
1097 return WL_OUTPUT_SUBPIXEL_NONE;
1098 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1099 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1100 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1101 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1102 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1103 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1104 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1105 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1106 }
1107}
1108
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001109/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001110static uint32_t
1111drm_get_backlight(struct drm_output *output)
1112{
1113 long brightness, max_brightness, norm;
1114
1115 brightness = backlight_get_brightness(output->backlight);
1116 max_brightness = backlight_get_max_brightness(output->backlight);
1117
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001118 /* convert it on a scale of 0 to 255 */
1119 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001120
1121 return (uint32_t) norm;
1122}
1123
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001124/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001125static void
1126drm_set_backlight(struct weston_output *output_base, uint32_t value)
1127{
1128 struct drm_output *output = (struct drm_output *) output_base;
1129 long max_brightness, new_brightness;
1130
1131 if (!output->backlight)
1132 return;
1133
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001134 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001135 return;
1136
1137 max_brightness = backlight_get_max_brightness(output->backlight);
1138
1139 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001140 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001141
1142 backlight_set_brightness(output->backlight, new_brightness);
1143}
1144
1145static drmModePropertyPtr
1146drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1147{
1148 drmModePropertyPtr props;
1149 int i;
1150
1151 for (i = 0; i < connector->count_props; i++) {
1152 props = drmModeGetProperty(fd, connector->props[i]);
1153 if (!props)
1154 continue;
1155
1156 if (!strcmp(props->name, name))
1157 return props;
1158
1159 drmModeFreeProperty(props);
1160 }
1161
1162 return NULL;
1163}
1164
1165static void
1166drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1167{
1168 struct drm_output *output = (struct drm_output *) output_base;
1169 struct weston_compositor *ec = output_base->compositor;
1170 struct drm_compositor *c = (struct drm_compositor *) ec;
1171 drmModeConnectorPtr connector;
1172 drmModePropertyPtr prop;
1173
1174 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1175 if (!connector)
1176 return;
1177
1178 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1179 if (!prop) {
1180 drmModeFreeConnector(connector);
1181 return;
1182 }
1183
1184 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1185 prop->prop_id, level);
1186 drmModeFreeProperty(prop);
1187 drmModeFreeConnector(connector);
1188}
1189
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001190static const char *connector_type_names[] = {
1191 "None",
1192 "VGA",
1193 "DVI",
1194 "DVI",
1195 "DVI",
1196 "Composite",
1197 "TV",
1198 "LVDS",
1199 "CTV",
1200 "DIN",
1201 "DP",
1202 "HDMI",
1203 "HDMI",
1204 "TV",
1205 "eDP",
1206};
1207
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001208static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001209find_crtc_for_connector(struct drm_compositor *ec,
1210 drmModeRes *resources, drmModeConnector *connector)
1211{
1212 drmModeEncoder *encoder;
1213 uint32_t possible_crtcs;
1214 int i, j;
1215
1216 for (j = 0; j < connector->count_encoders; j++) {
1217 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1218 if (encoder == NULL) {
1219 weston_log("Failed to get encoder.\n");
1220 return -1;
1221 }
1222 possible_crtcs = encoder->possible_crtcs;
1223 drmModeFreeEncoder(encoder);
1224
1225 for (i = 0; i < resources->count_crtcs; i++) {
1226 if (possible_crtcs & (1 << i) &&
1227 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1228 return i;
1229 }
1230 }
1231
1232 return -1;
1233}
1234
1235static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001236create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001237 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001238 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001239 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001240{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001241 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001242 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1243 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001244 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001245 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001246 drmModeModeInfo crtc_mode;
1247 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001248 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001249 char name[32];
1250 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001251
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001252 i = find_crtc_for_connector(ec, resources, connector);
1253 if (i < 0) {
1254 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001255 return -1;
1256 }
1257
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001258 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001259 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001260 return -1;
1261
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001262 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001263 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1264 output->base.make = "unknown";
1265 output->base.model = "unknown";
1266 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001267
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001268 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1269 type_name = connector_type_names[connector->connector_type];
1270 else
1271 type_name = "UNKNOWN";
1272 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1273 output->name = strdup(name);
1274
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001275 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001276 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001277 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001278 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001279 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001280
Matt Roper361d2ad2011-08-29 13:52:23 -07001281 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1282
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001283 /* Get the current mode on the crtc that's currently driving
1284 * this connector. */
1285 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001286 memset(&crtc_mode, 0, sizeof crtc_mode);
1287 if (encoder != NULL) {
1288 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1289 drmModeFreeEncoder(encoder);
1290 if (crtc == NULL)
1291 goto err_free;
1292 if (crtc->mode_valid)
1293 crtc_mode = crtc->mode;
1294 drmModeFreeCrtc(crtc);
1295 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001296
David Herrmann0f0d54e2011-12-08 17:05:45 +01001297 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001298 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1299 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001300 goto err_free;
1301 }
1302
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001303 preferred = NULL;
1304 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001305 configured = NULL;
1306
1307 wl_list_for_each(temp, &configured_output_list, link) {
1308 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001309 if (temp->mode)
1310 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001311 temp->name, temp->mode);
1312 o = temp;
1313 break;
1314 }
1315 }
1316
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001317 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001318 weston_log("Disabling output %s\n", o->name);
1319
1320 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1321 0, 0, 0, 0, 0, NULL);
1322 goto err_free;
1323 }
1324
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001325 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001326 if (o && o->config == OUTPUT_CONFIG_MODE &&
1327 o->width == drm_mode->base.width &&
1328 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001329 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001330 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001331 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001332 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001333 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001334 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001335
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001336 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001337 configured = drm_output_add_mode(output, &o->crtc_mode);
1338 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001339 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001340 current = configured;
1341 }
1342
Wang Quanxianacb805a2012-07-30 18:09:46 -04001343 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001344 current = drm_output_add_mode(output, &crtc_mode);
1345 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001346 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001347 }
1348
Scott Moreau8ab5d452012-07-30 19:51:08 -06001349 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1350 configured = current;
1351
Wang Quanxianacb805a2012-07-30 18:09:46 -04001352 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001353 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001354 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001355 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001356 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001357 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001358 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001359 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001360
1361 if (output->base.current == NULL) {
1362 weston_log("no available modes for %s\n", output->name);
1363 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001364 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001365
Wang Quanxianacb805a2012-07-30 18:09:46 -04001366 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1367
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001368 output->surface = gbm_surface_create(ec->gbm,
1369 output->base.current->width,
1370 output->base.current->height,
1371 GBM_FORMAT_XRGB8888,
1372 GBM_BO_USE_SCANOUT |
1373 GBM_BO_USE_RENDERING);
1374 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001375 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001376 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001377 }
1378
John Kåre Alsaker94659272012-11-13 19:10:18 +01001379 weston_output_init(&output->base, &ec->base, x, y,
1380 connector->mmWidth, connector->mmHeight,
1381 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1382
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001383 if (gl_renderer_output_create(&output->base, output->surface) < 0)
John Kåre Alsaker94659272012-11-13 19:10:18 +01001384 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001385
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001386 output->cursor_bo[0] =
1387 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1388 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1389 output->cursor_bo[1] =
1390 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1391 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001392 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1393 weston_log("cursor buffers unavailable, using gl cursors\n");
1394 ec->cursors_are_broken = 1;
1395 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001396
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001397 output->backlight = backlight_init(drm_device,
1398 connector->connector_type);
1399 if (output->backlight) {
1400 output->base.set_backlight = drm_set_backlight;
1401 output->base.backlight_current = drm_get_backlight(output);
1402 }
1403
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001404 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1405
Alex Wubd3354b2012-04-17 17:20:49 +08001406 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001407 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001408 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001409 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001410 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001411 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001412
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001413 weston_plane_init(&output->cursor_plane, 0, 0);
1414 weston_plane_init(&output->fb_plane, 0, 0);
1415
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001416 weston_log("Output %s, (connector %d, crtc %d)\n",
1417 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001418 wl_list_for_each(m, &output->base.mode_list, link)
1419 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1420 m->width, m->height, m->refresh / 1000.0,
1421 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1422 ", preferred" : "",
1423 m->flags & WL_OUTPUT_MODE_CURRENT ?
1424 ", current" : "",
1425 connector->count_modes == 0 ?
1426 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001427
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001428 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001429
John Kåre Alsaker94659272012-11-13 19:10:18 +01001430err_output:
1431 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001432 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001433err_free:
1434 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1435 base.link) {
1436 wl_list_remove(&drm_mode->base.link);
1437 free(drm_mode);
1438 }
1439
1440 drmModeFreeCrtc(output->original_crtc);
1441 ec->crtc_allocator &= ~(1 << output->crtc_id);
1442 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001443 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001444 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001445
David Herrmann0f0d54e2011-12-08 17:05:45 +01001446 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001447}
1448
Jesse Barnes58ef3792012-02-23 09:45:49 -05001449static void
1450create_sprites(struct drm_compositor *ec)
1451{
1452 struct drm_sprite *sprite;
1453 drmModePlaneRes *plane_res;
1454 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001455 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001456
1457 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1458 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001459 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001460 strerror(errno));
1461 return;
1462 }
1463
1464 for (i = 0; i < plane_res->count_planes; i++) {
1465 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1466 if (!plane)
1467 continue;
1468
1469 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1470 plane->count_formats));
1471 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001472 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001473 __func__);
1474 free(plane);
1475 continue;
1476 }
1477
1478 memset(sprite, 0, sizeof *sprite);
1479
1480 sprite->possible_crtcs = plane->possible_crtcs;
1481 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001482 sprite->current = NULL;
1483 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001484 sprite->compositor = ec;
1485 sprite->count_formats = plane->count_formats;
1486 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001487 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001488 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001489 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001490
1491 wl_list_insert(&ec->sprite_list, &sprite->link);
1492 }
1493
1494 free(plane_res->planes);
1495 free(plane_res);
1496}
1497
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001498static void
1499destroy_sprites(struct drm_compositor *compositor)
1500{
1501 struct drm_sprite *sprite, *next;
1502 struct drm_output *output;
1503
1504 output = container_of(compositor->base.output_list.next,
1505 struct drm_output, base.link);
1506
1507 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1508 drmModeSetPlane(compositor->drm.fd,
1509 sprite->plane_id,
1510 output->crtc_id, 0, 0,
1511 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001512 if (sprite->current)
1513 gbm_bo_destroy(sprite->current->bo);
1514 if (sprite->next)
1515 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001516 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001517 free(sprite);
1518 }
1519}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001520
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001521static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001522create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001523 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001524{
1525 drmModeConnector *connector;
1526 drmModeRes *resources;
1527 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001528 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001529
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001530 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001531 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001532 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001533 return -1;
1534 }
1535
Jesse Barnes58ef3792012-02-23 09:45:49 -05001536 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001537 if (!ec->crtcs) {
1538 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001539 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001540 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001541
Rob Clark4339add2012-08-09 14:18:28 -05001542 ec->min_width = resources->min_width;
1543 ec->max_width = resources->max_width;
1544 ec->min_height = resources->min_height;
1545 ec->max_height = resources->max_height;
1546
Jesse Barnes58ef3792012-02-23 09:45:49 -05001547 ec->num_crtcs = resources->count_crtcs;
1548 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1549
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001550 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001551 connector = drmModeGetConnector(ec->drm.fd,
1552 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001553 if (connector == NULL)
1554 continue;
1555
1556 if (connector->connection == DRM_MODE_CONNECTED &&
1557 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001558 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001559 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001560 connector, x, y,
1561 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001562 drmModeFreeConnector(connector);
1563 continue;
1564 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001565
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001566 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001567 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001568 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001569 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001570
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001571 drmModeFreeConnector(connector);
1572 }
1573
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001574 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001575 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001576 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001577 return -1;
1578 }
1579
1580 drmModeFreeResources(resources);
1581
1582 return 0;
1583}
1584
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001585static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001586update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001587{
1588 drmModeConnector *connector;
1589 drmModeRes *resources;
1590 struct drm_output *output, *next;
1591 int x = 0, y = 0;
1592 int x_offset = 0, y_offset = 0;
1593 uint32_t connected = 0, disconnects = 0;
1594 int i;
1595
1596 resources = drmModeGetResources(ec->drm.fd);
1597 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001598 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001599 return;
1600 }
1601
1602 /* collect new connects */
1603 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001604 int connector_id = resources->connectors[i];
1605
1606 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001607 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001608 continue;
1609
David Herrmann7551cff2011-12-08 17:05:43 +01001610 if (connector->connection != DRM_MODE_CONNECTED) {
1611 drmModeFreeConnector(connector);
1612 continue;
1613 }
1614
Benjamin Franzke117483d2011-08-30 11:38:26 +02001615 connected |= (1 << connector_id);
1616
1617 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001618 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001619 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001620 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001621
1622 /* XXX: not yet needed, we die with 0 outputs */
1623 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001624 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001625 else
1626 x = 0;
1627 y = 0;
1628 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001629 connector, x, y,
1630 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001631 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001632
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001633 }
1634 drmModeFreeConnector(connector);
1635 }
1636 drmModeFreeResources(resources);
1637
1638 disconnects = ec->connector_allocator & ~connected;
1639 if (disconnects) {
1640 wl_list_for_each_safe(output, next, &ec->base.output_list,
1641 base.link) {
1642 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001643 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001644 output->base.x - x_offset,
1645 output->base.y - y_offset);
1646 }
1647
1648 if (disconnects & (1 << output->connector_id)) {
1649 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001650 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001651 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001652 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001653 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001654 }
1655 }
1656 }
1657
1658 /* FIXME: handle zero outputs, without terminating */
1659 if (ec->connector_allocator == 0)
1660 wl_display_terminate(ec->base.wl_display);
1661}
1662
1663static int
David Herrmannd7488c22012-03-11 20:05:21 +01001664udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001665{
David Herrmannd7488c22012-03-11 20:05:21 +01001666 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001667 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001668
1669 sysnum = udev_device_get_sysnum(device);
1670 if (!sysnum || atoi(sysnum) != ec->drm.id)
1671 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001672
David Herrmann6ac52db2012-03-11 20:05:22 +01001673 val = udev_device_get_property_value(device, "HOTPLUG");
1674 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001675 return 0;
1676
David Herrmann6ac52db2012-03-11 20:05:22 +01001677 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678}
1679
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001680static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001681udev_drm_event(int fd, uint32_t mask, void *data)
1682{
1683 struct drm_compositor *ec = data;
1684 struct udev_device *event;
1685
1686 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001687
David Herrmannd7488c22012-03-11 20:05:21 +01001688 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001689 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001690
1691 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001692
1693 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001694}
1695
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001696static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001697drm_restore(struct weston_compositor *ec)
1698{
1699 struct drm_compositor *d = (struct drm_compositor *) ec;
1700
1701 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1702 weston_log("failed to drop master: %m\n");
1703 tty_reset(d->tty);
1704}
1705
Pekka Paalanen33156972012-08-03 13:30:30 -04001706static const char default_seat[] = "seat0";
1707
1708static void
1709device_added(struct udev_device *udev_device, struct drm_seat *master)
1710{
1711 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001712 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001713 const char *devnode;
1714 const char *device_seat;
1715 int fd;
1716
1717 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1718 if (!device_seat)
1719 device_seat = default_seat;
1720
1721 if (strcmp(device_seat, master->seat_id))
1722 return;
1723
1724 c = master->base.compositor;
1725 devnode = udev_device_get_devnode(udev_device);
1726
1727 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001728 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001729 * read. mtdev_get() also expects this. */
1730 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1731 if (fd < 0) {
1732 weston_log("opening input device '%s' failed.\n", devnode);
1733 return;
1734 }
1735
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001736 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001737 if (!device) {
1738 close(fd);
1739 weston_log("not using input device '%s'.\n", devnode);
1740 return;
1741 }
1742
1743 wl_list_insert(master->devices_list.prev, &device->link);
1744}
1745
1746static void
1747evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1748{
1749 struct drm_seat *seat = (struct drm_seat *) seat_base;
1750 struct udev_enumerate *e;
1751 struct udev_list_entry *entry;
1752 struct udev_device *device;
1753 const char *path, *sysname;
1754
1755 e = udev_enumerate_new(udev);
1756 udev_enumerate_add_match_subsystem(e, "input");
1757 udev_enumerate_scan_devices(e);
1758 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1759 path = udev_list_entry_get_name(entry);
1760 device = udev_device_new_from_syspath(udev, path);
1761
1762 sysname = udev_device_get_sysname(device);
1763 if (strncmp("event", sysname, 5) != 0) {
1764 udev_device_unref(device);
1765 continue;
1766 }
1767
1768 device_added(device, seat);
1769
1770 udev_device_unref(device);
1771 }
1772 udev_enumerate_unref(e);
1773
1774 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1775
1776 if (wl_list_empty(&seat->devices_list)) {
1777 weston_log(
1778 "warning: no input devices on entering Weston. "
1779 "Possible causes:\n"
1780 "\t- no permissions to read /dev/input/event*\n"
1781 "\t- seats misconfigured "
1782 "(Weston backend option 'seat', "
1783 "udev device property ID_SEAT)\n");
1784 }
1785}
1786
1787static int
1788evdev_udev_handler(int fd, uint32_t mask, void *data)
1789{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001790 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001791 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001792 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001793 const char *action;
1794 const char *devnode;
1795
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001796 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001797 if (!udev_device)
1798 return 1;
1799
1800 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001801 if (!action)
1802 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001803
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001804 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1805 goto out;
1806
1807 if (!strcmp(action, "add")) {
1808 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001809 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001810 else if (!strcmp(action, "remove")) {
1811 devnode = udev_device_get_devnode(udev_device);
1812 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1813 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001814 weston_log("input device %s, %s removed\n",
1815 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001816 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001817 break;
1818 }
1819 }
1820
1821out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001822 udev_device_unref(udev_device);
1823
1824 return 0;
1825}
1826
1827static int
1828evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1829{
1830 struct drm_seat *master = (struct drm_seat *) seat_base;
1831 struct wl_event_loop *loop;
1832 struct weston_compositor *c = master->base.compositor;
1833 int fd;
1834
1835 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1836 if (!master->udev_monitor) {
1837 weston_log("udev: failed to create the udev monitor\n");
1838 return 0;
1839 }
1840
1841 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1842 "input", NULL);
1843
1844 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1845 weston_log("udev: failed to bind the udev monitor\n");
1846 udev_monitor_unref(master->udev_monitor);
1847 return 0;
1848 }
1849
1850 loop = wl_display_get_event_loop(c->wl_display);
1851 fd = udev_monitor_get_fd(master->udev_monitor);
1852 master->udev_monitor_source =
1853 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1854 evdev_udev_handler, master);
1855 if (!master->udev_monitor_source) {
1856 udev_monitor_unref(master->udev_monitor);
1857 return 0;
1858 }
1859
1860 return 1;
1861}
1862
1863static void
1864evdev_disable_udev_monitor(struct weston_seat *seat_base)
1865{
1866 struct drm_seat *seat = (struct drm_seat *) seat_base;
1867
1868 if (!seat->udev_monitor)
1869 return;
1870
1871 udev_monitor_unref(seat->udev_monitor);
1872 seat->udev_monitor = NULL;
1873 wl_event_source_remove(seat->udev_monitor_source);
1874 seat->udev_monitor_source = NULL;
1875}
1876
1877static void
1878drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1879{
1880 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001881 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001882
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001883 wl_list_for_each(device, &seat->devices_list, link)
1884 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001885}
1886
1887static void
1888evdev_input_create(struct weston_compositor *c, struct udev *udev,
1889 const char *seat_id)
1890{
1891 struct drm_seat *seat;
1892
1893 seat = malloc(sizeof *seat);
1894 if (seat == NULL)
1895 return;
1896
1897 memset(seat, 0, sizeof *seat);
1898 weston_seat_init(&seat->base, c);
1899 seat->base.led_update = drm_led_update;
1900
1901 wl_list_init(&seat->devices_list);
1902 seat->seat_id = strdup(seat_id);
1903 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1904 free(seat->seat_id);
1905 free(seat);
1906 return;
1907 }
1908
1909 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001910}
1911
1912static void
1913evdev_remove_devices(struct weston_seat *seat_base)
1914{
1915 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001916 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001917
1918 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001919 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001920
Pekka Paalanend8583512012-08-03 14:39:11 +03001921 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001922 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001923}
1924
1925static void
1926evdev_input_destroy(struct weston_seat *seat_base)
1927{
1928 struct drm_seat *seat = (struct drm_seat *) seat_base;
1929
1930 evdev_remove_devices(seat_base);
1931 evdev_disable_udev_monitor(&seat->base);
1932
1933 weston_seat_release(seat_base);
1934 free(seat->seat_id);
1935 free(seat);
1936}
1937
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001938static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001939drm_free_configured_output(struct drm_configured_output *output)
1940{
1941 free(output->name);
1942 free(output->mode);
1943 free(output);
1944}
1945
1946static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001947drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001948{
1949 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001950 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001951 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001952
Daniel Stone37816df2012-05-16 18:45:18 +01001953 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1954 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001955 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001956 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001957
1958 wl_event_source_remove(d->udev_drm_source);
1959 wl_event_source_remove(d->drm_source);
1960
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001961 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001962
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001963 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001964
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001965 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001966 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001967 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001968 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001969 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001970
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001971 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001972}
1973
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001974static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001975drm_compositor_set_modes(struct drm_compositor *compositor)
1976{
1977 struct drm_output *output;
1978 struct drm_mode *drm_mode;
1979 int ret;
1980
1981 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1982 drm_mode = (struct drm_mode *) output->base.current;
1983 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001984 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001985 &output->connector_id, 1,
1986 &drm_mode->mode_info);
1987 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001988 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001989 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001990 drm_mode->base.width, drm_mode->base.height,
1991 output->base.x, output->base.y);
1992 }
1993 }
1994}
1995
1996static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001997vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001998{
1999 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002000 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002001 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002002 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002003
2004 switch (event) {
2005 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002006 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002007 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002008 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002009 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002010 wl_display_terminate(compositor->wl_display);
2011 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002012 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002013 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002014 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002015 wl_list_for_each(seat, &compositor->seat_list, link) {
2016 evdev_add_devices(ec->udev, seat);
2017 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002018 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002019 break;
2020 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002021 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002022 wl_list_for_each(seat, &compositor->seat_list, link) {
2023 evdev_disable_udev_monitor(seat);
2024 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002025 }
2026
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002027 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002028 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002029 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002030
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002031 /* If we have a repaint scheduled (either from a
2032 * pending pageflip or the idle handler), make sure we
2033 * cancel that so we don't try to pageflip when we're
2034 * vt switched away. The SLEEPING state will prevent
2035 * further attemps at repainting. When we switch
2036 * back, we schedule a repaint, which will process
2037 * pending frame callbacks. */
2038
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002039 wl_list_for_each(output, &ec->base.output_list, base.link) {
2040 output->base.repaint_needed = 0;
2041 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002042 }
2043
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002044 output = container_of(ec->base.output_list.next,
2045 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002046
2047 wl_list_for_each(sprite, &ec->sprite_list, link)
2048 drmModeSetPlane(ec->drm.fd,
2049 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002050 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002051 0, 0, 0, 0, 0, 0, 0, 0);
2052
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002053 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002054 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002055
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002056 break;
2057 };
2058}
2059
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002060static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002061switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002062{
2063 struct drm_compositor *ec = data;
2064
Daniel Stone325fc2d2012-05-30 16:31:58 +01002065 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002066}
2067
David Herrmann0af066f2012-10-29 19:21:16 +01002068/*
2069 * Find primary GPU
2070 * Some systems may have multiple DRM devices attached to a single seat. This
2071 * function loops over all devices and tries to find a PCI device with the
2072 * boot_vga sysfs attribute set to 1.
2073 * If no such device is found, the first DRM device reported by udev is used.
2074 */
2075static struct udev_device*
2076find_primary_gpu(struct drm_compositor *ec, const char *seat)
2077{
2078 struct udev_enumerate *e;
2079 struct udev_list_entry *entry;
2080 const char *path, *device_seat, *id;
2081 struct udev_device *device, *drm_device, *pci;
2082
2083 e = udev_enumerate_new(ec->udev);
2084 udev_enumerate_add_match_subsystem(e, "drm");
2085 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2086
2087 udev_enumerate_scan_devices(e);
2088 drm_device = NULL;
2089 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2090 path = udev_list_entry_get_name(entry);
2091 device = udev_device_new_from_syspath(ec->udev, path);
2092 if (!device)
2093 continue;
2094 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2095 if (!device_seat)
2096 device_seat = default_seat;
2097 if (strcmp(device_seat, seat)) {
2098 udev_device_unref(device);
2099 continue;
2100 }
2101
2102 pci = udev_device_get_parent_with_subsystem_devtype(device,
2103 "pci", NULL);
2104 if (pci) {
2105 id = udev_device_get_sysattr_value(pci, "boot_vga");
2106 if (id && !strcmp(id, "1")) {
2107 if (drm_device)
2108 udev_device_unref(drm_device);
2109 drm_device = device;
2110 break;
2111 }
2112 }
2113
2114 if (!drm_device)
2115 drm_device = device;
2116 else
2117 udev_device_unref(device);
2118 }
2119
2120 udev_enumerate_unref(e);
2121 return drm_device;
2122}
2123
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002124static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002125planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002126{
2127 struct drm_compositor *c = data;
2128
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002129 switch (key) {
2130 case KEY_C:
2131 c->cursors_are_broken ^= 1;
2132 break;
2133 case KEY_V:
2134 c->sprites_are_broken ^= 1;
2135 break;
2136 case KEY_O:
2137 c->sprites_hidden ^= 1;
2138 break;
2139 default:
2140 break;
2141 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002142}
2143
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002144static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002145drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002146 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002147 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002148{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002149 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002150 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002151 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002152 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002153 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002154 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002155
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002156 weston_log("initializing drm backend\n");
2157
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002158 ec = malloc(sizeof *ec);
2159 if (ec == NULL)
2160 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002161 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002162
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002163 /* KMS support for sprites is not complete yet, so disable the
2164 * functionality for now. */
2165 ec->sprites_are_broken = 1;
2166
Daniel Stone725c2c32012-06-22 14:04:36 +01002167 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002168 config_file) < 0) {
2169 weston_log("weston_compositor_init failed\n");
2170 goto err_base;
2171 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002172
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002173 ec->udev = udev_new();
2174 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002175 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002176 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002177 }
2178
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002179 ec->base.wl_display = display;
2180 ec->tty = tty_create(&ec->base, vt_func, tty);
2181 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002182 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002183 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002184 }
2185
David Herrmann0af066f2012-10-29 19:21:16 +01002186 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002187 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002188 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002189 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002190 }
David Herrmann0af066f2012-10-29 19:21:16 +01002191 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002192
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002193 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002194 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002195 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002196 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002197
2198 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002199 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002200
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002201 ec->base.focus = 1;
2202
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002203 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002204
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002205 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002206 weston_compositor_add_key_binding(&ec->base, key,
2207 MODIFIER_CTRL | MODIFIER_ALT,
2208 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002209
Jesse Barnes58ef3792012-02-23 09:45:49 -05002210 wl_list_init(&ec->sprite_list);
2211 create_sprites(ec);
2212
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002213 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002214 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002215 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002216 }
2217
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002218 path = NULL;
2219
Tiago Vignattice03ec32011-12-19 01:14:03 +02002220 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002221
2222 loop = wl_display_get_event_loop(ec->base.wl_display);
2223 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002224 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002225 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002226
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002227 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2228 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002229 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002230 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002231 }
2232 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2233 "drm", NULL);
2234 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002235 wl_event_loop_add_fd(loop,
2236 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002237 WL_EVENT_READABLE, udev_drm_event, ec);
2238
2239 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002240 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002241 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002242 }
2243
Daniel Stonea96b93c2012-06-22 14:04:37 +01002244 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002245
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002246 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002247 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002248 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002249 planes_binding, ec);
2250 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2251 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002252
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002253 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002254
2255err_udev_monitor:
2256 wl_event_source_remove(ec->udev_drm_source);
2257 udev_monitor_unref(ec->udev_monitor);
2258err_drm_source:
2259 wl_event_source_remove(ec->drm_source);
2260 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2261 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002262err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002263 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002264 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002265 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002266err_udev_dev:
2267 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002268err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002269 tty_destroy(ec->tty);
2270err_udev:
2271 udev_unref(ec->udev);
2272err_compositor:
2273 weston_compositor_shutdown(&ec->base);
2274err_base:
2275 free(ec);
2276 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002277}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002278
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002279static int
2280set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2281{
2282 mode->flags = 0;
2283
2284 if (strcmp(hsync, "+hsync") == 0)
2285 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2286 else if (strcmp(hsync, "-hsync") == 0)
2287 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2288 else
2289 return -1;
2290
2291 if (strcmp(vsync, "+vsync") == 0)
2292 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2293 else if (strcmp(vsync, "-vsync") == 0)
2294 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2295 else
2296 return -1;
2297
2298 return 0;
2299}
2300
2301static int
2302check_for_modeline(struct drm_configured_output *output)
2303{
2304 drmModeModeInfo mode;
2305 char hsync[16];
2306 char vsync[16];
2307 char mode_name[16];
2308 float fclock;
2309
2310 mode.type = DRM_MODE_TYPE_USERDEF;
2311 mode.hskew = 0;
2312 mode.vscan = 0;
2313 mode.vrefresh = 0;
2314
2315 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2316 &fclock, &mode.hdisplay,
2317 &mode.hsync_start,
2318 &mode.hsync_end, &mode.htotal,
2319 &mode.vdisplay,
2320 &mode.vsync_start,
2321 &mode.vsync_end, &mode.vtotal,
2322 hsync, vsync) == 11) {
2323 if (set_sync_flags(&mode, hsync, vsync))
2324 return -1;
2325
2326 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2327 strcpy(mode.name, mode_name);
2328
2329 mode.clock = fclock * 1000;
2330 } else
2331 return -1;
2332
2333 output->crtc_mode = mode;
2334
2335 return 0;
2336}
2337
Scott Moreau8ab5d452012-07-30 19:51:08 -06002338static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002339drm_output_set_transform(struct drm_configured_output *output)
2340{
2341 if (!output_transform) {
2342 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2343 return;
2344 }
2345
2346 if (!strcmp(output_transform, "normal"))
2347 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2348 else if (!strcmp(output_transform, "90"))
2349 output->transform = WL_OUTPUT_TRANSFORM_90;
2350 else if (!strcmp(output_transform, "180"))
2351 output->transform = WL_OUTPUT_TRANSFORM_180;
2352 else if (!strcmp(output_transform, "270"))
2353 output->transform = WL_OUTPUT_TRANSFORM_270;
2354 else if (!strcmp(output_transform, "flipped"))
2355 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2356 else if (!strcmp(output_transform, "flipped-90"))
2357 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2358 else if (!strcmp(output_transform, "flipped-180"))
2359 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2360 else if (!strcmp(output_transform, "flipped-270"))
2361 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2362 else {
2363 weston_log("Invalid transform \"%s\" for output %s\n",
2364 output_transform, output_name);
2365 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2366 }
2367
2368 free(output_transform);
2369 output_transform = NULL;
2370}
2371
2372static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002373output_section_done(void *data)
2374{
2375 struct drm_configured_output *output;
2376
2377 output = malloc(sizeof *output);
2378
Scott Moreau1bad5db2012-08-18 01:04:05 -06002379 if (!output || !output_name || (output_name[0] == 'X') ||
2380 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002381 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002382 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002383 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002384 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002385 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002386 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002387 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002388 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002389 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002390
2391 output->config = OUTPUT_CONFIG_INVALID;
2392 output->name = output_name;
2393 output->mode = output_mode;
2394
Scott Moreau1bad5db2012-08-18 01:04:05 -06002395 if (output_mode) {
2396 if (strcmp(output_mode, "off") == 0)
2397 output->config = OUTPUT_CONFIG_OFF;
2398 else if (strcmp(output_mode, "preferred") == 0)
2399 output->config = OUTPUT_CONFIG_PREFERRED;
2400 else if (strcmp(output_mode, "current") == 0)
2401 output->config = OUTPUT_CONFIG_CURRENT;
2402 else if (sscanf(output_mode, "%dx%d",
2403 &output->width, &output->height) == 2)
2404 output->config = OUTPUT_CONFIG_MODE;
2405 else if (check_for_modeline(output) == 0)
2406 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002407
Scott Moreau1bad5db2012-08-18 01:04:05 -06002408 if (output->config == OUTPUT_CONFIG_INVALID)
2409 weston_log("Invalid mode \"%s\" for output %s\n",
2410 output_mode, output_name);
2411 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002412 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002413
2414 drm_output_set_transform(output);
2415
2416 wl_list_insert(&configured_output_list, &output->link);
2417
2418 if (output_transform)
2419 free(output_transform);
2420 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002421}
2422
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002423WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002424backend_init(struct wl_display *display, int argc, char *argv[],
2425 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002426{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002427 int connector = 0, tty = 0;
2428 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002429
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002430 const struct weston_option drm_options[] = {
2431 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2432 { WESTON_OPTION_STRING, "seat", 0, &seat },
2433 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002434 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002435 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002436
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002437 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002438
Scott Moreau8ab5d452012-07-30 19:51:08 -06002439 wl_list_init(&configured_output_list);
2440
2441 const struct config_key drm_config_keys[] = {
2442 { "name", CONFIG_KEY_STRING, &output_name },
2443 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002444 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002445 };
2446
2447 const struct config_section config_section[] = {
2448 { "output", drm_config_keys,
2449 ARRAY_LENGTH(drm_config_keys), output_section_done },
2450 };
2451
2452 parse_config_file(config_file, config_section,
2453 ARRAY_LENGTH(config_section), NULL);
2454
Daniel Stonec1be8e52012-06-01 11:14:02 -04002455 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2456 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002457}