blob: 6eac8e7f9997e915062554264a74914b80bc81f2 [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
Rob Clark702ffae2012-08-09 14:18:27 -0500575 if (wl_buffer_is_shm(es->buffer))
576 return NULL;
577
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400579 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500580
Jesse Barnes58ef3792012-02-23 09:45:49 -0500581 wl_list_for_each(s, &c->sprite_list, link) {
582 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
583 continue;
584
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200585 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 found = 1;
587 break;
588 }
589 }
590
591 /* No sprites available */
592 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400593 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500594
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400595 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
596 es->buffer, GBM_BO_USE_SCANOUT);
597 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400598 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400599
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200602 if (!drm_surface_format_supported(s, format)) {
603 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400604 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 }
606
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200607 s->next = drm_fb_get_from_bo(bo, c);
608 if (!s->next) {
609 gbm_bo_destroy(bo);
610 return NULL;
611 }
612
613 drm_fb_set_buffer(s->next, es->buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500614
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400615 box = pixman_region32_extents(&es->transform.boundingbox);
616 s->plane.x = box->x1;
617 s->plane.y = box->y1;
618
Jesse Barnes58ef3792012-02-23 09:45:49 -0500619 /*
620 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200621 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 * for us already).
623 */
624 pixman_region32_init(&dest_rect);
625 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
626 &output_base->region);
627 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
628 box = pixman_region32_extents(&dest_rect);
629 s->dest_x = box->x1;
630 s->dest_y = box->y1;
631 s->dest_w = box->x2 - box->x1;
632 s->dest_h = box->y2 - box->y1;
633 pixman_region32_fini(&dest_rect);
634
635 pixman_region32_init(&src_rect);
636 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
637 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400639
640 weston_surface_from_global_fixed(es,
641 wl_fixed_from_int(box->x1),
642 wl_fixed_from_int(box->y1),
643 &sx1, &sy1);
644 weston_surface_from_global_fixed(es,
645 wl_fixed_from_int(box->x2),
646 wl_fixed_from_int(box->y2),
647 &sx2, &sy2);
648
649 if (sx1 < 0)
650 sx1 = 0;
651 if (sy1 < 0)
652 sy1 = 0;
653 if (sx2 > wl_fixed_from_int(es->geometry.width))
654 sx2 = wl_fixed_from_int(es->geometry.width);
655 if (sy2 > wl_fixed_from_int(es->geometry.height))
656 sy2 = wl_fixed_from_int(es->geometry.height);
657
658 s->src_x = sx1 << 8;
659 s->src_y = sy1 << 8;
660 s->src_w = (sx2 - sx1) << 8;
661 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500662 pixman_region32_fini(&src_rect);
663
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400664 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665}
666
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400667static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400668drm_output_prepare_cursor_surface(struct weston_output *output_base,
669 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500670{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400671 struct drm_compositor *c =
672 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400673 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400674
675 if (output->cursor_surface)
676 return NULL;
677 if (es->output_mask != (1u << output_base->id))
678 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500679 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400680 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400681 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
682 es->geometry.width > 64 || es->geometry.height > 64)
683 return NULL;
684
685 output->cursor_surface = es;
686
687 return &output->cursor_plane;
688}
689
690static void
691drm_output_set_cursor(struct drm_output *output)
692{
693 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400694 struct drm_compositor *c =
695 (struct drm_compositor *) output->base.compositor;
696 EGLint handle, stride;
697 struct gbm_bo *bo;
698 uint32_t buf[64 * 64];
699 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400700 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500701
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400702 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400703 if (es == NULL) {
704 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
705 return;
706 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500707
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400708 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
709 pixman_region32_fini(&output->cursor_plane.damage);
710 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400711 output->current_cursor ^= 1;
712 bo = output->cursor_bo[output->current_cursor];
713 memset(buf, 0, sizeof buf);
714 stride = wl_shm_buffer_get_stride(es->buffer);
715 s = wl_shm_buffer_get_data(es->buffer);
716 for (i = 0; i < es->geometry.height; i++)
717 memcpy(buf + i * 64, s + i * stride,
718 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500719
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400720 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300721 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400722
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400723 handle = gbm_bo_get_handle(bo).s32;
724 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500725 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300726 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500727 c->cursors_are_broken = 1;
728 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400729 }
730
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400731 x = es->geometry.x - output->base.x;
732 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400733 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500734 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400735 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500736 c->cursors_are_broken = 1;
737 }
738
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400739 output->cursor_plane.x = x;
740 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400741 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500742}
743
Jesse Barnes58ef3792012-02-23 09:45:49 -0500744static void
745drm_assign_planes(struct weston_output *output)
746{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400747 struct drm_compositor *c =
748 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200749 struct drm_output *drm_output = (struct drm_output *) output;
750 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400751 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500752 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400753 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500754
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200755 /* Reset the opaque region of the planes */
756 pixman_region32_fini(&drm_output->cursor_plane.opaque);
757 pixman_region32_init(&drm_output->cursor_plane.opaque);
758 pixman_region32_fini(&drm_output->fb_plane.opaque);
759 pixman_region32_init(&drm_output->fb_plane.opaque);
760
761 wl_list_for_each (s, &c->sprite_list, link) {
762 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
763 continue;
764
765 pixman_region32_fini(&s->plane.opaque);
766 pixman_region32_init(&s->plane.opaque);
767 }
768
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 /*
770 * Find a surface for each sprite in the output using some heuristics:
771 * 1) size
772 * 2) frequency of update
773 * 3) opacity (though some hw might support alpha blending)
774 * 4) clipping (this can be fixed with color keys)
775 *
776 * The idea is to save on blitting since this should save power.
777 * If we can get a large video surface on the sprite for example,
778 * the main display surface may not need to update at all, and
779 * the client buffer can be used directly for the sprite surface
780 * as we do for flipping full screen surfaces.
781 */
782 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400783 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400784 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785 pixman_region32_init(&surface_overlap);
786 pixman_region32_intersect(&surface_overlap, &overlap,
787 &es->transform.boundingbox);
788
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400789 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400790 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400791 next_plane = primary;
792 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400793 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 if (next_plane == NULL)
795 next_plane = drm_output_prepare_scanout_surface(output, es);
796 if (next_plane == NULL)
797 next_plane = drm_output_prepare_overlay_surface(output, es);
798 if (next_plane == NULL)
799 next_plane = primary;
800 weston_surface_move_to_plane(es, next_plane);
801 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802 pixman_region32_union(&overlap, &overlap,
803 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400804
Jesse Barnes58ef3792012-02-23 09:45:49 -0500805 pixman_region32_fini(&surface_overlap);
806 }
807 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808}
809
Matt Roper361d2ad2011-08-29 13:52:23 -0700810static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500811drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700812{
813 struct drm_output *output = (struct drm_output *) output_base;
814 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200815 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700816 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700817
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200818 if (output->backlight)
819 backlight_destroy(output->backlight);
820
Matt Roper361d2ad2011-08-29 13:52:23 -0700821 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400822 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700823
824 /* Restore original CRTC state */
825 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200826 origcrtc->x, origcrtc->y,
827 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700828 drmModeFreeCrtc(origcrtc);
829
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200830 c->crtc_allocator &= ~(1 << output->crtc_id);
831 c->connector_allocator &= ~(1 << output->connector_id);
832
John Kåre Alsaker94659272012-11-13 19:10:18 +0100833 gles2_renderer_output_destroy(output_base);
834
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400835 gbm_surface_destroy(output->surface);
836
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400837 weston_plane_release(&output->fb_plane);
838 weston_plane_release(&output->cursor_plane);
839
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500840 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200841 wl_list_remove(&output->base.link);
842
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400843 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700844 free(output);
845}
846
Alex Wub7b8bda2012-04-17 17:20:48 +0800847static struct drm_mode *
848choose_mode (struct drm_output *output, struct weston_mode *target_mode)
849{
850 struct drm_mode *tmp_mode = NULL, *mode;
851
852 if (output->base.current->width == target_mode->width &&
853 output->base.current->height == target_mode->height &&
854 (output->base.current->refresh == target_mode->refresh ||
855 target_mode->refresh == 0))
856 return (struct drm_mode *)output->base.current;
857
858 wl_list_for_each(mode, &output->base.mode_list, base.link) {
859 if (mode->mode_info.hdisplay == target_mode->width &&
860 mode->mode_info.vdisplay == target_mode->height) {
861 if (mode->mode_info.vrefresh == target_mode->refresh ||
862 target_mode->refresh == 0) {
863 return mode;
864 } else if (!tmp_mode)
865 tmp_mode = mode;
866 }
867 }
868
869 return tmp_mode;
870}
871
872static int
873drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
874{
875 struct drm_output *output;
876 struct drm_mode *drm_mode;
877 int ret;
878 struct drm_compositor *ec;
879 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800880
881 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200882 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800883 return -1;
884 }
885
886 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200887 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800888 return -1;
889 }
890
891 ec = (struct drm_compositor *)output_base->compositor;
892 output = (struct drm_output *)output_base;
893 drm_mode = choose_mode (output, mode);
894
895 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200896 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800897 return -1;
898 } else if (&drm_mode->base == output->base.current) {
899 return 0;
900 } else if (drm_mode->base.width == output->base.current->width &&
901 drm_mode->base.height == output->base.current->height) {
902 /* only change refresh value */
903 ret = drmModeSetCrtc(ec->drm.fd,
904 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300905 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800906 &output->connector_id, 1, &drm_mode->mode_info);
907
908 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200909 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800910 drm_mode->base.width,
911 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400912 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800913 ret = -1;
914 } else {
915 output->base.current->flags = 0;
916 output->base.current = &drm_mode->base;
917 drm_mode->base.flags =
918 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
919 ret = 0;
920 }
921
922 return ret;
923 }
924
925 drm_mode->base.flags =
926 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
927
928 surface = gbm_surface_create(ec->gbm,
929 drm_mode->base.width,
930 drm_mode->base.height,
931 GBM_FORMAT_XRGB8888,
932 GBM_BO_USE_SCANOUT |
933 GBM_BO_USE_RENDERING);
934 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200935 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800936 return -1;
937 }
938
John Kåre Alsaker94659272012-11-13 19:10:18 +0100939 gles2_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800940
John Kåre Alsaker94659272012-11-13 19:10:18 +0100941 if (!gles2_renderer_output_create(&output->base, surface)) {
942 weston_log("failed to create renderer output\n");
943 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800944 }
945
946 ret = drmModeSetCrtc(ec->drm.fd,
947 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300948 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800949 &output->connector_id, 1, &drm_mode->mode_info);
950 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200951 weston_log("failed to set mode\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +0100952 goto err_gles2;
Alex Wub7b8bda2012-04-17 17:20:48 +0800953 }
954
955 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300956 if (output->current) {
957 if (output->current->is_client_buffer)
958 gbm_bo_destroy(output->current->bo);
959 else
960 gbm_surface_release_buffer(output->surface,
961 output->current->bo);
962 }
963 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800964
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300965 if (output->next) {
966 if (output->next->is_client_buffer)
967 gbm_bo_destroy(output->next->bo);
968 else
969 gbm_surface_release_buffer(output->surface,
970 output->next->bo);
971 }
972 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800973
Alex Wub7b8bda2012-04-17 17:20:48 +0800974 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800975 output->surface = surface;
976
977 /*update output*/
978 output->base.current = &drm_mode->base;
979 output->base.dirty = 1;
980 weston_output_move(&output->base, output->base.x, output->base.y);
981 return 0;
982
John Kåre Alsaker94659272012-11-13 19:10:18 +0100983err_gles2:
984 gles2_renderer_output_destroy(&output->base);
985err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +0800986 gbm_surface_destroy(surface);
987 return -1;
988}
989
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400990static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400991on_drm_input(int fd, uint32_t mask, void *data)
992{
993 drmEventContext evctx;
994
995 memset(&evctx, 0, sizeof evctx);
996 evctx.version = DRM_EVENT_CONTEXT_VERSION;
997 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500998 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400999 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001000
1001 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001002}
1003
1004static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001005init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001006{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001007 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001008 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001009
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001010 sysnum = udev_device_get_sysnum(device);
1011 if (sysnum)
1012 ec->drm.id = atoi(sysnum);
1013 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001014 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001015 return -1;
1016 }
1017
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001018 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001019 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001020 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001021 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001022 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001023 udev_device_get_devnode(device));
1024 return -1;
1025 }
1026
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001027 weston_log("using %s\n", filename);
1028
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001029 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001030 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001031
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001032 if (gles2_renderer_create(&ec->base, ec->gbm, gles2_renderer_opaque_attribs,
1033 NULL) < 0) {
1034 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001035 return -1;
1036 }
1037
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001038 return 0;
1039}
1040
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001041static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001042drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1043{
1044 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001045 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001046
1047 mode = malloc(sizeof *mode);
1048 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001049 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001050
1051 mode->base.flags = 0;
1052 mode->base.width = info->hdisplay;
1053 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001054
1055 /* Calculate higher precision (mHz) refresh rate */
1056 refresh = (info->clock * 1000000LL / info->htotal +
1057 info->vtotal / 2) / info->vtotal;
1058
1059 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1060 refresh *= 2;
1061 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1062 refresh /= 2;
1063 if (info->vscan > 1)
1064 refresh /= info->vscan;
1065
1066 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001067 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001068
1069 if (info->type & DRM_MODE_TYPE_PREFERRED)
1070 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1071
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001072 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1073
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001074 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001075}
1076
1077static int
1078drm_subpixel_to_wayland(int drm_value)
1079{
1080 switch (drm_value) {
1081 default:
1082 case DRM_MODE_SUBPIXEL_UNKNOWN:
1083 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1084 case DRM_MODE_SUBPIXEL_NONE:
1085 return WL_OUTPUT_SUBPIXEL_NONE;
1086 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1087 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1088 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1089 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1090 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1091 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1092 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1093 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1094 }
1095}
1096
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001097/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001098static uint32_t
1099drm_get_backlight(struct drm_output *output)
1100{
1101 long brightness, max_brightness, norm;
1102
1103 brightness = backlight_get_brightness(output->backlight);
1104 max_brightness = backlight_get_max_brightness(output->backlight);
1105
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001106 /* convert it on a scale of 0 to 255 */
1107 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001108
1109 return (uint32_t) norm;
1110}
1111
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001112/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001113static void
1114drm_set_backlight(struct weston_output *output_base, uint32_t value)
1115{
1116 struct drm_output *output = (struct drm_output *) output_base;
1117 long max_brightness, new_brightness;
1118
1119 if (!output->backlight)
1120 return;
1121
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001122 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001123 return;
1124
1125 max_brightness = backlight_get_max_brightness(output->backlight);
1126
1127 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001128 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001129
1130 backlight_set_brightness(output->backlight, new_brightness);
1131}
1132
1133static drmModePropertyPtr
1134drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1135{
1136 drmModePropertyPtr props;
1137 int i;
1138
1139 for (i = 0; i < connector->count_props; i++) {
1140 props = drmModeGetProperty(fd, connector->props[i]);
1141 if (!props)
1142 continue;
1143
1144 if (!strcmp(props->name, name))
1145 return props;
1146
1147 drmModeFreeProperty(props);
1148 }
1149
1150 return NULL;
1151}
1152
1153static void
1154drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1155{
1156 struct drm_output *output = (struct drm_output *) output_base;
1157 struct weston_compositor *ec = output_base->compositor;
1158 struct drm_compositor *c = (struct drm_compositor *) ec;
1159 drmModeConnectorPtr connector;
1160 drmModePropertyPtr prop;
1161
1162 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1163 if (!connector)
1164 return;
1165
1166 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1167 if (!prop) {
1168 drmModeFreeConnector(connector);
1169 return;
1170 }
1171
1172 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1173 prop->prop_id, level);
1174 drmModeFreeProperty(prop);
1175 drmModeFreeConnector(connector);
1176}
1177
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001178static const char *connector_type_names[] = {
1179 "None",
1180 "VGA",
1181 "DVI",
1182 "DVI",
1183 "DVI",
1184 "Composite",
1185 "TV",
1186 "LVDS",
1187 "CTV",
1188 "DIN",
1189 "DP",
1190 "HDMI",
1191 "HDMI",
1192 "TV",
1193 "eDP",
1194};
1195
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001196static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001197find_crtc_for_connector(struct drm_compositor *ec,
1198 drmModeRes *resources, drmModeConnector *connector)
1199{
1200 drmModeEncoder *encoder;
1201 uint32_t possible_crtcs;
1202 int i, j;
1203
1204 for (j = 0; j < connector->count_encoders; j++) {
1205 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1206 if (encoder == NULL) {
1207 weston_log("Failed to get encoder.\n");
1208 return -1;
1209 }
1210 possible_crtcs = encoder->possible_crtcs;
1211 drmModeFreeEncoder(encoder);
1212
1213 for (i = 0; i < resources->count_crtcs; i++) {
1214 if (possible_crtcs & (1 << i) &&
1215 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1216 return i;
1217 }
1218 }
1219
1220 return -1;
1221}
1222
1223static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001224create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001225 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001226 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001227 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001228{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001229 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001230 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1231 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001232 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001233 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001234 drmModeModeInfo crtc_mode;
1235 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001236 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001237 char name[32];
1238 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001239
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001240 i = find_crtc_for_connector(ec, resources, connector);
1241 if (i < 0) {
1242 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001243 return -1;
1244 }
1245
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001246 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001247 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001248 return -1;
1249
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001250 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001251 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1252 output->base.make = "unknown";
1253 output->base.model = "unknown";
1254 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001255
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001256 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1257 type_name = connector_type_names[connector->connector_type];
1258 else
1259 type_name = "UNKNOWN";
1260 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1261 output->name = strdup(name);
1262
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001263 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001264 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001265 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001266 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001267 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001268
Matt Roper361d2ad2011-08-29 13:52:23 -07001269 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1270
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001271 /* Get the current mode on the crtc that's currently driving
1272 * this connector. */
1273 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001274 memset(&crtc_mode, 0, sizeof crtc_mode);
1275 if (encoder != NULL) {
1276 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1277 drmModeFreeEncoder(encoder);
1278 if (crtc == NULL)
1279 goto err_free;
1280 if (crtc->mode_valid)
1281 crtc_mode = crtc->mode;
1282 drmModeFreeCrtc(crtc);
1283 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001284
David Herrmann0f0d54e2011-12-08 17:05:45 +01001285 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001286 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1287 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001288 goto err_free;
1289 }
1290
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001291 preferred = NULL;
1292 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001293 configured = NULL;
1294
1295 wl_list_for_each(temp, &configured_output_list, link) {
1296 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001297 if (temp->mode)
1298 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001299 temp->name, temp->mode);
1300 o = temp;
1301 break;
1302 }
1303 }
1304
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001305 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001306 weston_log("Disabling output %s\n", o->name);
1307
1308 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1309 0, 0, 0, 0, 0, NULL);
1310 goto err_free;
1311 }
1312
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001313 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001314 if (o && o->config == OUTPUT_CONFIG_MODE &&
1315 o->width == drm_mode->base.width &&
1316 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001317 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001318 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001319 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001320 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001321 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001322 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001323
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001324 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001325 configured = drm_output_add_mode(output, &o->crtc_mode);
1326 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001327 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001328 current = configured;
1329 }
1330
Wang Quanxianacb805a2012-07-30 18:09:46 -04001331 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001332 current = drm_output_add_mode(output, &crtc_mode);
1333 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001334 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001335 }
1336
Scott Moreau8ab5d452012-07-30 19:51:08 -06001337 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1338 configured = current;
1339
Wang Quanxianacb805a2012-07-30 18:09:46 -04001340 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001341 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001342 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001343 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001344 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001345 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001346 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001347 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001348
1349 if (output->base.current == NULL) {
1350 weston_log("no available modes for %s\n", output->name);
1351 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001352 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001353
Wang Quanxianacb805a2012-07-30 18:09:46 -04001354 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1355
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001356 output->surface = gbm_surface_create(ec->gbm,
1357 output->base.current->width,
1358 output->base.current->height,
1359 GBM_FORMAT_XRGB8888,
1360 GBM_BO_USE_SCANOUT |
1361 GBM_BO_USE_RENDERING);
1362 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001363 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001364 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001365 }
1366
John Kåre Alsaker94659272012-11-13 19:10:18 +01001367 weston_output_init(&output->base, &ec->base, x, y,
1368 connector->mmWidth, connector->mmHeight,
1369 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1370
1371 if (gles2_renderer_output_create(&output->base, output->surface) < 0)
1372 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001373
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001374 output->cursor_bo[0] =
1375 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1376 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1377 output->cursor_bo[1] =
1378 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1379 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001380 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1381 weston_log("cursor buffers unavailable, using gl cursors\n");
1382 ec->cursors_are_broken = 1;
1383 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001384
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001385 output->backlight = backlight_init(drm_device,
1386 connector->connector_type);
1387 if (output->backlight) {
1388 output->base.set_backlight = drm_set_backlight;
1389 output->base.backlight_current = drm_get_backlight(output);
1390 }
1391
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001392 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1393
Alex Wubd3354b2012-04-17 17:20:49 +08001394 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001395 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001396 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001397 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001398 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001399 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001400
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001401 weston_plane_init(&output->cursor_plane, 0, 0);
1402 weston_plane_init(&output->fb_plane, 0, 0);
1403
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001404 weston_log("Output %s, (connector %d, crtc %d)\n",
1405 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001406 wl_list_for_each(m, &output->base.mode_list, link)
1407 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1408 m->width, m->height, m->refresh / 1000.0,
1409 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1410 ", preferred" : "",
1411 m->flags & WL_OUTPUT_MODE_CURRENT ?
1412 ", current" : "",
1413 connector->count_modes == 0 ?
1414 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001415
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001416 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001417
John Kåre Alsaker94659272012-11-13 19:10:18 +01001418err_output:
1419 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001420 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001421err_free:
1422 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1423 base.link) {
1424 wl_list_remove(&drm_mode->base.link);
1425 free(drm_mode);
1426 }
1427
1428 drmModeFreeCrtc(output->original_crtc);
1429 ec->crtc_allocator &= ~(1 << output->crtc_id);
1430 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001431 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001432 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001433
David Herrmann0f0d54e2011-12-08 17:05:45 +01001434 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001435}
1436
Jesse Barnes58ef3792012-02-23 09:45:49 -05001437static void
1438create_sprites(struct drm_compositor *ec)
1439{
1440 struct drm_sprite *sprite;
1441 drmModePlaneRes *plane_res;
1442 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001443 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001444
1445 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1446 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001447 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001448 strerror(errno));
1449 return;
1450 }
1451
1452 for (i = 0; i < plane_res->count_planes; i++) {
1453 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1454 if (!plane)
1455 continue;
1456
1457 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1458 plane->count_formats));
1459 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001460 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001461 __func__);
1462 free(plane);
1463 continue;
1464 }
1465
1466 memset(sprite, 0, sizeof *sprite);
1467
1468 sprite->possible_crtcs = plane->possible_crtcs;
1469 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001470 sprite->current = NULL;
1471 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001472 sprite->compositor = ec;
1473 sprite->count_formats = plane->count_formats;
1474 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001475 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001476 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001477 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001478
1479 wl_list_insert(&ec->sprite_list, &sprite->link);
1480 }
1481
1482 free(plane_res->planes);
1483 free(plane_res);
1484}
1485
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001486static void
1487destroy_sprites(struct drm_compositor *compositor)
1488{
1489 struct drm_sprite *sprite, *next;
1490 struct drm_output *output;
1491
1492 output = container_of(compositor->base.output_list.next,
1493 struct drm_output, base.link);
1494
1495 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1496 drmModeSetPlane(compositor->drm.fd,
1497 sprite->plane_id,
1498 output->crtc_id, 0, 0,
1499 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001500 if (sprite->current)
1501 gbm_bo_destroy(sprite->current->bo);
1502 if (sprite->next)
1503 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001504 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001505 free(sprite);
1506 }
1507}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001508
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001509static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001510create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001511 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001512{
1513 drmModeConnector *connector;
1514 drmModeRes *resources;
1515 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001516 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001517
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001518 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001519 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001520 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001521 return -1;
1522 }
1523
Jesse Barnes58ef3792012-02-23 09:45:49 -05001524 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001525 if (!ec->crtcs) {
1526 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001527 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001528 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001529
Rob Clark4339add2012-08-09 14:18:28 -05001530 ec->min_width = resources->min_width;
1531 ec->max_width = resources->max_width;
1532 ec->min_height = resources->min_height;
1533 ec->max_height = resources->max_height;
1534
Jesse Barnes58ef3792012-02-23 09:45:49 -05001535 ec->num_crtcs = resources->count_crtcs;
1536 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1537
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001538 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001539 connector = drmModeGetConnector(ec->drm.fd,
1540 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001541 if (connector == NULL)
1542 continue;
1543
1544 if (connector->connection == DRM_MODE_CONNECTED &&
1545 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001546 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001547 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001548 connector, x, y,
1549 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001550 drmModeFreeConnector(connector);
1551 continue;
1552 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001553
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001554 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001555 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001556 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001557 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001558
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001559 drmModeFreeConnector(connector);
1560 }
1561
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001562 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001563 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001564 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001565 return -1;
1566 }
1567
1568 drmModeFreeResources(resources);
1569
1570 return 0;
1571}
1572
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001573static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001574update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001575{
1576 drmModeConnector *connector;
1577 drmModeRes *resources;
1578 struct drm_output *output, *next;
1579 int x = 0, y = 0;
1580 int x_offset = 0, y_offset = 0;
1581 uint32_t connected = 0, disconnects = 0;
1582 int i;
1583
1584 resources = drmModeGetResources(ec->drm.fd);
1585 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001586 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001587 return;
1588 }
1589
1590 /* collect new connects */
1591 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001592 int connector_id = resources->connectors[i];
1593
1594 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001595 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001596 continue;
1597
David Herrmann7551cff2011-12-08 17:05:43 +01001598 if (connector->connection != DRM_MODE_CONNECTED) {
1599 drmModeFreeConnector(connector);
1600 continue;
1601 }
1602
Benjamin Franzke117483d2011-08-30 11:38:26 +02001603 connected |= (1 << connector_id);
1604
1605 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001606 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001607 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001608 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001609
1610 /* XXX: not yet needed, we die with 0 outputs */
1611 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001612 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001613 else
1614 x = 0;
1615 y = 0;
1616 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001617 connector, x, y,
1618 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001619 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001620
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001621 }
1622 drmModeFreeConnector(connector);
1623 }
1624 drmModeFreeResources(resources);
1625
1626 disconnects = ec->connector_allocator & ~connected;
1627 if (disconnects) {
1628 wl_list_for_each_safe(output, next, &ec->base.output_list,
1629 base.link) {
1630 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001631 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001632 output->base.x - x_offset,
1633 output->base.y - y_offset);
1634 }
1635
1636 if (disconnects & (1 << output->connector_id)) {
1637 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001638 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001639 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001640 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001641 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001642 }
1643 }
1644 }
1645
1646 /* FIXME: handle zero outputs, without terminating */
1647 if (ec->connector_allocator == 0)
1648 wl_display_terminate(ec->base.wl_display);
1649}
1650
1651static int
David Herrmannd7488c22012-03-11 20:05:21 +01001652udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001653{
David Herrmannd7488c22012-03-11 20:05:21 +01001654 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001655 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001656
1657 sysnum = udev_device_get_sysnum(device);
1658 if (!sysnum || atoi(sysnum) != ec->drm.id)
1659 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001660
David Herrmann6ac52db2012-03-11 20:05:22 +01001661 val = udev_device_get_property_value(device, "HOTPLUG");
1662 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001663 return 0;
1664
David Herrmann6ac52db2012-03-11 20:05:22 +01001665 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001666}
1667
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001668static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001669udev_drm_event(int fd, uint32_t mask, void *data)
1670{
1671 struct drm_compositor *ec = data;
1672 struct udev_device *event;
1673
1674 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001675
David Herrmannd7488c22012-03-11 20:05:21 +01001676 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001677 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678
1679 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001680
1681 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001682}
1683
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001684static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001685drm_restore(struct weston_compositor *ec)
1686{
1687 struct drm_compositor *d = (struct drm_compositor *) ec;
1688
1689 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1690 weston_log("failed to drop master: %m\n");
1691 tty_reset(d->tty);
1692}
1693
Pekka Paalanen33156972012-08-03 13:30:30 -04001694static const char default_seat[] = "seat0";
1695
1696static void
1697device_added(struct udev_device *udev_device, struct drm_seat *master)
1698{
1699 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001700 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001701 const char *devnode;
1702 const char *device_seat;
1703 int fd;
1704
1705 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1706 if (!device_seat)
1707 device_seat = default_seat;
1708
1709 if (strcmp(device_seat, master->seat_id))
1710 return;
1711
1712 c = master->base.compositor;
1713 devnode = udev_device_get_devnode(udev_device);
1714
1715 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001716 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001717 * read. mtdev_get() also expects this. */
1718 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1719 if (fd < 0) {
1720 weston_log("opening input device '%s' failed.\n", devnode);
1721 return;
1722 }
1723
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001724 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001725 if (!device) {
1726 close(fd);
1727 weston_log("not using input device '%s'.\n", devnode);
1728 return;
1729 }
1730
1731 wl_list_insert(master->devices_list.prev, &device->link);
1732}
1733
1734static void
1735evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1736{
1737 struct drm_seat *seat = (struct drm_seat *) seat_base;
1738 struct udev_enumerate *e;
1739 struct udev_list_entry *entry;
1740 struct udev_device *device;
1741 const char *path, *sysname;
1742
1743 e = udev_enumerate_new(udev);
1744 udev_enumerate_add_match_subsystem(e, "input");
1745 udev_enumerate_scan_devices(e);
1746 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1747 path = udev_list_entry_get_name(entry);
1748 device = udev_device_new_from_syspath(udev, path);
1749
1750 sysname = udev_device_get_sysname(device);
1751 if (strncmp("event", sysname, 5) != 0) {
1752 udev_device_unref(device);
1753 continue;
1754 }
1755
1756 device_added(device, seat);
1757
1758 udev_device_unref(device);
1759 }
1760 udev_enumerate_unref(e);
1761
1762 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1763
1764 if (wl_list_empty(&seat->devices_list)) {
1765 weston_log(
1766 "warning: no input devices on entering Weston. "
1767 "Possible causes:\n"
1768 "\t- no permissions to read /dev/input/event*\n"
1769 "\t- seats misconfigured "
1770 "(Weston backend option 'seat', "
1771 "udev device property ID_SEAT)\n");
1772 }
1773}
1774
1775static int
1776evdev_udev_handler(int fd, uint32_t mask, void *data)
1777{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001778 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001779 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001780 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001781 const char *action;
1782 const char *devnode;
1783
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001784 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001785 if (!udev_device)
1786 return 1;
1787
1788 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001789 if (!action)
1790 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001791
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001792 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1793 goto out;
1794
1795 if (!strcmp(action, "add")) {
1796 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001797 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001798 else if (!strcmp(action, "remove")) {
1799 devnode = udev_device_get_devnode(udev_device);
1800 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1801 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001802 weston_log("input device %s, %s removed\n",
1803 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001804 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001805 break;
1806 }
1807 }
1808
1809out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001810 udev_device_unref(udev_device);
1811
1812 return 0;
1813}
1814
1815static int
1816evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1817{
1818 struct drm_seat *master = (struct drm_seat *) seat_base;
1819 struct wl_event_loop *loop;
1820 struct weston_compositor *c = master->base.compositor;
1821 int fd;
1822
1823 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1824 if (!master->udev_monitor) {
1825 weston_log("udev: failed to create the udev monitor\n");
1826 return 0;
1827 }
1828
1829 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1830 "input", NULL);
1831
1832 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1833 weston_log("udev: failed to bind the udev monitor\n");
1834 udev_monitor_unref(master->udev_monitor);
1835 return 0;
1836 }
1837
1838 loop = wl_display_get_event_loop(c->wl_display);
1839 fd = udev_monitor_get_fd(master->udev_monitor);
1840 master->udev_monitor_source =
1841 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1842 evdev_udev_handler, master);
1843 if (!master->udev_monitor_source) {
1844 udev_monitor_unref(master->udev_monitor);
1845 return 0;
1846 }
1847
1848 return 1;
1849}
1850
1851static void
1852evdev_disable_udev_monitor(struct weston_seat *seat_base)
1853{
1854 struct drm_seat *seat = (struct drm_seat *) seat_base;
1855
1856 if (!seat->udev_monitor)
1857 return;
1858
1859 udev_monitor_unref(seat->udev_monitor);
1860 seat->udev_monitor = NULL;
1861 wl_event_source_remove(seat->udev_monitor_source);
1862 seat->udev_monitor_source = NULL;
1863}
1864
1865static void
1866drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1867{
1868 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001869 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001870
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001871 wl_list_for_each(device, &seat->devices_list, link)
1872 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001873}
1874
1875static void
1876evdev_input_create(struct weston_compositor *c, struct udev *udev,
1877 const char *seat_id)
1878{
1879 struct drm_seat *seat;
1880
1881 seat = malloc(sizeof *seat);
1882 if (seat == NULL)
1883 return;
1884
1885 memset(seat, 0, sizeof *seat);
1886 weston_seat_init(&seat->base, c);
1887 seat->base.led_update = drm_led_update;
1888
1889 wl_list_init(&seat->devices_list);
1890 seat->seat_id = strdup(seat_id);
1891 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1892 free(seat->seat_id);
1893 free(seat);
1894 return;
1895 }
1896
1897 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001898}
1899
1900static void
1901evdev_remove_devices(struct weston_seat *seat_base)
1902{
1903 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001904 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001905
1906 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001907 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001908
Pekka Paalanend8583512012-08-03 14:39:11 +03001909 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001910 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001911}
1912
1913static void
1914evdev_input_destroy(struct weston_seat *seat_base)
1915{
1916 struct drm_seat *seat = (struct drm_seat *) seat_base;
1917
1918 evdev_remove_devices(seat_base);
1919 evdev_disable_udev_monitor(&seat->base);
1920
1921 weston_seat_release(seat_base);
1922 free(seat->seat_id);
1923 free(seat);
1924}
1925
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001926static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001927drm_free_configured_output(struct drm_configured_output *output)
1928{
1929 free(output->name);
1930 free(output->mode);
1931 free(output);
1932}
1933
1934static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001935drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001936{
1937 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001938 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001939 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001940
Daniel Stone37816df2012-05-16 18:45:18 +01001941 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1942 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001943 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001944 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001945
1946 wl_event_source_remove(d->udev_drm_source);
1947 wl_event_source_remove(d->drm_source);
1948
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001949 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001950
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001951 gles2_renderer_destroy(ec);
1952
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001953 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001954 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001955 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001956 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001957 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001958
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001959 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001960}
1961
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001962static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001963drm_compositor_set_modes(struct drm_compositor *compositor)
1964{
1965 struct drm_output *output;
1966 struct drm_mode *drm_mode;
1967 int ret;
1968
1969 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1970 drm_mode = (struct drm_mode *) output->base.current;
1971 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001972 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001973 &output->connector_id, 1,
1974 &drm_mode->mode_info);
1975 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001976 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001977 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001978 drm_mode->base.width, drm_mode->base.height,
1979 output->base.x, output->base.y);
1980 }
1981 }
1982}
1983
1984static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001985vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001986{
1987 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001988 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001989 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001990 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001991
1992 switch (event) {
1993 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03001994 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001995 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001996 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001997 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001998 wl_display_terminate(compositor->wl_display);
1999 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002000 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002001 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002002 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002003 wl_list_for_each(seat, &compositor->seat_list, link) {
2004 evdev_add_devices(ec->udev, seat);
2005 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002006 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002007 break;
2008 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002009 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002010 wl_list_for_each(seat, &compositor->seat_list, link) {
2011 evdev_disable_udev_monitor(seat);
2012 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002013 }
2014
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002015 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002016 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002017 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002018
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002019 /* If we have a repaint scheduled (either from a
2020 * pending pageflip or the idle handler), make sure we
2021 * cancel that so we don't try to pageflip when we're
2022 * vt switched away. The SLEEPING state will prevent
2023 * further attemps at repainting. When we switch
2024 * back, we schedule a repaint, which will process
2025 * pending frame callbacks. */
2026
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002027 wl_list_for_each(output, &ec->base.output_list, base.link) {
2028 output->base.repaint_needed = 0;
2029 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002030 }
2031
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002032 output = container_of(ec->base.output_list.next,
2033 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002034
2035 wl_list_for_each(sprite, &ec->sprite_list, link)
2036 drmModeSetPlane(ec->drm.fd,
2037 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002038 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002039 0, 0, 0, 0, 0, 0, 0, 0);
2040
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002041 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002042 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002043
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002044 break;
2045 };
2046}
2047
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002048static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002049switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002050{
2051 struct drm_compositor *ec = data;
2052
Daniel Stone325fc2d2012-05-30 16:31:58 +01002053 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002054}
2055
David Herrmann0af066f2012-10-29 19:21:16 +01002056/*
2057 * Find primary GPU
2058 * Some systems may have multiple DRM devices attached to a single seat. This
2059 * function loops over all devices and tries to find a PCI device with the
2060 * boot_vga sysfs attribute set to 1.
2061 * If no such device is found, the first DRM device reported by udev is used.
2062 */
2063static struct udev_device*
2064find_primary_gpu(struct drm_compositor *ec, const char *seat)
2065{
2066 struct udev_enumerate *e;
2067 struct udev_list_entry *entry;
2068 const char *path, *device_seat, *id;
2069 struct udev_device *device, *drm_device, *pci;
2070
2071 e = udev_enumerate_new(ec->udev);
2072 udev_enumerate_add_match_subsystem(e, "drm");
2073 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2074
2075 udev_enumerate_scan_devices(e);
2076 drm_device = NULL;
2077 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2078 path = udev_list_entry_get_name(entry);
2079 device = udev_device_new_from_syspath(ec->udev, path);
2080 if (!device)
2081 continue;
2082 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2083 if (!device_seat)
2084 device_seat = default_seat;
2085 if (strcmp(device_seat, seat)) {
2086 udev_device_unref(device);
2087 continue;
2088 }
2089
2090 pci = udev_device_get_parent_with_subsystem_devtype(device,
2091 "pci", NULL);
2092 if (pci) {
2093 id = udev_device_get_sysattr_value(pci, "boot_vga");
2094 if (id && !strcmp(id, "1")) {
2095 if (drm_device)
2096 udev_device_unref(drm_device);
2097 drm_device = device;
2098 break;
2099 }
2100 }
2101
2102 if (!drm_device)
2103 drm_device = device;
2104 else
2105 udev_device_unref(device);
2106 }
2107
2108 udev_enumerate_unref(e);
2109 return drm_device;
2110}
2111
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002112static void
2113hide_sprites_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2114 void *data)
2115{
2116 struct drm_compositor *c = data;
2117
2118 c->sprites_hidden ^= 1;
2119}
2120
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002121static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002122drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002123 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002124 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002125{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002126 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002127 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002128 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002129 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002130 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002131 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002132
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002133 weston_log("initializing drm backend\n");
2134
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002135 ec = malloc(sizeof *ec);
2136 if (ec == NULL)
2137 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002138 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002139
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002140 /* KMS support for sprites is not complete yet, so disable the
2141 * functionality for now. */
2142 ec->sprites_are_broken = 1;
2143
Daniel Stone725c2c32012-06-22 14:04:36 +01002144 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002145 config_file) < 0) {
2146 weston_log("weston_compositor_init failed\n");
2147 goto err_base;
2148 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002149
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002150 ec->udev = udev_new();
2151 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002152 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002153 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002154 }
2155
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002156 ec->base.wl_display = display;
2157 ec->tty = tty_create(&ec->base, vt_func, tty);
2158 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002159 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002160 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002161 }
2162
David Herrmann0af066f2012-10-29 19:21:16 +01002163 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002164 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002165 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002166 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002167 }
David Herrmann0af066f2012-10-29 19:21:16 +01002168 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002169
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002170 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002171 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002172 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002173 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002174
2175 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002176 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002177
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002178 ec->base.focus = 1;
2179
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002180 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002181
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002182 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002183 weston_compositor_add_key_binding(&ec->base, key,
2184 MODIFIER_CTRL | MODIFIER_ALT,
2185 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002186
Jesse Barnes58ef3792012-02-23 09:45:49 -05002187 wl_list_init(&ec->sprite_list);
2188 create_sprites(ec);
2189
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002190 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002191 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002192 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002193 }
2194
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002195 path = NULL;
2196
Tiago Vignattice03ec32011-12-19 01:14:03 +02002197 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002198
2199 loop = wl_display_get_event_loop(ec->base.wl_display);
2200 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002201 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002202 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002203
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002204 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2205 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002206 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002207 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002208 }
2209 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2210 "drm", NULL);
2211 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002212 wl_event_loop_add_fd(loop,
2213 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002214 WL_EVENT_READABLE, udev_drm_event, ec);
2215
2216 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002217 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002218 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002219 }
2220
Daniel Stonea96b93c2012-06-22 14:04:37 +01002221 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002222
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002223 weston_compositor_add_debug_binding(&ec->base, KEY_O,
2224 hide_sprites_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002225
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002226 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002227
2228err_udev_monitor:
2229 wl_event_source_remove(ec->udev_drm_source);
2230 udev_monitor_unref(ec->udev_monitor);
2231err_drm_source:
2232 wl_event_source_remove(ec->drm_source);
2233 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2234 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002235err_sprite:
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002236 gles2_renderer_destroy(&ec->base);
2237 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002238 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002239err_udev_dev:
2240 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002241err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002242 tty_destroy(ec->tty);
2243err_udev:
2244 udev_unref(ec->udev);
2245err_compositor:
2246 weston_compositor_shutdown(&ec->base);
2247err_base:
2248 free(ec);
2249 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002250}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002251
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002252static int
2253set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2254{
2255 mode->flags = 0;
2256
2257 if (strcmp(hsync, "+hsync") == 0)
2258 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2259 else if (strcmp(hsync, "-hsync") == 0)
2260 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2261 else
2262 return -1;
2263
2264 if (strcmp(vsync, "+vsync") == 0)
2265 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2266 else if (strcmp(vsync, "-vsync") == 0)
2267 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2268 else
2269 return -1;
2270
2271 return 0;
2272}
2273
2274static int
2275check_for_modeline(struct drm_configured_output *output)
2276{
2277 drmModeModeInfo mode;
2278 char hsync[16];
2279 char vsync[16];
2280 char mode_name[16];
2281 float fclock;
2282
2283 mode.type = DRM_MODE_TYPE_USERDEF;
2284 mode.hskew = 0;
2285 mode.vscan = 0;
2286 mode.vrefresh = 0;
2287
2288 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2289 &fclock, &mode.hdisplay,
2290 &mode.hsync_start,
2291 &mode.hsync_end, &mode.htotal,
2292 &mode.vdisplay,
2293 &mode.vsync_start,
2294 &mode.vsync_end, &mode.vtotal,
2295 hsync, vsync) == 11) {
2296 if (set_sync_flags(&mode, hsync, vsync))
2297 return -1;
2298
2299 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2300 strcpy(mode.name, mode_name);
2301
2302 mode.clock = fclock * 1000;
2303 } else
2304 return -1;
2305
2306 output->crtc_mode = mode;
2307
2308 return 0;
2309}
2310
Scott Moreau8ab5d452012-07-30 19:51:08 -06002311static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002312drm_output_set_transform(struct drm_configured_output *output)
2313{
2314 if (!output_transform) {
2315 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2316 return;
2317 }
2318
2319 if (!strcmp(output_transform, "normal"))
2320 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2321 else if (!strcmp(output_transform, "90"))
2322 output->transform = WL_OUTPUT_TRANSFORM_90;
2323 else if (!strcmp(output_transform, "180"))
2324 output->transform = WL_OUTPUT_TRANSFORM_180;
2325 else if (!strcmp(output_transform, "270"))
2326 output->transform = WL_OUTPUT_TRANSFORM_270;
2327 else if (!strcmp(output_transform, "flipped"))
2328 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2329 else if (!strcmp(output_transform, "flipped-90"))
2330 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2331 else if (!strcmp(output_transform, "flipped-180"))
2332 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2333 else if (!strcmp(output_transform, "flipped-270"))
2334 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2335 else {
2336 weston_log("Invalid transform \"%s\" for output %s\n",
2337 output_transform, output_name);
2338 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2339 }
2340
2341 free(output_transform);
2342 output_transform = NULL;
2343}
2344
2345static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002346output_section_done(void *data)
2347{
2348 struct drm_configured_output *output;
2349
2350 output = malloc(sizeof *output);
2351
Scott Moreau1bad5db2012-08-18 01:04:05 -06002352 if (!output || !output_name || (output_name[0] == 'X') ||
2353 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002354 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002355 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002356 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002357 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002358 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002359 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002360 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002361 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002362 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002363
2364 output->config = OUTPUT_CONFIG_INVALID;
2365 output->name = output_name;
2366 output->mode = output_mode;
2367
Scott Moreau1bad5db2012-08-18 01:04:05 -06002368 if (output_mode) {
2369 if (strcmp(output_mode, "off") == 0)
2370 output->config = OUTPUT_CONFIG_OFF;
2371 else if (strcmp(output_mode, "preferred") == 0)
2372 output->config = OUTPUT_CONFIG_PREFERRED;
2373 else if (strcmp(output_mode, "current") == 0)
2374 output->config = OUTPUT_CONFIG_CURRENT;
2375 else if (sscanf(output_mode, "%dx%d",
2376 &output->width, &output->height) == 2)
2377 output->config = OUTPUT_CONFIG_MODE;
2378 else if (check_for_modeline(output) == 0)
2379 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002380
Scott Moreau1bad5db2012-08-18 01:04:05 -06002381 if (output->config == OUTPUT_CONFIG_INVALID)
2382 weston_log("Invalid mode \"%s\" for output %s\n",
2383 output_mode, output_name);
2384 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002385 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002386
2387 drm_output_set_transform(output);
2388
2389 wl_list_insert(&configured_output_list, &output->link);
2390
2391 if (output_transform)
2392 free(output_transform);
2393 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002394}
2395
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002396WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002397backend_init(struct wl_display *display, int argc, char *argv[],
2398 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002399{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002400 int connector = 0, tty = 0;
2401 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002402
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002403 const struct weston_option drm_options[] = {
2404 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2405 { WESTON_OPTION_STRING, "seat", 0, &seat },
2406 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002407 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002408 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002409
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002410 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002411
Scott Moreau8ab5d452012-07-30 19:51:08 -06002412 wl_list_init(&configured_output_list);
2413
2414 const struct config_key drm_config_keys[] = {
2415 { "name", CONFIG_KEY_STRING, &output_name },
2416 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002417 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002418 };
2419
2420 const struct config_section config_section[] = {
2421 { "output", drm_config_keys,
2422 ARRAY_LENGTH(drm_config_keys), output_section_done },
2423 };
2424
2425 parse_config_file(config_file, config_section,
2426 ARRAY_LENGTH(config_section), NULL);
2427
Daniel Stonec1be8e52012-06-01 11:14:02 -04002428 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2429 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002430}