blob: 142faa5cee0c60835addd0008d632711dca903ec [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 ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200319 es->geometry.width != output->base.current->width ||
320 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200321 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400322 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400323 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500324
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400325 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
326 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500327
Rob Bradford9b101872012-09-14 23:25:41 +0100328 /* Unable to use the buffer for scanout */
329 if (!bo)
330 return NULL;
331
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300332 /* Need to verify output->region contained in surface opaque
333 * region. Or maybe just that format doesn't have alpha.
334 * For now, scanout only if format is XRGB8888. */
335 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
336 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400337 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300338 }
339
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200340 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341 if (!output->next) {
342 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400343 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300344 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500345
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200346 drm_fb_set_buffer(output->next, es->buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500347
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400348 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500349}
350
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500351static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400352drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400353{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200354 struct drm_compositor *c =
355 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400357
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400359
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300360 bo = gbm_surface_lock_front_buffer(output->surface);
361 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200362 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400363 return;
364 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200366 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200368 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300369 gbm_surface_release_buffer(output->surface, bo);
370 return;
371 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400372}
373
374static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500375drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400376 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100377{
378 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500379 struct drm_compositor *compositor =
380 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500381 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400382 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500383 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100384
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300385 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400386 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300387 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400388 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100389
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400390 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300391 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400392 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300393 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400394 &output->connector_id, 1,
395 &mode->mode_info);
396 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200397 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400398 return;
399 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200400 }
401
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500402 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300403 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500404 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200405 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500406 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500407 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100408
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300409 output->page_flip_pending = 1;
410
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400411 drm_output_set_cursor(output);
412
Jesse Barnes58ef3792012-02-23 09:45:49 -0500413 /*
414 * Now, update all the sprite surfaces
415 */
416 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200417 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500418 drmVBlank vbl = {
419 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
420 .request.sequence = 1,
421 };
422
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200423 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200424 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500425 continue;
426
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200427 if (s->next && !compositor->sprites_hidden)
428 fb_id = s->next->fb_id;
429
Jesse Barnes58ef3792012-02-23 09:45:49 -0500430 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200431 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500432 s->dest_x, s->dest_y,
433 s->dest_w, s->dest_h,
434 s->src_x, s->src_y,
435 s->src_w, s->src_h);
436 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200437 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500438 ret, strerror(errno));
439
Rob Clark5ca1a472012-08-08 20:27:37 -0500440 if (output->pipe > 0)
441 vbl.request.type |= DRM_VBLANK_SECONDARY;
442
Jesse Barnes58ef3792012-02-23 09:45:49 -0500443 /*
444 * Queue a vblank signal so we know when the surface
445 * becomes active on the display or has been replaced.
446 */
447 vbl.request.signal = (unsigned long)s;
448 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
449 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200450 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500451 ret, strerror(errno));
452 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300453
454 s->output = output;
455 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500456 }
457
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500458 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400459}
460
461static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500462vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
463 void *data)
464{
465 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300466 struct drm_output *output = s->output;
467 uint32_t msecs;
468
469 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500470
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200471 if (s->current)
472 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500473
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200474 s->current = s->next;
475 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300476
477 if (!output->page_flip_pending) {
478 msecs = sec * 1000 + usec / 1000;
479 weston_output_finish_frame(&output->base, msecs);
480 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500481}
482
483static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400484page_flip_handler(int fd, unsigned int frame,
485 unsigned int sec, unsigned int usec, void *data)
486{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200487 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400488 uint32_t msecs;
489
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300490 output->page_flip_pending = 0;
491
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300492 if (output->current) {
493 if (output->current->is_client_buffer)
494 gbm_bo_destroy(output->current->bo);
495 else
496 gbm_surface_release_buffer(output->surface,
497 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200498 }
499
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300500 output->current = output->next;
501 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400502
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300503 if (!output->vblank_pending) {
504 msecs = sec * 1000 + usec / 1000;
505 weston_output_finish_frame(&output->base, msecs);
506 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200507}
508
509static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500510drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
511{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400512 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500513
514 for (i = 0; i < s->count_formats; i++)
515 if (s->formats[i] == format)
516 return 1;
517
518 return 0;
519}
520
521static int
522drm_surface_transform_supported(struct weston_surface *es)
523{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400524 struct weston_matrix *matrix = &es->transform.matrix;
525 int i;
526
527 if (!es->transform.enabled)
528 return 1;
529
530 for (i = 0; i < 16; i++) {
531 switch (i) {
532 case 10:
533 case 15:
534 if (matrix->d[i] != 1.0)
535 return 0;
536 break;
537 case 0:
538 case 5:
539 case 12:
540 case 13:
541 break;
542 default:
543 if (matrix->d[i] != 0.0)
544 return 0;
545 break;
546 }
547 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500548
549 return 1;
550}
551
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400552static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500553drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400554 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500555{
556 struct weston_compositor *ec = output_base->compositor;
557 struct drm_compositor *c =(struct drm_compositor *) ec;
558 struct drm_sprite *s;
559 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500560 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500561 pixman_region32_t dest_rect, src_rect;
562 pixman_box32_t *box;
563 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400564 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500565
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500566 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400567 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500568
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300569 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400570 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300571
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400572 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400573 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200575 if (es->alpha != 1.0f)
576 return NULL;
577
Rob Clark702ffae2012-08-09 14:18:27 -0500578 if (wl_buffer_is_shm(es->buffer))
579 return NULL;
580
Jesse Barnes58ef3792012-02-23 09:45:49 -0500581 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400582 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500583
Jesse Barnes58ef3792012-02-23 09:45:49 -0500584 wl_list_for_each(s, &c->sprite_list, link) {
585 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
586 continue;
587
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200588 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589 found = 1;
590 break;
591 }
592 }
593
594 /* No sprites available */
595 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400596 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500597
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400598 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
599 es->buffer, GBM_BO_USE_SCANOUT);
600 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400601 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400602
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200605 if (!drm_surface_format_supported(s, format)) {
606 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400607 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 }
609
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200610 s->next = drm_fb_get_from_bo(bo, c);
611 if (!s->next) {
612 gbm_bo_destroy(bo);
613 return NULL;
614 }
615
616 drm_fb_set_buffer(s->next, es->buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500617
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400618 box = pixman_region32_extents(&es->transform.boundingbox);
619 s->plane.x = box->x1;
620 s->plane.y = box->y1;
621
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 /*
623 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200624 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500625 * for us already).
626 */
627 pixman_region32_init(&dest_rect);
628 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
629 &output_base->region);
630 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
631 box = pixman_region32_extents(&dest_rect);
632 s->dest_x = box->x1;
633 s->dest_y = box->y1;
634 s->dest_w = box->x2 - box->x1;
635 s->dest_h = box->y2 - box->y1;
636 pixman_region32_fini(&dest_rect);
637
638 pixman_region32_init(&src_rect);
639 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
640 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400642
643 weston_surface_from_global_fixed(es,
644 wl_fixed_from_int(box->x1),
645 wl_fixed_from_int(box->y1),
646 &sx1, &sy1);
647 weston_surface_from_global_fixed(es,
648 wl_fixed_from_int(box->x2),
649 wl_fixed_from_int(box->y2),
650 &sx2, &sy2);
651
652 if (sx1 < 0)
653 sx1 = 0;
654 if (sy1 < 0)
655 sy1 = 0;
656 if (sx2 > wl_fixed_from_int(es->geometry.width))
657 sx2 = wl_fixed_from_int(es->geometry.width);
658 if (sy2 > wl_fixed_from_int(es->geometry.height))
659 sy2 = wl_fixed_from_int(es->geometry.height);
660
661 s->src_x = sx1 << 8;
662 s->src_y = sy1 << 8;
663 s->src_w = (sx2 - sx1) << 8;
664 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665 pixman_region32_fini(&src_rect);
666
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400667 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668}
669
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400670static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400671drm_output_prepare_cursor_surface(struct weston_output *output_base,
672 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500673{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400674 struct drm_compositor *c =
675 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400676 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400677
678 if (output->cursor_surface)
679 return NULL;
680 if (es->output_mask != (1u << output_base->id))
681 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500682 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400683 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400684 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
685 es->geometry.width > 64 || es->geometry.height > 64)
686 return NULL;
687
688 output->cursor_surface = es;
689
690 return &output->cursor_plane;
691}
692
693static void
694drm_output_set_cursor(struct drm_output *output)
695{
696 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400697 struct drm_compositor *c =
698 (struct drm_compositor *) output->base.compositor;
699 EGLint handle, stride;
700 struct gbm_bo *bo;
701 uint32_t buf[64 * 64];
702 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400703 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500704
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400705 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400706 if (es == NULL) {
707 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
708 return;
709 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500710
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400711 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
712 pixman_region32_fini(&output->cursor_plane.damage);
713 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400714 output->current_cursor ^= 1;
715 bo = output->cursor_bo[output->current_cursor];
716 memset(buf, 0, sizeof buf);
717 stride = wl_shm_buffer_get_stride(es->buffer);
718 s = wl_shm_buffer_get_data(es->buffer);
719 for (i = 0; i < es->geometry.height; i++)
720 memcpy(buf + i * 64, s + i * stride,
721 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500722
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400723 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300724 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400725
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400726 handle = gbm_bo_get_handle(bo).s32;
727 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500728 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300729 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500730 c->cursors_are_broken = 1;
731 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400732 }
733
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400734 x = es->geometry.x - output->base.x;
735 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400736 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500737 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400738 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500739 c->cursors_are_broken = 1;
740 }
741
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400742 output->cursor_plane.x = x;
743 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400744 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500745}
746
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747static void
748drm_assign_planes(struct weston_output *output)
749{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400750 struct drm_compositor *c =
751 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200752 struct drm_output *drm_output = (struct drm_output *) output;
753 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400754 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500755 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400756 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500757
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200758 /* Reset the opaque region of the planes */
759 pixman_region32_fini(&drm_output->cursor_plane.opaque);
760 pixman_region32_init(&drm_output->cursor_plane.opaque);
761 pixman_region32_fini(&drm_output->fb_plane.opaque);
762 pixman_region32_init(&drm_output->fb_plane.opaque);
763
764 wl_list_for_each (s, &c->sprite_list, link) {
765 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
766 continue;
767
768 pixman_region32_fini(&s->plane.opaque);
769 pixman_region32_init(&s->plane.opaque);
770 }
771
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772 /*
773 * Find a surface for each sprite in the output using some heuristics:
774 * 1) size
775 * 2) frequency of update
776 * 3) opacity (though some hw might support alpha blending)
777 * 4) clipping (this can be fixed with color keys)
778 *
779 * The idea is to save on blitting since this should save power.
780 * If we can get a large video surface on the sprite for example,
781 * the main display surface may not need to update at all, and
782 * the client buffer can be used directly for the sprite surface
783 * as we do for flipping full screen surfaces.
784 */
785 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400786 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400787 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500788 pixman_region32_init(&surface_overlap);
789 pixman_region32_intersect(&surface_overlap, &overlap,
790 &es->transform.boundingbox);
791
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400792 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400793 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 next_plane = primary;
795 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400796 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400797 if (next_plane == NULL)
798 next_plane = drm_output_prepare_scanout_surface(output, es);
799 if (next_plane == NULL)
800 next_plane = drm_output_prepare_overlay_surface(output, es);
801 if (next_plane == NULL)
802 next_plane = primary;
803 weston_surface_move_to_plane(es, next_plane);
804 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500805 pixman_region32_union(&overlap, &overlap,
806 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400807
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808 pixman_region32_fini(&surface_overlap);
809 }
810 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500811}
812
Matt Roper361d2ad2011-08-29 13:52:23 -0700813static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500814drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700815{
816 struct drm_output *output = (struct drm_output *) output_base;
817 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200818 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700819 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700820
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200821 if (output->backlight)
822 backlight_destroy(output->backlight);
823
Matt Roper361d2ad2011-08-29 13:52:23 -0700824 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400825 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700826
827 /* Restore original CRTC state */
828 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200829 origcrtc->x, origcrtc->y,
830 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700831 drmModeFreeCrtc(origcrtc);
832
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200833 c->crtc_allocator &= ~(1 << output->crtc_id);
834 c->connector_allocator &= ~(1 << output->connector_id);
835
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100836 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100837
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400838 gbm_surface_destroy(output->surface);
839
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400840 weston_plane_release(&output->fb_plane);
841 weston_plane_release(&output->cursor_plane);
842
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500843 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200844 wl_list_remove(&output->base.link);
845
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400846 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700847 free(output);
848}
849
Alex Wub7b8bda2012-04-17 17:20:48 +0800850static struct drm_mode *
851choose_mode (struct drm_output *output, struct weston_mode *target_mode)
852{
853 struct drm_mode *tmp_mode = NULL, *mode;
854
855 if (output->base.current->width == target_mode->width &&
856 output->base.current->height == target_mode->height &&
857 (output->base.current->refresh == target_mode->refresh ||
858 target_mode->refresh == 0))
859 return (struct drm_mode *)output->base.current;
860
861 wl_list_for_each(mode, &output->base.mode_list, base.link) {
862 if (mode->mode_info.hdisplay == target_mode->width &&
863 mode->mode_info.vdisplay == target_mode->height) {
864 if (mode->mode_info.vrefresh == target_mode->refresh ||
865 target_mode->refresh == 0) {
866 return mode;
867 } else if (!tmp_mode)
868 tmp_mode = mode;
869 }
870 }
871
872 return tmp_mode;
873}
874
875static int
876drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
877{
878 struct drm_output *output;
879 struct drm_mode *drm_mode;
880 int ret;
881 struct drm_compositor *ec;
882 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800883
884 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200885 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800886 return -1;
887 }
888
889 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200890 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800891 return -1;
892 }
893
894 ec = (struct drm_compositor *)output_base->compositor;
895 output = (struct drm_output *)output_base;
896 drm_mode = choose_mode (output, mode);
897
898 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200899 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800900 return -1;
901 } else if (&drm_mode->base == output->base.current) {
902 return 0;
903 } else if (drm_mode->base.width == output->base.current->width &&
904 drm_mode->base.height == output->base.current->height) {
905 /* only change refresh value */
906 ret = drmModeSetCrtc(ec->drm.fd,
907 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300908 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800909 &output->connector_id, 1, &drm_mode->mode_info);
910
911 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200912 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800913 drm_mode->base.width,
914 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400915 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800916 ret = -1;
917 } else {
918 output->base.current->flags = 0;
919 output->base.current = &drm_mode->base;
920 drm_mode->base.flags =
921 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
922 ret = 0;
923 }
924
925 return ret;
926 }
927
928 drm_mode->base.flags =
929 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
930
931 surface = gbm_surface_create(ec->gbm,
932 drm_mode->base.width,
933 drm_mode->base.height,
934 GBM_FORMAT_XRGB8888,
935 GBM_BO_USE_SCANOUT |
936 GBM_BO_USE_RENDERING);
937 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200938 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800939 return -1;
940 }
941
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100942 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800943
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100944 if (!gl_renderer_output_create(&output->base, surface)) {
John Kåre Alsaker94659272012-11-13 19:10:18 +0100945 weston_log("failed to create renderer output\n");
946 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800947 }
948
949 ret = drmModeSetCrtc(ec->drm.fd,
950 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300951 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800952 &output->connector_id, 1, &drm_mode->mode_info);
953 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200954 weston_log("failed to set mode\n");
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100955 goto err_gl;
Alex Wub7b8bda2012-04-17 17:20:48 +0800956 }
957
958 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300959 if (output->current) {
960 if (output->current->is_client_buffer)
961 gbm_bo_destroy(output->current->bo);
962 else
963 gbm_surface_release_buffer(output->surface,
964 output->current->bo);
965 }
966 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800967
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300968 if (output->next) {
969 if (output->next->is_client_buffer)
970 gbm_bo_destroy(output->next->bo);
971 else
972 gbm_surface_release_buffer(output->surface,
973 output->next->bo);
974 }
975 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800976
Alex Wub7b8bda2012-04-17 17:20:48 +0800977 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800978 output->surface = surface;
979
980 /*update output*/
981 output->base.current = &drm_mode->base;
982 output->base.dirty = 1;
983 weston_output_move(&output->base, output->base.x, output->base.y);
984 return 0;
985
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100986err_gl:
987 gl_renderer_output_destroy(&output->base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100988err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +0800989 gbm_surface_destroy(surface);
990 return -1;
991}
992
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400993static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400994on_drm_input(int fd, uint32_t mask, void *data)
995{
996 drmEventContext evctx;
997
998 memset(&evctx, 0, sizeof evctx);
999 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1000 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001001 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001002 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001003
1004 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001005}
1006
1007static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001008init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001009{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001010 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001011 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001012
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001013 sysnum = udev_device_get_sysnum(device);
1014 if (sysnum)
1015 ec->drm.id = atoi(sysnum);
1016 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001017 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001018 return -1;
1019 }
1020
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001021 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001022 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001023 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001024 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001025 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001026 udev_device_get_devnode(device));
1027 return -1;
1028 }
1029
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001030 weston_log("using %s\n", filename);
1031
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001032 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001033 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001034
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001035 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001036 NULL) < 0) {
1037 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001038 return -1;
1039 }
1040
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001041 return 0;
1042}
1043
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001044static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001045drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1046{
1047 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001048 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001049
1050 mode = malloc(sizeof *mode);
1051 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001052 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001053
1054 mode->base.flags = 0;
1055 mode->base.width = info->hdisplay;
1056 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001057
1058 /* Calculate higher precision (mHz) refresh rate */
1059 refresh = (info->clock * 1000000LL / info->htotal +
1060 info->vtotal / 2) / info->vtotal;
1061
1062 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1063 refresh *= 2;
1064 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1065 refresh /= 2;
1066 if (info->vscan > 1)
1067 refresh /= info->vscan;
1068
1069 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001070 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001071
1072 if (info->type & DRM_MODE_TYPE_PREFERRED)
1073 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1074
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001075 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1076
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001077 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001078}
1079
1080static int
1081drm_subpixel_to_wayland(int drm_value)
1082{
1083 switch (drm_value) {
1084 default:
1085 case DRM_MODE_SUBPIXEL_UNKNOWN:
1086 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1087 case DRM_MODE_SUBPIXEL_NONE:
1088 return WL_OUTPUT_SUBPIXEL_NONE;
1089 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1090 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1091 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1092 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1093 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1094 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1095 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1096 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1097 }
1098}
1099
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001100/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001101static uint32_t
1102drm_get_backlight(struct drm_output *output)
1103{
1104 long brightness, max_brightness, norm;
1105
1106 brightness = backlight_get_brightness(output->backlight);
1107 max_brightness = backlight_get_max_brightness(output->backlight);
1108
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001109 /* convert it on a scale of 0 to 255 */
1110 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001111
1112 return (uint32_t) norm;
1113}
1114
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001115/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001116static void
1117drm_set_backlight(struct weston_output *output_base, uint32_t value)
1118{
1119 struct drm_output *output = (struct drm_output *) output_base;
1120 long max_brightness, new_brightness;
1121
1122 if (!output->backlight)
1123 return;
1124
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001125 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001126 return;
1127
1128 max_brightness = backlight_get_max_brightness(output->backlight);
1129
1130 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001131 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001132
1133 backlight_set_brightness(output->backlight, new_brightness);
1134}
1135
1136static drmModePropertyPtr
1137drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1138{
1139 drmModePropertyPtr props;
1140 int i;
1141
1142 for (i = 0; i < connector->count_props; i++) {
1143 props = drmModeGetProperty(fd, connector->props[i]);
1144 if (!props)
1145 continue;
1146
1147 if (!strcmp(props->name, name))
1148 return props;
1149
1150 drmModeFreeProperty(props);
1151 }
1152
1153 return NULL;
1154}
1155
1156static void
1157drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1158{
1159 struct drm_output *output = (struct drm_output *) output_base;
1160 struct weston_compositor *ec = output_base->compositor;
1161 struct drm_compositor *c = (struct drm_compositor *) ec;
1162 drmModeConnectorPtr connector;
1163 drmModePropertyPtr prop;
1164
1165 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1166 if (!connector)
1167 return;
1168
1169 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1170 if (!prop) {
1171 drmModeFreeConnector(connector);
1172 return;
1173 }
1174
1175 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1176 prop->prop_id, level);
1177 drmModeFreeProperty(prop);
1178 drmModeFreeConnector(connector);
1179}
1180
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001181static const char *connector_type_names[] = {
1182 "None",
1183 "VGA",
1184 "DVI",
1185 "DVI",
1186 "DVI",
1187 "Composite",
1188 "TV",
1189 "LVDS",
1190 "CTV",
1191 "DIN",
1192 "DP",
1193 "HDMI",
1194 "HDMI",
1195 "TV",
1196 "eDP",
1197};
1198
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001199static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001200find_crtc_for_connector(struct drm_compositor *ec,
1201 drmModeRes *resources, drmModeConnector *connector)
1202{
1203 drmModeEncoder *encoder;
1204 uint32_t possible_crtcs;
1205 int i, j;
1206
1207 for (j = 0; j < connector->count_encoders; j++) {
1208 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1209 if (encoder == NULL) {
1210 weston_log("Failed to get encoder.\n");
1211 return -1;
1212 }
1213 possible_crtcs = encoder->possible_crtcs;
1214 drmModeFreeEncoder(encoder);
1215
1216 for (i = 0; i < resources->count_crtcs; i++) {
1217 if (possible_crtcs & (1 << i) &&
1218 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1219 return i;
1220 }
1221 }
1222
1223 return -1;
1224}
1225
1226static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001227create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001228 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001229 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001230 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001231{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001232 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001233 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1234 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001235 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001236 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001237 drmModeModeInfo crtc_mode;
1238 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001239 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001240 char name[32];
1241 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001242
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001243 i = find_crtc_for_connector(ec, resources, connector);
1244 if (i < 0) {
1245 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001246 return -1;
1247 }
1248
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001249 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001250 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001251 return -1;
1252
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001253 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001254 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1255 output->base.make = "unknown";
1256 output->base.model = "unknown";
1257 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001258
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001259 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1260 type_name = connector_type_names[connector->connector_type];
1261 else
1262 type_name = "UNKNOWN";
1263 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1264 output->name = strdup(name);
1265
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001266 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001267 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001268 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001269 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001270 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001271
Matt Roper361d2ad2011-08-29 13:52:23 -07001272 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1273
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001274 /* Get the current mode on the crtc that's currently driving
1275 * this connector. */
1276 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001277 memset(&crtc_mode, 0, sizeof crtc_mode);
1278 if (encoder != NULL) {
1279 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1280 drmModeFreeEncoder(encoder);
1281 if (crtc == NULL)
1282 goto err_free;
1283 if (crtc->mode_valid)
1284 crtc_mode = crtc->mode;
1285 drmModeFreeCrtc(crtc);
1286 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001287
David Herrmann0f0d54e2011-12-08 17:05:45 +01001288 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001289 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1290 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001291 goto err_free;
1292 }
1293
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001294 preferred = NULL;
1295 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001296 configured = NULL;
1297
1298 wl_list_for_each(temp, &configured_output_list, link) {
1299 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001300 if (temp->mode)
1301 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001302 temp->name, temp->mode);
1303 o = temp;
1304 break;
1305 }
1306 }
1307
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001308 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001309 weston_log("Disabling output %s\n", o->name);
1310
1311 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1312 0, 0, 0, 0, 0, NULL);
1313 goto err_free;
1314 }
1315
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001316 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001317 if (o && o->config == OUTPUT_CONFIG_MODE &&
1318 o->width == drm_mode->base.width &&
1319 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001320 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001321 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001322 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001323 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001324 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001325 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001326
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001327 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001328 configured = drm_output_add_mode(output, &o->crtc_mode);
1329 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001330 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001331 current = configured;
1332 }
1333
Wang Quanxianacb805a2012-07-30 18:09:46 -04001334 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001335 current = drm_output_add_mode(output, &crtc_mode);
1336 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001337 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001338 }
1339
Scott Moreau8ab5d452012-07-30 19:51:08 -06001340 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1341 configured = current;
1342
Wang Quanxianacb805a2012-07-30 18:09:46 -04001343 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001344 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001345 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001346 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001347 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001348 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001349 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001350 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001351
1352 if (output->base.current == NULL) {
1353 weston_log("no available modes for %s\n", output->name);
1354 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001355 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001356
Wang Quanxianacb805a2012-07-30 18:09:46 -04001357 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1358
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001359 output->surface = gbm_surface_create(ec->gbm,
1360 output->base.current->width,
1361 output->base.current->height,
1362 GBM_FORMAT_XRGB8888,
1363 GBM_BO_USE_SCANOUT |
1364 GBM_BO_USE_RENDERING);
1365 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001366 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001367 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001368 }
1369
John Kåre Alsaker94659272012-11-13 19:10:18 +01001370 weston_output_init(&output->base, &ec->base, x, y,
1371 connector->mmWidth, connector->mmHeight,
1372 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1373
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001374 if (gl_renderer_output_create(&output->base, output->surface) < 0)
John Kåre Alsaker94659272012-11-13 19:10:18 +01001375 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001376
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001377 output->cursor_bo[0] =
1378 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1379 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1380 output->cursor_bo[1] =
1381 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1382 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001383 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1384 weston_log("cursor buffers unavailable, using gl cursors\n");
1385 ec->cursors_are_broken = 1;
1386 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001387
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001388 output->backlight = backlight_init(drm_device,
1389 connector->connector_type);
1390 if (output->backlight) {
1391 output->base.set_backlight = drm_set_backlight;
1392 output->base.backlight_current = drm_get_backlight(output);
1393 }
1394
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001395 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1396
Alex Wubd3354b2012-04-17 17:20:49 +08001397 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001398 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001399 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001400 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001401 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001402 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001403
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001404 weston_plane_init(&output->cursor_plane, 0, 0);
1405 weston_plane_init(&output->fb_plane, 0, 0);
1406
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001407 weston_log("Output %s, (connector %d, crtc %d)\n",
1408 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001409 wl_list_for_each(m, &output->base.mode_list, link)
1410 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1411 m->width, m->height, m->refresh / 1000.0,
1412 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1413 ", preferred" : "",
1414 m->flags & WL_OUTPUT_MODE_CURRENT ?
1415 ", current" : "",
1416 connector->count_modes == 0 ?
1417 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001418
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001419 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001420
John Kåre Alsaker94659272012-11-13 19:10:18 +01001421err_output:
1422 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001423 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001424err_free:
1425 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1426 base.link) {
1427 wl_list_remove(&drm_mode->base.link);
1428 free(drm_mode);
1429 }
1430
1431 drmModeFreeCrtc(output->original_crtc);
1432 ec->crtc_allocator &= ~(1 << output->crtc_id);
1433 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001434 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001435 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001436
David Herrmann0f0d54e2011-12-08 17:05:45 +01001437 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001438}
1439
Jesse Barnes58ef3792012-02-23 09:45:49 -05001440static void
1441create_sprites(struct drm_compositor *ec)
1442{
1443 struct drm_sprite *sprite;
1444 drmModePlaneRes *plane_res;
1445 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001446 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001447
1448 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1449 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001450 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001451 strerror(errno));
1452 return;
1453 }
1454
1455 for (i = 0; i < plane_res->count_planes; i++) {
1456 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1457 if (!plane)
1458 continue;
1459
1460 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1461 plane->count_formats));
1462 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001463 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001464 __func__);
1465 free(plane);
1466 continue;
1467 }
1468
1469 memset(sprite, 0, sizeof *sprite);
1470
1471 sprite->possible_crtcs = plane->possible_crtcs;
1472 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001473 sprite->current = NULL;
1474 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001475 sprite->compositor = ec;
1476 sprite->count_formats = plane->count_formats;
1477 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001478 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001479 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001480 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001481
1482 wl_list_insert(&ec->sprite_list, &sprite->link);
1483 }
1484
1485 free(plane_res->planes);
1486 free(plane_res);
1487}
1488
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001489static void
1490destroy_sprites(struct drm_compositor *compositor)
1491{
1492 struct drm_sprite *sprite, *next;
1493 struct drm_output *output;
1494
1495 output = container_of(compositor->base.output_list.next,
1496 struct drm_output, base.link);
1497
1498 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1499 drmModeSetPlane(compositor->drm.fd,
1500 sprite->plane_id,
1501 output->crtc_id, 0, 0,
1502 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001503 if (sprite->current)
1504 gbm_bo_destroy(sprite->current->bo);
1505 if (sprite->next)
1506 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001507 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001508 free(sprite);
1509 }
1510}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001511
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001512static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001513create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001514 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001515{
1516 drmModeConnector *connector;
1517 drmModeRes *resources;
1518 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001519 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001520
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001521 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001522 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001523 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001524 return -1;
1525 }
1526
Jesse Barnes58ef3792012-02-23 09:45:49 -05001527 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001528 if (!ec->crtcs) {
1529 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001530 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001531 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001532
Rob Clark4339add2012-08-09 14:18:28 -05001533 ec->min_width = resources->min_width;
1534 ec->max_width = resources->max_width;
1535 ec->min_height = resources->min_height;
1536 ec->max_height = resources->max_height;
1537
Jesse Barnes58ef3792012-02-23 09:45:49 -05001538 ec->num_crtcs = resources->count_crtcs;
1539 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1540
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001541 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001542 connector = drmModeGetConnector(ec->drm.fd,
1543 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001544 if (connector == NULL)
1545 continue;
1546
1547 if (connector->connection == DRM_MODE_CONNECTED &&
1548 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001549 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001550 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001551 connector, x, y,
1552 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001553 drmModeFreeConnector(connector);
1554 continue;
1555 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001556
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001557 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001558 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001559 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001560 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001561
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001562 drmModeFreeConnector(connector);
1563 }
1564
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001565 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001566 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001567 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001568 return -1;
1569 }
1570
1571 drmModeFreeResources(resources);
1572
1573 return 0;
1574}
1575
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001576static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001577update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001578{
1579 drmModeConnector *connector;
1580 drmModeRes *resources;
1581 struct drm_output *output, *next;
1582 int x = 0, y = 0;
1583 int x_offset = 0, y_offset = 0;
1584 uint32_t connected = 0, disconnects = 0;
1585 int i;
1586
1587 resources = drmModeGetResources(ec->drm.fd);
1588 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001589 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001590 return;
1591 }
1592
1593 /* collect new connects */
1594 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001595 int connector_id = resources->connectors[i];
1596
1597 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001598 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001599 continue;
1600
David Herrmann7551cff2011-12-08 17:05:43 +01001601 if (connector->connection != DRM_MODE_CONNECTED) {
1602 drmModeFreeConnector(connector);
1603 continue;
1604 }
1605
Benjamin Franzke117483d2011-08-30 11:38:26 +02001606 connected |= (1 << connector_id);
1607
1608 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001609 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001610 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001611 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001612
1613 /* XXX: not yet needed, we die with 0 outputs */
1614 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001615 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001616 else
1617 x = 0;
1618 y = 0;
1619 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001620 connector, x, y,
1621 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001622 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001623
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001624 }
1625 drmModeFreeConnector(connector);
1626 }
1627 drmModeFreeResources(resources);
1628
1629 disconnects = ec->connector_allocator & ~connected;
1630 if (disconnects) {
1631 wl_list_for_each_safe(output, next, &ec->base.output_list,
1632 base.link) {
1633 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001634 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001635 output->base.x - x_offset,
1636 output->base.y - y_offset);
1637 }
1638
1639 if (disconnects & (1 << output->connector_id)) {
1640 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001641 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001642 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001643 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001644 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001645 }
1646 }
1647 }
1648
1649 /* FIXME: handle zero outputs, without terminating */
1650 if (ec->connector_allocator == 0)
1651 wl_display_terminate(ec->base.wl_display);
1652}
1653
1654static int
David Herrmannd7488c22012-03-11 20:05:21 +01001655udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001656{
David Herrmannd7488c22012-03-11 20:05:21 +01001657 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001658 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001659
1660 sysnum = udev_device_get_sysnum(device);
1661 if (!sysnum || atoi(sysnum) != ec->drm.id)
1662 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001663
David Herrmann6ac52db2012-03-11 20:05:22 +01001664 val = udev_device_get_property_value(device, "HOTPLUG");
1665 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001666 return 0;
1667
David Herrmann6ac52db2012-03-11 20:05:22 +01001668 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001669}
1670
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001671static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001672udev_drm_event(int fd, uint32_t mask, void *data)
1673{
1674 struct drm_compositor *ec = data;
1675 struct udev_device *event;
1676
1677 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001678
David Herrmannd7488c22012-03-11 20:05:21 +01001679 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001680 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001681
1682 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001683
1684 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001685}
1686
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001687static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001688drm_restore(struct weston_compositor *ec)
1689{
1690 struct drm_compositor *d = (struct drm_compositor *) ec;
1691
1692 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1693 weston_log("failed to drop master: %m\n");
1694 tty_reset(d->tty);
1695}
1696
Pekka Paalanen33156972012-08-03 13:30:30 -04001697static const char default_seat[] = "seat0";
1698
1699static void
1700device_added(struct udev_device *udev_device, struct drm_seat *master)
1701{
1702 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001703 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001704 const char *devnode;
1705 const char *device_seat;
1706 int fd;
1707
1708 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1709 if (!device_seat)
1710 device_seat = default_seat;
1711
1712 if (strcmp(device_seat, master->seat_id))
1713 return;
1714
1715 c = master->base.compositor;
1716 devnode = udev_device_get_devnode(udev_device);
1717
1718 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001719 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001720 * read. mtdev_get() also expects this. */
1721 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1722 if (fd < 0) {
1723 weston_log("opening input device '%s' failed.\n", devnode);
1724 return;
1725 }
1726
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001727 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001728 if (!device) {
1729 close(fd);
1730 weston_log("not using input device '%s'.\n", devnode);
1731 return;
1732 }
1733
1734 wl_list_insert(master->devices_list.prev, &device->link);
1735}
1736
1737static void
1738evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1739{
1740 struct drm_seat *seat = (struct drm_seat *) seat_base;
1741 struct udev_enumerate *e;
1742 struct udev_list_entry *entry;
1743 struct udev_device *device;
1744 const char *path, *sysname;
1745
1746 e = udev_enumerate_new(udev);
1747 udev_enumerate_add_match_subsystem(e, "input");
1748 udev_enumerate_scan_devices(e);
1749 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1750 path = udev_list_entry_get_name(entry);
1751 device = udev_device_new_from_syspath(udev, path);
1752
1753 sysname = udev_device_get_sysname(device);
1754 if (strncmp("event", sysname, 5) != 0) {
1755 udev_device_unref(device);
1756 continue;
1757 }
1758
1759 device_added(device, seat);
1760
1761 udev_device_unref(device);
1762 }
1763 udev_enumerate_unref(e);
1764
1765 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1766
1767 if (wl_list_empty(&seat->devices_list)) {
1768 weston_log(
1769 "warning: no input devices on entering Weston. "
1770 "Possible causes:\n"
1771 "\t- no permissions to read /dev/input/event*\n"
1772 "\t- seats misconfigured "
1773 "(Weston backend option 'seat', "
1774 "udev device property ID_SEAT)\n");
1775 }
1776}
1777
1778static int
1779evdev_udev_handler(int fd, uint32_t mask, void *data)
1780{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001781 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001782 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001783 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001784 const char *action;
1785 const char *devnode;
1786
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001787 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001788 if (!udev_device)
1789 return 1;
1790
1791 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001792 if (!action)
1793 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001794
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001795 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1796 goto out;
1797
1798 if (!strcmp(action, "add")) {
1799 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001800 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001801 else if (!strcmp(action, "remove")) {
1802 devnode = udev_device_get_devnode(udev_device);
1803 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1804 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001805 weston_log("input device %s, %s removed\n",
1806 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001807 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001808 break;
1809 }
1810 }
1811
1812out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001813 udev_device_unref(udev_device);
1814
1815 return 0;
1816}
1817
1818static int
1819evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1820{
1821 struct drm_seat *master = (struct drm_seat *) seat_base;
1822 struct wl_event_loop *loop;
1823 struct weston_compositor *c = master->base.compositor;
1824 int fd;
1825
1826 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1827 if (!master->udev_monitor) {
1828 weston_log("udev: failed to create the udev monitor\n");
1829 return 0;
1830 }
1831
1832 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1833 "input", NULL);
1834
1835 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1836 weston_log("udev: failed to bind the udev monitor\n");
1837 udev_monitor_unref(master->udev_monitor);
1838 return 0;
1839 }
1840
1841 loop = wl_display_get_event_loop(c->wl_display);
1842 fd = udev_monitor_get_fd(master->udev_monitor);
1843 master->udev_monitor_source =
1844 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1845 evdev_udev_handler, master);
1846 if (!master->udev_monitor_source) {
1847 udev_monitor_unref(master->udev_monitor);
1848 return 0;
1849 }
1850
1851 return 1;
1852}
1853
1854static void
1855evdev_disable_udev_monitor(struct weston_seat *seat_base)
1856{
1857 struct drm_seat *seat = (struct drm_seat *) seat_base;
1858
1859 if (!seat->udev_monitor)
1860 return;
1861
1862 udev_monitor_unref(seat->udev_monitor);
1863 seat->udev_monitor = NULL;
1864 wl_event_source_remove(seat->udev_monitor_source);
1865 seat->udev_monitor_source = NULL;
1866}
1867
1868static void
1869drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1870{
1871 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001872 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001873
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001874 wl_list_for_each(device, &seat->devices_list, link)
1875 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001876}
1877
1878static void
1879evdev_input_create(struct weston_compositor *c, struct udev *udev,
1880 const char *seat_id)
1881{
1882 struct drm_seat *seat;
1883
1884 seat = malloc(sizeof *seat);
1885 if (seat == NULL)
1886 return;
1887
1888 memset(seat, 0, sizeof *seat);
1889 weston_seat_init(&seat->base, c);
1890 seat->base.led_update = drm_led_update;
1891
1892 wl_list_init(&seat->devices_list);
1893 seat->seat_id = strdup(seat_id);
1894 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1895 free(seat->seat_id);
1896 free(seat);
1897 return;
1898 }
1899
1900 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001901}
1902
1903static void
1904evdev_remove_devices(struct weston_seat *seat_base)
1905{
1906 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001907 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001908
1909 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001910 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001911
Pekka Paalanend8583512012-08-03 14:39:11 +03001912 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001913 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001914}
1915
1916static void
1917evdev_input_destroy(struct weston_seat *seat_base)
1918{
1919 struct drm_seat *seat = (struct drm_seat *) seat_base;
1920
1921 evdev_remove_devices(seat_base);
1922 evdev_disable_udev_monitor(&seat->base);
1923
1924 weston_seat_release(seat_base);
1925 free(seat->seat_id);
1926 free(seat);
1927}
1928
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001929static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001930drm_free_configured_output(struct drm_configured_output *output)
1931{
1932 free(output->name);
1933 free(output->mode);
1934 free(output);
1935}
1936
1937static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001938drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001939{
1940 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001941 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001942 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001943
Daniel Stone37816df2012-05-16 18:45:18 +01001944 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1945 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001946 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001947 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001948
1949 wl_event_source_remove(d->udev_drm_source);
1950 wl_event_source_remove(d->drm_source);
1951
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001952 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001953
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001954 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001955
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001956 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001957 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001958 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001959 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001960 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001961
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001962 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001963}
1964
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001965static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001966drm_compositor_set_modes(struct drm_compositor *compositor)
1967{
1968 struct drm_output *output;
1969 struct drm_mode *drm_mode;
1970 int ret;
1971
1972 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1973 drm_mode = (struct drm_mode *) output->base.current;
1974 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001975 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001976 &output->connector_id, 1,
1977 &drm_mode->mode_info);
1978 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001979 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001980 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001981 drm_mode->base.width, drm_mode->base.height,
1982 output->base.x, output->base.y);
1983 }
1984 }
1985}
1986
1987static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001988vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001989{
1990 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001991 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001992 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001993 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001994
1995 switch (event) {
1996 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03001997 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001998 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001999 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002000 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002001 wl_display_terminate(compositor->wl_display);
2002 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002003 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002004 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002005 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002006 wl_list_for_each(seat, &compositor->seat_list, link) {
2007 evdev_add_devices(ec->udev, seat);
2008 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002009 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002010 break;
2011 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002012 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002013 wl_list_for_each(seat, &compositor->seat_list, link) {
2014 evdev_disable_udev_monitor(seat);
2015 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002016 }
2017
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002018 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002019 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002020 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002021
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002022 /* If we have a repaint scheduled (either from a
2023 * pending pageflip or the idle handler), make sure we
2024 * cancel that so we don't try to pageflip when we're
2025 * vt switched away. The SLEEPING state will prevent
2026 * further attemps at repainting. When we switch
2027 * back, we schedule a repaint, which will process
2028 * pending frame callbacks. */
2029
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002030 wl_list_for_each(output, &ec->base.output_list, base.link) {
2031 output->base.repaint_needed = 0;
2032 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002033 }
2034
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002035 output = container_of(ec->base.output_list.next,
2036 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002037
2038 wl_list_for_each(sprite, &ec->sprite_list, link)
2039 drmModeSetPlane(ec->drm.fd,
2040 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002041 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002042 0, 0, 0, 0, 0, 0, 0, 0);
2043
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002044 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002045 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002046
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002047 break;
2048 };
2049}
2050
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002051static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002052switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002053{
2054 struct drm_compositor *ec = data;
2055
Daniel Stone325fc2d2012-05-30 16:31:58 +01002056 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002057}
2058
David Herrmann0af066f2012-10-29 19:21:16 +01002059/*
2060 * Find primary GPU
2061 * Some systems may have multiple DRM devices attached to a single seat. This
2062 * function loops over all devices and tries to find a PCI device with the
2063 * boot_vga sysfs attribute set to 1.
2064 * If no such device is found, the first DRM device reported by udev is used.
2065 */
2066static struct udev_device*
2067find_primary_gpu(struct drm_compositor *ec, const char *seat)
2068{
2069 struct udev_enumerate *e;
2070 struct udev_list_entry *entry;
2071 const char *path, *device_seat, *id;
2072 struct udev_device *device, *drm_device, *pci;
2073
2074 e = udev_enumerate_new(ec->udev);
2075 udev_enumerate_add_match_subsystem(e, "drm");
2076 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2077
2078 udev_enumerate_scan_devices(e);
2079 drm_device = NULL;
2080 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2081 path = udev_list_entry_get_name(entry);
2082 device = udev_device_new_from_syspath(ec->udev, path);
2083 if (!device)
2084 continue;
2085 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2086 if (!device_seat)
2087 device_seat = default_seat;
2088 if (strcmp(device_seat, seat)) {
2089 udev_device_unref(device);
2090 continue;
2091 }
2092
2093 pci = udev_device_get_parent_with_subsystem_devtype(device,
2094 "pci", NULL);
2095 if (pci) {
2096 id = udev_device_get_sysattr_value(pci, "boot_vga");
2097 if (id && !strcmp(id, "1")) {
2098 if (drm_device)
2099 udev_device_unref(drm_device);
2100 drm_device = device;
2101 break;
2102 }
2103 }
2104
2105 if (!drm_device)
2106 drm_device = device;
2107 else
2108 udev_device_unref(device);
2109 }
2110
2111 udev_enumerate_unref(e);
2112 return drm_device;
2113}
2114
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002115static void
2116hide_sprites_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2117 void *data)
2118{
2119 struct drm_compositor *c = data;
2120
2121 c->sprites_hidden ^= 1;
2122}
2123
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002124static void
2125cursor_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
2126{
2127 struct drm_compositor *c = data;
2128
2129 c->cursors_are_broken ^= 1;
2130}
2131
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002132static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002133drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002134 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002135 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002136{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002137 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002138 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002139 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002140 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002141 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002142 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002143
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002144 weston_log("initializing drm backend\n");
2145
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002146 ec = malloc(sizeof *ec);
2147 if (ec == NULL)
2148 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002149 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002150
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002151 /* KMS support for sprites is not complete yet, so disable the
2152 * functionality for now. */
2153 ec->sprites_are_broken = 1;
2154
Daniel Stone725c2c32012-06-22 14:04:36 +01002155 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002156 config_file) < 0) {
2157 weston_log("weston_compositor_init failed\n");
2158 goto err_base;
2159 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002160
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002161 ec->udev = udev_new();
2162 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002163 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002164 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002165 }
2166
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002167 ec->base.wl_display = display;
2168 ec->tty = tty_create(&ec->base, vt_func, tty);
2169 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002170 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002171 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002172 }
2173
David Herrmann0af066f2012-10-29 19:21:16 +01002174 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002175 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002176 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002177 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002178 }
David Herrmann0af066f2012-10-29 19:21:16 +01002179 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002180
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002181 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002182 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002183 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002184 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002185
2186 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002187 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002188
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002189 ec->base.focus = 1;
2190
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002191 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002192
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002193 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002194 weston_compositor_add_key_binding(&ec->base, key,
2195 MODIFIER_CTRL | MODIFIER_ALT,
2196 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002197
Jesse Barnes58ef3792012-02-23 09:45:49 -05002198 wl_list_init(&ec->sprite_list);
2199 create_sprites(ec);
2200
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002201 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002202 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002203 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002204 }
2205
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002206 path = NULL;
2207
Tiago Vignattice03ec32011-12-19 01:14:03 +02002208 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002209
2210 loop = wl_display_get_event_loop(ec->base.wl_display);
2211 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002212 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002213 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002214
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002215 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2216 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002217 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002218 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002219 }
2220 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2221 "drm", NULL);
2222 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002223 wl_event_loop_add_fd(loop,
2224 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002225 WL_EVENT_READABLE, udev_drm_event, ec);
2226
2227 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002228 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002229 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002230 }
2231
Daniel Stonea96b93c2012-06-22 14:04:37 +01002232 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002233
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002234 weston_compositor_add_debug_binding(&ec->base, KEY_O,
2235 hide_sprites_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002236 weston_compositor_add_debug_binding(&ec->base, KEY_C,
2237 cursor_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002238
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002239 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002240
2241err_udev_monitor:
2242 wl_event_source_remove(ec->udev_drm_source);
2243 udev_monitor_unref(ec->udev_monitor);
2244err_drm_source:
2245 wl_event_source_remove(ec->drm_source);
2246 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2247 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002248err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002249 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002250 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002251 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002252err_udev_dev:
2253 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002254err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002255 tty_destroy(ec->tty);
2256err_udev:
2257 udev_unref(ec->udev);
2258err_compositor:
2259 weston_compositor_shutdown(&ec->base);
2260err_base:
2261 free(ec);
2262 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002263}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002264
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002265static int
2266set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2267{
2268 mode->flags = 0;
2269
2270 if (strcmp(hsync, "+hsync") == 0)
2271 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2272 else if (strcmp(hsync, "-hsync") == 0)
2273 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2274 else
2275 return -1;
2276
2277 if (strcmp(vsync, "+vsync") == 0)
2278 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2279 else if (strcmp(vsync, "-vsync") == 0)
2280 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2281 else
2282 return -1;
2283
2284 return 0;
2285}
2286
2287static int
2288check_for_modeline(struct drm_configured_output *output)
2289{
2290 drmModeModeInfo mode;
2291 char hsync[16];
2292 char vsync[16];
2293 char mode_name[16];
2294 float fclock;
2295
2296 mode.type = DRM_MODE_TYPE_USERDEF;
2297 mode.hskew = 0;
2298 mode.vscan = 0;
2299 mode.vrefresh = 0;
2300
2301 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2302 &fclock, &mode.hdisplay,
2303 &mode.hsync_start,
2304 &mode.hsync_end, &mode.htotal,
2305 &mode.vdisplay,
2306 &mode.vsync_start,
2307 &mode.vsync_end, &mode.vtotal,
2308 hsync, vsync) == 11) {
2309 if (set_sync_flags(&mode, hsync, vsync))
2310 return -1;
2311
2312 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2313 strcpy(mode.name, mode_name);
2314
2315 mode.clock = fclock * 1000;
2316 } else
2317 return -1;
2318
2319 output->crtc_mode = mode;
2320
2321 return 0;
2322}
2323
Scott Moreau8ab5d452012-07-30 19:51:08 -06002324static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002325drm_output_set_transform(struct drm_configured_output *output)
2326{
2327 if (!output_transform) {
2328 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2329 return;
2330 }
2331
2332 if (!strcmp(output_transform, "normal"))
2333 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2334 else if (!strcmp(output_transform, "90"))
2335 output->transform = WL_OUTPUT_TRANSFORM_90;
2336 else if (!strcmp(output_transform, "180"))
2337 output->transform = WL_OUTPUT_TRANSFORM_180;
2338 else if (!strcmp(output_transform, "270"))
2339 output->transform = WL_OUTPUT_TRANSFORM_270;
2340 else if (!strcmp(output_transform, "flipped"))
2341 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2342 else if (!strcmp(output_transform, "flipped-90"))
2343 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2344 else if (!strcmp(output_transform, "flipped-180"))
2345 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2346 else if (!strcmp(output_transform, "flipped-270"))
2347 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2348 else {
2349 weston_log("Invalid transform \"%s\" for output %s\n",
2350 output_transform, output_name);
2351 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2352 }
2353
2354 free(output_transform);
2355 output_transform = NULL;
2356}
2357
2358static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002359output_section_done(void *data)
2360{
2361 struct drm_configured_output *output;
2362
2363 output = malloc(sizeof *output);
2364
Scott Moreau1bad5db2012-08-18 01:04:05 -06002365 if (!output || !output_name || (output_name[0] == 'X') ||
2366 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002367 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002368 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002369 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002370 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002371 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002372 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002373 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002374 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002375 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002376
2377 output->config = OUTPUT_CONFIG_INVALID;
2378 output->name = output_name;
2379 output->mode = output_mode;
2380
Scott Moreau1bad5db2012-08-18 01:04:05 -06002381 if (output_mode) {
2382 if (strcmp(output_mode, "off") == 0)
2383 output->config = OUTPUT_CONFIG_OFF;
2384 else if (strcmp(output_mode, "preferred") == 0)
2385 output->config = OUTPUT_CONFIG_PREFERRED;
2386 else if (strcmp(output_mode, "current") == 0)
2387 output->config = OUTPUT_CONFIG_CURRENT;
2388 else if (sscanf(output_mode, "%dx%d",
2389 &output->width, &output->height) == 2)
2390 output->config = OUTPUT_CONFIG_MODE;
2391 else if (check_for_modeline(output) == 0)
2392 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002393
Scott Moreau1bad5db2012-08-18 01:04:05 -06002394 if (output->config == OUTPUT_CONFIG_INVALID)
2395 weston_log("Invalid mode \"%s\" for output %s\n",
2396 output_mode, output_name);
2397 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002398 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002399
2400 drm_output_set_transform(output);
2401
2402 wl_list_insert(&configured_output_list, &output->link);
2403
2404 if (output_transform)
2405 free(output_transform);
2406 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002407}
2408
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002409WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002410backend_init(struct wl_display *display, int argc, char *argv[],
2411 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002412{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002413 int connector = 0, tty = 0;
2414 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002415
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002416 const struct weston_option drm_options[] = {
2417 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2418 { WESTON_OPTION_STRING, "seat", 0, &seat },
2419 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002420 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002421 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002422
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002423 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002424
Scott Moreau8ab5d452012-07-30 19:51:08 -06002425 wl_list_init(&configured_output_list);
2426
2427 const struct config_key drm_config_keys[] = {
2428 { "name", CONFIG_KEY_STRING, &output_name },
2429 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002430 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002431 };
2432
2433 const struct config_section config_section[] = {
2434 { "output", drm_config_keys,
2435 ARRAY_LENGTH(drm_config_keys), output_section_done },
2436 };
2437
2438 parse_config_file(config_file, config_section,
2439 ARRAY_LENGTH(config_section), NULL);
2440
Daniel Stonec1be8e52012-06-01 11:14:02 -04002441 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2442 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002443}