blob: 417b67ff569feec1921e38f1b951407d3c0021bf [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 Oliveira0a887722012-11-22 15:57:00 +0200360 pixman_region32_subtract(&c->base.primary_plane.damage,
361 &c->base.primary_plane.damage, damage);
362
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363 bo = gbm_surface_lock_front_buffer(output->surface);
364 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200365 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400366 return;
367 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200369 output->next = drm_fb_get_from_bo(bo, c);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300370 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200371 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300372 gbm_surface_release_buffer(output->surface, bo);
373 return;
374 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400375}
376
377static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500378drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400379 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100380{
381 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500382 struct drm_compositor *compositor =
383 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500384 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400385 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500386 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100387
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300388 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400389 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300390 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400391 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100392
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400393 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300394 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400395 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300396 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400397 &output->connector_id, 1,
398 &mode->mode_info);
399 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200400 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400401 return;
402 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200403 }
404
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500405 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300406 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500407 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200408 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500409 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500410 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100411
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300412 output->page_flip_pending = 1;
413
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400414 drm_output_set_cursor(output);
415
Jesse Barnes58ef3792012-02-23 09:45:49 -0500416 /*
417 * Now, update all the sprite surfaces
418 */
419 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200420 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500421 drmVBlank vbl = {
422 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
423 .request.sequence = 1,
424 };
425
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200426 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200427 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500428 continue;
429
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200430 if (s->next && !compositor->sprites_hidden)
431 fb_id = s->next->fb_id;
432
Jesse Barnes58ef3792012-02-23 09:45:49 -0500433 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200434 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500435 s->dest_x, s->dest_y,
436 s->dest_w, s->dest_h,
437 s->src_x, s->src_y,
438 s->src_w, s->src_h);
439 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200440 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500441 ret, strerror(errno));
442
Rob Clark5ca1a472012-08-08 20:27:37 -0500443 if (output->pipe > 0)
444 vbl.request.type |= DRM_VBLANK_SECONDARY;
445
Jesse Barnes58ef3792012-02-23 09:45:49 -0500446 /*
447 * Queue a vblank signal so we know when the surface
448 * becomes active on the display or has been replaced.
449 */
450 vbl.request.signal = (unsigned long)s;
451 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
452 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200453 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500454 ret, strerror(errno));
455 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300456
457 s->output = output;
458 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500459 }
460
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500461 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400462}
463
464static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500465vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
466 void *data)
467{
468 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300469 struct drm_output *output = s->output;
470 uint32_t msecs;
471
472 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500473
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200474 if (s->current)
475 gbm_bo_destroy(s->current->bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500476
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200477 s->current = s->next;
478 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300479
480 if (!output->page_flip_pending) {
481 msecs = sec * 1000 + usec / 1000;
482 weston_output_finish_frame(&output->base, msecs);
483 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500484}
485
486static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400487page_flip_handler(int fd, unsigned int frame,
488 unsigned int sec, unsigned int usec, void *data)
489{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200490 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400491 uint32_t msecs;
492
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300493 output->page_flip_pending = 0;
494
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300495 if (output->current) {
496 if (output->current->is_client_buffer)
497 gbm_bo_destroy(output->current->bo);
498 else
499 gbm_surface_release_buffer(output->surface,
500 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200501 }
502
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 output->current = output->next;
504 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400505
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300506 if (!output->vblank_pending) {
507 msecs = sec * 1000 + usec / 1000;
508 weston_output_finish_frame(&output->base, msecs);
509 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200510}
511
512static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500513drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
514{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400515 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500516
517 for (i = 0; i < s->count_formats; i++)
518 if (s->formats[i] == format)
519 return 1;
520
521 return 0;
522}
523
524static int
525drm_surface_transform_supported(struct weston_surface *es)
526{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400527 struct weston_matrix *matrix = &es->transform.matrix;
528 int i;
529
530 if (!es->transform.enabled)
531 return 1;
532
533 for (i = 0; i < 16; i++) {
534 switch (i) {
535 case 10:
536 case 15:
537 if (matrix->d[i] != 1.0)
538 return 0;
539 break;
540 case 0:
541 case 5:
542 case 12:
543 case 13:
544 break;
545 default:
546 if (matrix->d[i] != 0.0)
547 return 0;
548 break;
549 }
550 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500551
552 return 1;
553}
554
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400555static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500556drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400557 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500558{
559 struct weston_compositor *ec = output_base->compositor;
560 struct drm_compositor *c =(struct drm_compositor *) ec;
561 struct drm_sprite *s;
562 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500563 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500564 pixman_region32_t dest_rect, src_rect;
565 pixman_box32_t *box;
566 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400567 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500568
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500569 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400570 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500571
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300572 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400573 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300574
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400575 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400576 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200578 if (es->alpha != 1.0f)
579 return NULL;
580
Rob Clark702ffae2012-08-09 14:18:27 -0500581 if (wl_buffer_is_shm(es->buffer))
582 return NULL;
583
Jesse Barnes58ef3792012-02-23 09:45:49 -0500584 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400585 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586
Jesse Barnes58ef3792012-02-23 09:45:49 -0500587 wl_list_for_each(s, &c->sprite_list, link) {
588 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
589 continue;
590
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200591 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500592 found = 1;
593 break;
594 }
595 }
596
597 /* No sprites available */
598 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400599 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400601 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
602 es->buffer, GBM_BO_USE_SCANOUT);
603 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400604 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400605
Jesse Barnes58ef3792012-02-23 09:45:49 -0500606 format = gbm_bo_get_format(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500607
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200608 if (!drm_surface_format_supported(s, format)) {
609 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400610 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611 }
612
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200613 s->next = drm_fb_get_from_bo(bo, c);
614 if (!s->next) {
615 gbm_bo_destroy(bo);
616 return NULL;
617 }
618
619 drm_fb_set_buffer(s->next, es->buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400621 box = pixman_region32_extents(&es->transform.boundingbox);
622 s->plane.x = box->x1;
623 s->plane.y = box->y1;
624
Jesse Barnes58ef3792012-02-23 09:45:49 -0500625 /*
626 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200627 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628 * for us already).
629 */
630 pixman_region32_init(&dest_rect);
631 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
632 &output_base->region);
633 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
634 box = pixman_region32_extents(&dest_rect);
635 s->dest_x = box->x1;
636 s->dest_y = box->y1;
637 s->dest_w = box->x2 - box->x1;
638 s->dest_h = box->y2 - box->y1;
639 pixman_region32_fini(&dest_rect);
640
641 pixman_region32_init(&src_rect);
642 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
643 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500644 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400645
646 weston_surface_from_global_fixed(es,
647 wl_fixed_from_int(box->x1),
648 wl_fixed_from_int(box->y1),
649 &sx1, &sy1);
650 weston_surface_from_global_fixed(es,
651 wl_fixed_from_int(box->x2),
652 wl_fixed_from_int(box->y2),
653 &sx2, &sy2);
654
655 if (sx1 < 0)
656 sx1 = 0;
657 if (sy1 < 0)
658 sy1 = 0;
659 if (sx2 > wl_fixed_from_int(es->geometry.width))
660 sx2 = wl_fixed_from_int(es->geometry.width);
661 if (sy2 > wl_fixed_from_int(es->geometry.height))
662 sy2 = wl_fixed_from_int(es->geometry.height);
663
664 s->src_x = sx1 << 8;
665 s->src_y = sy1 << 8;
666 s->src_w = (sx2 - sx1) << 8;
667 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668 pixman_region32_fini(&src_rect);
669
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400670 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500671}
672
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400673static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400674drm_output_prepare_cursor_surface(struct weston_output *output_base,
675 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500676{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400677 struct drm_compositor *c =
678 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400679 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400680
681 if (output->cursor_surface)
682 return NULL;
683 if (es->output_mask != (1u << output_base->id))
684 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500685 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400686 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400687 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
688 es->geometry.width > 64 || es->geometry.height > 64)
689 return NULL;
690
691 output->cursor_surface = es;
692
693 return &output->cursor_plane;
694}
695
696static void
697drm_output_set_cursor(struct drm_output *output)
698{
699 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400700 struct drm_compositor *c =
701 (struct drm_compositor *) output->base.compositor;
702 EGLint handle, stride;
703 struct gbm_bo *bo;
704 uint32_t buf[64 * 64];
705 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400706 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500707
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400708 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400709 if (es == NULL) {
710 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
711 return;
712 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500713
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400714 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
715 pixman_region32_fini(&output->cursor_plane.damage);
716 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400717 output->current_cursor ^= 1;
718 bo = output->cursor_bo[output->current_cursor];
719 memset(buf, 0, sizeof buf);
720 stride = wl_shm_buffer_get_stride(es->buffer);
721 s = wl_shm_buffer_get_data(es->buffer);
722 for (i = 0; i < es->geometry.height; i++)
723 memcpy(buf + i * 64, s + i * stride,
724 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500725
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400726 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300727 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400728
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400729 handle = gbm_bo_get_handle(bo).s32;
730 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500731 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300732 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500733 c->cursors_are_broken = 1;
734 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400735 }
736
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400737 x = es->geometry.x - output->base.x;
738 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400739 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500740 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400741 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500742 c->cursors_are_broken = 1;
743 }
744
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400745 output->cursor_plane.x = x;
746 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400747 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500748}
749
Jesse Barnes58ef3792012-02-23 09:45:49 -0500750static void
751drm_assign_planes(struct weston_output *output)
752{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400753 struct drm_compositor *c =
754 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200755 struct drm_output *drm_output = (struct drm_output *) output;
756 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400757 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500758 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400759 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200761 /* Reset the opaque region of the planes */
762 pixman_region32_fini(&drm_output->cursor_plane.opaque);
763 pixman_region32_init(&drm_output->cursor_plane.opaque);
764 pixman_region32_fini(&drm_output->fb_plane.opaque);
765 pixman_region32_init(&drm_output->fb_plane.opaque);
766
767 wl_list_for_each (s, &c->sprite_list, link) {
768 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
769 continue;
770
771 pixman_region32_fini(&s->plane.opaque);
772 pixman_region32_init(&s->plane.opaque);
773 }
774
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775 /*
776 * Find a surface for each sprite in the output using some heuristics:
777 * 1) size
778 * 2) frequency of update
779 * 3) opacity (though some hw might support alpha blending)
780 * 4) clipping (this can be fixed with color keys)
781 *
782 * The idea is to save on blitting since this should save power.
783 * If we can get a large video surface on the sprite for example,
784 * the main display surface may not need to update at all, and
785 * the client buffer can be used directly for the sprite surface
786 * as we do for flipping full screen surfaces.
787 */
788 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400789 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400790 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791 pixman_region32_init(&surface_overlap);
792 pixman_region32_intersect(&surface_overlap, &overlap,
793 &es->transform.boundingbox);
794
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400795 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400796 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400797 next_plane = primary;
798 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400799 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400800 if (next_plane == NULL)
801 next_plane = drm_output_prepare_scanout_surface(output, es);
802 if (next_plane == NULL)
803 next_plane = drm_output_prepare_overlay_surface(output, es);
804 if (next_plane == NULL)
805 next_plane = primary;
806 weston_surface_move_to_plane(es, next_plane);
807 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808 pixman_region32_union(&overlap, &overlap,
809 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400810
Jesse Barnes58ef3792012-02-23 09:45:49 -0500811 pixman_region32_fini(&surface_overlap);
812 }
813 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814}
815
Matt Roper361d2ad2011-08-29 13:52:23 -0700816static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500817drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700818{
819 struct drm_output *output = (struct drm_output *) output_base;
820 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200821 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700822 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700823
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200824 if (output->backlight)
825 backlight_destroy(output->backlight);
826
Matt Roper361d2ad2011-08-29 13:52:23 -0700827 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400828 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700829
830 /* Restore original CRTC state */
831 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200832 origcrtc->x, origcrtc->y,
833 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700834 drmModeFreeCrtc(origcrtc);
835
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200836 c->crtc_allocator &= ~(1 << output->crtc_id);
837 c->connector_allocator &= ~(1 << output->connector_id);
838
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100839 gl_renderer_output_destroy(output_base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100840
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400841 gbm_surface_destroy(output->surface);
842
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400843 weston_plane_release(&output->fb_plane);
844 weston_plane_release(&output->cursor_plane);
845
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500846 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200847 wl_list_remove(&output->base.link);
848
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400849 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700850 free(output);
851}
852
Alex Wub7b8bda2012-04-17 17:20:48 +0800853static struct drm_mode *
854choose_mode (struct drm_output *output, struct weston_mode *target_mode)
855{
856 struct drm_mode *tmp_mode = NULL, *mode;
857
858 if (output->base.current->width == target_mode->width &&
859 output->base.current->height == target_mode->height &&
860 (output->base.current->refresh == target_mode->refresh ||
861 target_mode->refresh == 0))
862 return (struct drm_mode *)output->base.current;
863
864 wl_list_for_each(mode, &output->base.mode_list, base.link) {
865 if (mode->mode_info.hdisplay == target_mode->width &&
866 mode->mode_info.vdisplay == target_mode->height) {
867 if (mode->mode_info.vrefresh == target_mode->refresh ||
868 target_mode->refresh == 0) {
869 return mode;
870 } else if (!tmp_mode)
871 tmp_mode = mode;
872 }
873 }
874
875 return tmp_mode;
876}
877
878static int
879drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
880{
881 struct drm_output *output;
882 struct drm_mode *drm_mode;
883 int ret;
884 struct drm_compositor *ec;
885 struct gbm_surface *surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800886
887 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200888 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800889 return -1;
890 }
891
892 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200893 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800894 return -1;
895 }
896
897 ec = (struct drm_compositor *)output_base->compositor;
898 output = (struct drm_output *)output_base;
899 drm_mode = choose_mode (output, mode);
900
901 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200902 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800903 return -1;
904 } else if (&drm_mode->base == output->base.current) {
905 return 0;
906 } else if (drm_mode->base.width == output->base.current->width &&
907 drm_mode->base.height == output->base.current->height) {
908 /* only change refresh value */
909 ret = drmModeSetCrtc(ec->drm.fd,
910 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300911 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800912 &output->connector_id, 1, &drm_mode->mode_info);
913
914 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200915 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800916 drm_mode->base.width,
917 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400918 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800919 ret = -1;
920 } else {
921 output->base.current->flags = 0;
922 output->base.current = &drm_mode->base;
923 drm_mode->base.flags =
924 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
925 ret = 0;
926 }
927
928 return ret;
929 }
930
931 drm_mode->base.flags =
932 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
933
934 surface = gbm_surface_create(ec->gbm,
935 drm_mode->base.width,
936 drm_mode->base.height,
937 GBM_FORMAT_XRGB8888,
938 GBM_BO_USE_SCANOUT |
939 GBM_BO_USE_RENDERING);
940 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200941 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800942 return -1;
943 }
944
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100945 gl_renderer_output_destroy(&output->base);
Alex Wub7b8bda2012-04-17 17:20:48 +0800946
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100947 if (!gl_renderer_output_create(&output->base, surface)) {
John Kåre Alsaker94659272012-11-13 19:10:18 +0100948 weston_log("failed to create renderer output\n");
949 goto err_gbm;
Alex Wub7b8bda2012-04-17 17:20:48 +0800950 }
951
952 ret = drmModeSetCrtc(ec->drm.fd,
953 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300954 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800955 &output->connector_id, 1, &drm_mode->mode_info);
956 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200957 weston_log("failed to set mode\n");
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100958 goto err_gl;
Alex Wub7b8bda2012-04-17 17:20:48 +0800959 }
960
961 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300962 if (output->current) {
963 if (output->current->is_client_buffer)
964 gbm_bo_destroy(output->current->bo);
965 else
966 gbm_surface_release_buffer(output->surface,
967 output->current->bo);
968 }
969 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800970
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300971 if (output->next) {
972 if (output->next->is_client_buffer)
973 gbm_bo_destroy(output->next->bo);
974 else
975 gbm_surface_release_buffer(output->surface,
976 output->next->bo);
977 }
978 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800979
Alex Wub7b8bda2012-04-17 17:20:48 +0800980 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800981 output->surface = surface;
982
983 /*update output*/
984 output->base.current = &drm_mode->base;
985 output->base.dirty = 1;
986 weston_output_move(&output->base, output->base.x, output->base.y);
987 return 0;
988
John Kåre Alsaker779b52a2012-11-13 19:10:29 +0100989err_gl:
990 gl_renderer_output_destroy(&output->base);
John Kåre Alsaker94659272012-11-13 19:10:18 +0100991err_gbm:
Alex Wub7b8bda2012-04-17 17:20:48 +0800992 gbm_surface_destroy(surface);
993 return -1;
994}
995
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400996static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400997on_drm_input(int fd, uint32_t mask, void *data)
998{
999 drmEventContext evctx;
1000
1001 memset(&evctx, 0, sizeof evctx);
1002 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1003 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001004 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001005 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001006
1007 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001008}
1009
1010static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001011init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001012{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001013 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001014 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001015
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001016 sysnum = udev_device_get_sysnum(device);
1017 if (sysnum)
1018 ec->drm.id = atoi(sysnum);
1019 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001020 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001021 return -1;
1022 }
1023
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001024 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001025 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001026 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001027 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001028 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001029 udev_device_get_devnode(device));
1030 return -1;
1031 }
1032
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001033 weston_log("using %s\n", filename);
1034
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001035 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001036 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001037
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001038 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001039 NULL) < 0) {
1040 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001041 return -1;
1042 }
1043
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001044 return 0;
1045}
1046
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001047static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001048drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1049{
1050 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001051 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001052
1053 mode = malloc(sizeof *mode);
1054 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001055 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001056
1057 mode->base.flags = 0;
1058 mode->base.width = info->hdisplay;
1059 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001060
1061 /* Calculate higher precision (mHz) refresh rate */
1062 refresh = (info->clock * 1000000LL / info->htotal +
1063 info->vtotal / 2) / info->vtotal;
1064
1065 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1066 refresh *= 2;
1067 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1068 refresh /= 2;
1069 if (info->vscan > 1)
1070 refresh /= info->vscan;
1071
1072 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001073 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001074
1075 if (info->type & DRM_MODE_TYPE_PREFERRED)
1076 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1077
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001078 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1079
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001080 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001081}
1082
1083static int
1084drm_subpixel_to_wayland(int drm_value)
1085{
1086 switch (drm_value) {
1087 default:
1088 case DRM_MODE_SUBPIXEL_UNKNOWN:
1089 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1090 case DRM_MODE_SUBPIXEL_NONE:
1091 return WL_OUTPUT_SUBPIXEL_NONE;
1092 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1093 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1094 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1095 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1096 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1097 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1098 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1099 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1100 }
1101}
1102
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001103/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001104static uint32_t
1105drm_get_backlight(struct drm_output *output)
1106{
1107 long brightness, max_brightness, norm;
1108
1109 brightness = backlight_get_brightness(output->backlight);
1110 max_brightness = backlight_get_max_brightness(output->backlight);
1111
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001112 /* convert it on a scale of 0 to 255 */
1113 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001114
1115 return (uint32_t) norm;
1116}
1117
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001118/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001119static void
1120drm_set_backlight(struct weston_output *output_base, uint32_t value)
1121{
1122 struct drm_output *output = (struct drm_output *) output_base;
1123 long max_brightness, new_brightness;
1124
1125 if (!output->backlight)
1126 return;
1127
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001128 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001129 return;
1130
1131 max_brightness = backlight_get_max_brightness(output->backlight);
1132
1133 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001134 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001135
1136 backlight_set_brightness(output->backlight, new_brightness);
1137}
1138
1139static drmModePropertyPtr
1140drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1141{
1142 drmModePropertyPtr props;
1143 int i;
1144
1145 for (i = 0; i < connector->count_props; i++) {
1146 props = drmModeGetProperty(fd, connector->props[i]);
1147 if (!props)
1148 continue;
1149
1150 if (!strcmp(props->name, name))
1151 return props;
1152
1153 drmModeFreeProperty(props);
1154 }
1155
1156 return NULL;
1157}
1158
1159static void
1160drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1161{
1162 struct drm_output *output = (struct drm_output *) output_base;
1163 struct weston_compositor *ec = output_base->compositor;
1164 struct drm_compositor *c = (struct drm_compositor *) ec;
1165 drmModeConnectorPtr connector;
1166 drmModePropertyPtr prop;
1167
1168 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1169 if (!connector)
1170 return;
1171
1172 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1173 if (!prop) {
1174 drmModeFreeConnector(connector);
1175 return;
1176 }
1177
1178 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1179 prop->prop_id, level);
1180 drmModeFreeProperty(prop);
1181 drmModeFreeConnector(connector);
1182}
1183
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001184static const char *connector_type_names[] = {
1185 "None",
1186 "VGA",
1187 "DVI",
1188 "DVI",
1189 "DVI",
1190 "Composite",
1191 "TV",
1192 "LVDS",
1193 "CTV",
1194 "DIN",
1195 "DP",
1196 "HDMI",
1197 "HDMI",
1198 "TV",
1199 "eDP",
1200};
1201
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001202static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001203find_crtc_for_connector(struct drm_compositor *ec,
1204 drmModeRes *resources, drmModeConnector *connector)
1205{
1206 drmModeEncoder *encoder;
1207 uint32_t possible_crtcs;
1208 int i, j;
1209
1210 for (j = 0; j < connector->count_encoders; j++) {
1211 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1212 if (encoder == NULL) {
1213 weston_log("Failed to get encoder.\n");
1214 return -1;
1215 }
1216 possible_crtcs = encoder->possible_crtcs;
1217 drmModeFreeEncoder(encoder);
1218
1219 for (i = 0; i < resources->count_crtcs; i++) {
1220 if (possible_crtcs & (1 << i) &&
1221 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1222 return i;
1223 }
1224 }
1225
1226 return -1;
1227}
1228
1229static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001230create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001231 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001232 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001233 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001234{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001235 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001236 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1237 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001238 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001239 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001240 drmModeModeInfo crtc_mode;
1241 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001242 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001243 char name[32];
1244 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001245
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001246 i = find_crtc_for_connector(ec, resources, connector);
1247 if (i < 0) {
1248 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001249 return -1;
1250 }
1251
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001252 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001253 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001254 return -1;
1255
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001256 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001257 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1258 output->base.make = "unknown";
1259 output->base.model = "unknown";
1260 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001261
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001262 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1263 type_name = connector_type_names[connector->connector_type];
1264 else
1265 type_name = "UNKNOWN";
1266 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1267 output->name = strdup(name);
1268
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001269 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001270 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001271 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001272 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001273 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001274
Matt Roper361d2ad2011-08-29 13:52:23 -07001275 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1276
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001277 /* Get the current mode on the crtc that's currently driving
1278 * this connector. */
1279 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001280 memset(&crtc_mode, 0, sizeof crtc_mode);
1281 if (encoder != NULL) {
1282 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1283 drmModeFreeEncoder(encoder);
1284 if (crtc == NULL)
1285 goto err_free;
1286 if (crtc->mode_valid)
1287 crtc_mode = crtc->mode;
1288 drmModeFreeCrtc(crtc);
1289 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001290
David Herrmann0f0d54e2011-12-08 17:05:45 +01001291 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001292 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1293 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001294 goto err_free;
1295 }
1296
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001297 preferred = NULL;
1298 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001299 configured = NULL;
1300
1301 wl_list_for_each(temp, &configured_output_list, link) {
1302 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001303 if (temp->mode)
1304 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001305 temp->name, temp->mode);
1306 o = temp;
1307 break;
1308 }
1309 }
1310
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001311 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001312 weston_log("Disabling output %s\n", o->name);
1313
1314 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1315 0, 0, 0, 0, 0, NULL);
1316 goto err_free;
1317 }
1318
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001319 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001320 if (o && o->config == OUTPUT_CONFIG_MODE &&
1321 o->width == drm_mode->base.width &&
1322 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001323 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001324 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001325 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001326 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001327 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001328 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001329
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001330 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001331 configured = drm_output_add_mode(output, &o->crtc_mode);
1332 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001333 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001334 current = configured;
1335 }
1336
Wang Quanxianacb805a2012-07-30 18:09:46 -04001337 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001338 current = drm_output_add_mode(output, &crtc_mode);
1339 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001340 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001341 }
1342
Scott Moreau8ab5d452012-07-30 19:51:08 -06001343 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1344 configured = current;
1345
Wang Quanxianacb805a2012-07-30 18:09:46 -04001346 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001347 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001348 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001349 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001350 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001351 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001352 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001353 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001354
1355 if (output->base.current == NULL) {
1356 weston_log("no available modes for %s\n", output->name);
1357 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001358 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001359
Wang Quanxianacb805a2012-07-30 18:09:46 -04001360 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1361
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001362 output->surface = gbm_surface_create(ec->gbm,
1363 output->base.current->width,
1364 output->base.current->height,
1365 GBM_FORMAT_XRGB8888,
1366 GBM_BO_USE_SCANOUT |
1367 GBM_BO_USE_RENDERING);
1368 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001369 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001370 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001371 }
1372
John Kåre Alsaker94659272012-11-13 19:10:18 +01001373 weston_output_init(&output->base, &ec->base, x, y,
1374 connector->mmWidth, connector->mmHeight,
1375 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1376
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001377 if (gl_renderer_output_create(&output->base, output->surface) < 0)
John Kåre Alsaker94659272012-11-13 19:10:18 +01001378 goto err_output;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001379
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001380 output->cursor_bo[0] =
1381 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1382 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1383 output->cursor_bo[1] =
1384 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1385 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001386 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1387 weston_log("cursor buffers unavailable, using gl cursors\n");
1388 ec->cursors_are_broken = 1;
1389 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001390
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001391 output->backlight = backlight_init(drm_device,
1392 connector->connector_type);
1393 if (output->backlight) {
1394 output->base.set_backlight = drm_set_backlight;
1395 output->base.backlight_current = drm_get_backlight(output);
1396 }
1397
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001398 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1399
Alex Wubd3354b2012-04-17 17:20:49 +08001400 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001401 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001402 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001403 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001404 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001405 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001406
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001407 weston_plane_init(&output->cursor_plane, 0, 0);
1408 weston_plane_init(&output->fb_plane, 0, 0);
1409
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001410 weston_log("Output %s, (connector %d, crtc %d)\n",
1411 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001412 wl_list_for_each(m, &output->base.mode_list, link)
1413 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1414 m->width, m->height, m->refresh / 1000.0,
1415 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1416 ", preferred" : "",
1417 m->flags & WL_OUTPUT_MODE_CURRENT ?
1418 ", current" : "",
1419 connector->count_modes == 0 ?
1420 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001421
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001422 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001423
John Kåre Alsaker94659272012-11-13 19:10:18 +01001424err_output:
1425 weston_output_destroy(&output->base);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001426 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001427err_free:
1428 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1429 base.link) {
1430 wl_list_remove(&drm_mode->base.link);
1431 free(drm_mode);
1432 }
1433
1434 drmModeFreeCrtc(output->original_crtc);
1435 ec->crtc_allocator &= ~(1 << output->crtc_id);
1436 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001437 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001438 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001439
David Herrmann0f0d54e2011-12-08 17:05:45 +01001440 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001441}
1442
Jesse Barnes58ef3792012-02-23 09:45:49 -05001443static void
1444create_sprites(struct drm_compositor *ec)
1445{
1446 struct drm_sprite *sprite;
1447 drmModePlaneRes *plane_res;
1448 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001449 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001450
1451 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1452 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001453 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001454 strerror(errno));
1455 return;
1456 }
1457
1458 for (i = 0; i < plane_res->count_planes; i++) {
1459 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1460 if (!plane)
1461 continue;
1462
1463 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1464 plane->count_formats));
1465 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001466 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001467 __func__);
1468 free(plane);
1469 continue;
1470 }
1471
1472 memset(sprite, 0, sizeof *sprite);
1473
1474 sprite->possible_crtcs = plane->possible_crtcs;
1475 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001476 sprite->current = NULL;
1477 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001478 sprite->compositor = ec;
1479 sprite->count_formats = plane->count_formats;
1480 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001481 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001482 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001483 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001484
1485 wl_list_insert(&ec->sprite_list, &sprite->link);
1486 }
1487
1488 free(plane_res->planes);
1489 free(plane_res);
1490}
1491
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001492static void
1493destroy_sprites(struct drm_compositor *compositor)
1494{
1495 struct drm_sprite *sprite, *next;
1496 struct drm_output *output;
1497
1498 output = container_of(compositor->base.output_list.next,
1499 struct drm_output, base.link);
1500
1501 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1502 drmModeSetPlane(compositor->drm.fd,
1503 sprite->plane_id,
1504 output->crtc_id, 0, 0,
1505 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001506 if (sprite->current)
1507 gbm_bo_destroy(sprite->current->bo);
1508 if (sprite->next)
1509 gbm_bo_destroy(sprite->next->bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001510 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001511 free(sprite);
1512 }
1513}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001514
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001515static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001516create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001517 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001518{
1519 drmModeConnector *connector;
1520 drmModeRes *resources;
1521 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001522 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001523
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001524 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001525 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001526 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001527 return -1;
1528 }
1529
Jesse Barnes58ef3792012-02-23 09:45:49 -05001530 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001531 if (!ec->crtcs) {
1532 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001533 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001534 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001535
Rob Clark4339add2012-08-09 14:18:28 -05001536 ec->min_width = resources->min_width;
1537 ec->max_width = resources->max_width;
1538 ec->min_height = resources->min_height;
1539 ec->max_height = resources->max_height;
1540
Jesse Barnes58ef3792012-02-23 09:45:49 -05001541 ec->num_crtcs = resources->count_crtcs;
1542 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1543
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001544 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001545 connector = drmModeGetConnector(ec->drm.fd,
1546 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001547 if (connector == NULL)
1548 continue;
1549
1550 if (connector->connection == DRM_MODE_CONNECTED &&
1551 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001552 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001553 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001554 connector, x, y,
1555 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001556 drmModeFreeConnector(connector);
1557 continue;
1558 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001559
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001560 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001561 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001562 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001563 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001564
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001565 drmModeFreeConnector(connector);
1566 }
1567
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001568 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001569 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001570 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001571 return -1;
1572 }
1573
1574 drmModeFreeResources(resources);
1575
1576 return 0;
1577}
1578
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001579static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001580update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001581{
1582 drmModeConnector *connector;
1583 drmModeRes *resources;
1584 struct drm_output *output, *next;
1585 int x = 0, y = 0;
1586 int x_offset = 0, y_offset = 0;
1587 uint32_t connected = 0, disconnects = 0;
1588 int i;
1589
1590 resources = drmModeGetResources(ec->drm.fd);
1591 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001592 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001593 return;
1594 }
1595
1596 /* collect new connects */
1597 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001598 int connector_id = resources->connectors[i];
1599
1600 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001601 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001602 continue;
1603
David Herrmann7551cff2011-12-08 17:05:43 +01001604 if (connector->connection != DRM_MODE_CONNECTED) {
1605 drmModeFreeConnector(connector);
1606 continue;
1607 }
1608
Benjamin Franzke117483d2011-08-30 11:38:26 +02001609 connected |= (1 << connector_id);
1610
1611 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001612 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001613 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001614 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001615
1616 /* XXX: not yet needed, we die with 0 outputs */
1617 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001618 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001619 else
1620 x = 0;
1621 y = 0;
1622 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001623 connector, x, y,
1624 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001625 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001626
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001627 }
1628 drmModeFreeConnector(connector);
1629 }
1630 drmModeFreeResources(resources);
1631
1632 disconnects = ec->connector_allocator & ~connected;
1633 if (disconnects) {
1634 wl_list_for_each_safe(output, next, &ec->base.output_list,
1635 base.link) {
1636 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001637 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001638 output->base.x - x_offset,
1639 output->base.y - y_offset);
1640 }
1641
1642 if (disconnects & (1 << output->connector_id)) {
1643 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001644 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001645 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001646 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001647 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001648 }
1649 }
1650 }
1651
1652 /* FIXME: handle zero outputs, without terminating */
1653 if (ec->connector_allocator == 0)
1654 wl_display_terminate(ec->base.wl_display);
1655}
1656
1657static int
David Herrmannd7488c22012-03-11 20:05:21 +01001658udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001659{
David Herrmannd7488c22012-03-11 20:05:21 +01001660 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001661 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001662
1663 sysnum = udev_device_get_sysnum(device);
1664 if (!sysnum || atoi(sysnum) != ec->drm.id)
1665 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001666
David Herrmann6ac52db2012-03-11 20:05:22 +01001667 val = udev_device_get_property_value(device, "HOTPLUG");
1668 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001669 return 0;
1670
David Herrmann6ac52db2012-03-11 20:05:22 +01001671 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001672}
1673
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001674static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001675udev_drm_event(int fd, uint32_t mask, void *data)
1676{
1677 struct drm_compositor *ec = data;
1678 struct udev_device *event;
1679
1680 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001681
David Herrmannd7488c22012-03-11 20:05:21 +01001682 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001683 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001684
1685 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001686
1687 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001688}
1689
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001690static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001691drm_restore(struct weston_compositor *ec)
1692{
1693 struct drm_compositor *d = (struct drm_compositor *) ec;
1694
1695 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1696 weston_log("failed to drop master: %m\n");
1697 tty_reset(d->tty);
1698}
1699
Pekka Paalanen33156972012-08-03 13:30:30 -04001700static const char default_seat[] = "seat0";
1701
1702static void
1703device_added(struct udev_device *udev_device, struct drm_seat *master)
1704{
1705 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001706 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001707 const char *devnode;
1708 const char *device_seat;
1709 int fd;
1710
1711 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1712 if (!device_seat)
1713 device_seat = default_seat;
1714
1715 if (strcmp(device_seat, master->seat_id))
1716 return;
1717
1718 c = master->base.compositor;
1719 devnode = udev_device_get_devnode(udev_device);
1720
1721 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001722 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001723 * read. mtdev_get() also expects this. */
1724 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1725 if (fd < 0) {
1726 weston_log("opening input device '%s' failed.\n", devnode);
1727 return;
1728 }
1729
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001730 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001731 if (!device) {
1732 close(fd);
1733 weston_log("not using input device '%s'.\n", devnode);
1734 return;
1735 }
1736
1737 wl_list_insert(master->devices_list.prev, &device->link);
1738}
1739
1740static void
1741evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1742{
1743 struct drm_seat *seat = (struct drm_seat *) seat_base;
1744 struct udev_enumerate *e;
1745 struct udev_list_entry *entry;
1746 struct udev_device *device;
1747 const char *path, *sysname;
1748
1749 e = udev_enumerate_new(udev);
1750 udev_enumerate_add_match_subsystem(e, "input");
1751 udev_enumerate_scan_devices(e);
1752 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1753 path = udev_list_entry_get_name(entry);
1754 device = udev_device_new_from_syspath(udev, path);
1755
1756 sysname = udev_device_get_sysname(device);
1757 if (strncmp("event", sysname, 5) != 0) {
1758 udev_device_unref(device);
1759 continue;
1760 }
1761
1762 device_added(device, seat);
1763
1764 udev_device_unref(device);
1765 }
1766 udev_enumerate_unref(e);
1767
1768 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1769
1770 if (wl_list_empty(&seat->devices_list)) {
1771 weston_log(
1772 "warning: no input devices on entering Weston. "
1773 "Possible causes:\n"
1774 "\t- no permissions to read /dev/input/event*\n"
1775 "\t- seats misconfigured "
1776 "(Weston backend option 'seat', "
1777 "udev device property ID_SEAT)\n");
1778 }
1779}
1780
1781static int
1782evdev_udev_handler(int fd, uint32_t mask, void *data)
1783{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001784 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001785 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001786 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001787 const char *action;
1788 const char *devnode;
1789
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001790 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001791 if (!udev_device)
1792 return 1;
1793
1794 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001795 if (!action)
1796 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001797
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001798 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1799 goto out;
1800
1801 if (!strcmp(action, "add")) {
1802 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001803 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001804 else if (!strcmp(action, "remove")) {
1805 devnode = udev_device_get_devnode(udev_device);
1806 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1807 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001808 weston_log("input device %s, %s removed\n",
1809 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001810 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001811 break;
1812 }
1813 }
1814
1815out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001816 udev_device_unref(udev_device);
1817
1818 return 0;
1819}
1820
1821static int
1822evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1823{
1824 struct drm_seat *master = (struct drm_seat *) seat_base;
1825 struct wl_event_loop *loop;
1826 struct weston_compositor *c = master->base.compositor;
1827 int fd;
1828
1829 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1830 if (!master->udev_monitor) {
1831 weston_log("udev: failed to create the udev monitor\n");
1832 return 0;
1833 }
1834
1835 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1836 "input", NULL);
1837
1838 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1839 weston_log("udev: failed to bind the udev monitor\n");
1840 udev_monitor_unref(master->udev_monitor);
1841 return 0;
1842 }
1843
1844 loop = wl_display_get_event_loop(c->wl_display);
1845 fd = udev_monitor_get_fd(master->udev_monitor);
1846 master->udev_monitor_source =
1847 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1848 evdev_udev_handler, master);
1849 if (!master->udev_monitor_source) {
1850 udev_monitor_unref(master->udev_monitor);
1851 return 0;
1852 }
1853
1854 return 1;
1855}
1856
1857static void
1858evdev_disable_udev_monitor(struct weston_seat *seat_base)
1859{
1860 struct drm_seat *seat = (struct drm_seat *) seat_base;
1861
1862 if (!seat->udev_monitor)
1863 return;
1864
1865 udev_monitor_unref(seat->udev_monitor);
1866 seat->udev_monitor = NULL;
1867 wl_event_source_remove(seat->udev_monitor_source);
1868 seat->udev_monitor_source = NULL;
1869}
1870
1871static void
1872drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1873{
1874 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001875 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001876
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001877 wl_list_for_each(device, &seat->devices_list, link)
1878 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001879}
1880
1881static void
1882evdev_input_create(struct weston_compositor *c, struct udev *udev,
1883 const char *seat_id)
1884{
1885 struct drm_seat *seat;
1886
1887 seat = malloc(sizeof *seat);
1888 if (seat == NULL)
1889 return;
1890
1891 memset(seat, 0, sizeof *seat);
1892 weston_seat_init(&seat->base, c);
1893 seat->base.led_update = drm_led_update;
1894
1895 wl_list_init(&seat->devices_list);
1896 seat->seat_id = strdup(seat_id);
1897 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1898 free(seat->seat_id);
1899 free(seat);
1900 return;
1901 }
1902
1903 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001904}
1905
1906static void
1907evdev_remove_devices(struct weston_seat *seat_base)
1908{
1909 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001910 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001911
1912 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001913 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001914
Pekka Paalanend8583512012-08-03 14:39:11 +03001915 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001916 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001917}
1918
1919static void
1920evdev_input_destroy(struct weston_seat *seat_base)
1921{
1922 struct drm_seat *seat = (struct drm_seat *) seat_base;
1923
1924 evdev_remove_devices(seat_base);
1925 evdev_disable_udev_monitor(&seat->base);
1926
1927 weston_seat_release(seat_base);
1928 free(seat->seat_id);
1929 free(seat);
1930}
1931
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001932static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001933drm_free_configured_output(struct drm_configured_output *output)
1934{
1935 free(output->name);
1936 free(output->mode);
1937 free(output);
1938}
1939
1940static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001941drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001942{
1943 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001944 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001945 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001946
Daniel Stone37816df2012-05-16 18:45:18 +01001947 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1948 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001949 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001950 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001951
1952 wl_event_source_remove(d->udev_drm_source);
1953 wl_event_source_remove(d->drm_source);
1954
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001955 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001956
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001957 gl_renderer_destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04001958
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001959 destroy_sprites(d);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001960 gbm_device_destroy(d->gbm);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001961 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001962 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001963 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001964
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001965 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001966}
1967
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001968static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001969drm_compositor_set_modes(struct drm_compositor *compositor)
1970{
1971 struct drm_output *output;
1972 struct drm_mode *drm_mode;
1973 int ret;
1974
1975 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1976 drm_mode = (struct drm_mode *) output->base.current;
1977 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001978 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001979 &output->connector_id, 1,
1980 &drm_mode->mode_info);
1981 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001982 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001983 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001984 drm_mode->base.width, drm_mode->base.height,
1985 output->base.x, output->base.y);
1986 }
1987 }
1988}
1989
1990static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001991vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001992{
1993 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001994 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001995 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001996 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001997
1998 switch (event) {
1999 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002000 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002001 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002002 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002003 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002004 wl_display_terminate(compositor->wl_display);
2005 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002006 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002007 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002008 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002009 wl_list_for_each(seat, &compositor->seat_list, link) {
2010 evdev_add_devices(ec->udev, seat);
2011 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002012 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002013 break;
2014 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002015 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002016 wl_list_for_each(seat, &compositor->seat_list, link) {
2017 evdev_disable_udev_monitor(seat);
2018 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002019 }
2020
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002021 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002022 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002023 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002024
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002025 /* If we have a repaint scheduled (either from a
2026 * pending pageflip or the idle handler), make sure we
2027 * cancel that so we don't try to pageflip when we're
2028 * vt switched away. The SLEEPING state will prevent
2029 * further attemps at repainting. When we switch
2030 * back, we schedule a repaint, which will process
2031 * pending frame callbacks. */
2032
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002033 wl_list_for_each(output, &ec->base.output_list, base.link) {
2034 output->base.repaint_needed = 0;
2035 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002036 }
2037
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002038 output = container_of(ec->base.output_list.next,
2039 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002040
2041 wl_list_for_each(sprite, &ec->sprite_list, link)
2042 drmModeSetPlane(ec->drm.fd,
2043 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002044 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002045 0, 0, 0, 0, 0, 0, 0, 0);
2046
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002047 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002048 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002049
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002050 break;
2051 };
2052}
2053
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002054static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002055switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002056{
2057 struct drm_compositor *ec = data;
2058
Daniel Stone325fc2d2012-05-30 16:31:58 +01002059 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002060}
2061
David Herrmann0af066f2012-10-29 19:21:16 +01002062/*
2063 * Find primary GPU
2064 * Some systems may have multiple DRM devices attached to a single seat. This
2065 * function loops over all devices and tries to find a PCI device with the
2066 * boot_vga sysfs attribute set to 1.
2067 * If no such device is found, the first DRM device reported by udev is used.
2068 */
2069static struct udev_device*
2070find_primary_gpu(struct drm_compositor *ec, const char *seat)
2071{
2072 struct udev_enumerate *e;
2073 struct udev_list_entry *entry;
2074 const char *path, *device_seat, *id;
2075 struct udev_device *device, *drm_device, *pci;
2076
2077 e = udev_enumerate_new(ec->udev);
2078 udev_enumerate_add_match_subsystem(e, "drm");
2079 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2080
2081 udev_enumerate_scan_devices(e);
2082 drm_device = NULL;
2083 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2084 path = udev_list_entry_get_name(entry);
2085 device = udev_device_new_from_syspath(ec->udev, path);
2086 if (!device)
2087 continue;
2088 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2089 if (!device_seat)
2090 device_seat = default_seat;
2091 if (strcmp(device_seat, seat)) {
2092 udev_device_unref(device);
2093 continue;
2094 }
2095
2096 pci = udev_device_get_parent_with_subsystem_devtype(device,
2097 "pci", NULL);
2098 if (pci) {
2099 id = udev_device_get_sysattr_value(pci, "boot_vga");
2100 if (id && !strcmp(id, "1")) {
2101 if (drm_device)
2102 udev_device_unref(drm_device);
2103 drm_device = device;
2104 break;
2105 }
2106 }
2107
2108 if (!drm_device)
2109 drm_device = device;
2110 else
2111 udev_device_unref(device);
2112 }
2113
2114 udev_enumerate_unref(e);
2115 return drm_device;
2116}
2117
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002118static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002119planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002120{
2121 struct drm_compositor *c = data;
2122
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002123 switch (key) {
2124 case KEY_C:
2125 c->cursors_are_broken ^= 1;
2126 break;
2127 case KEY_V:
2128 c->sprites_are_broken ^= 1;
2129 break;
2130 case KEY_O:
2131 c->sprites_hidden ^= 1;
2132 break;
2133 default:
2134 break;
2135 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002136}
2137
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002138static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002139drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002140 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002141 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002142{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002143 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002144 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002145 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002146 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002147 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002148 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002149
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002150 weston_log("initializing drm backend\n");
2151
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002152 ec = malloc(sizeof *ec);
2153 if (ec == NULL)
2154 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002155 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002156
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002157 /* KMS support for sprites is not complete yet, so disable the
2158 * functionality for now. */
2159 ec->sprites_are_broken = 1;
2160
Daniel Stone725c2c32012-06-22 14:04:36 +01002161 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002162 config_file) < 0) {
2163 weston_log("weston_compositor_init failed\n");
2164 goto err_base;
2165 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002166
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002167 ec->udev = udev_new();
2168 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002169 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002170 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002171 }
2172
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002173 ec->base.wl_display = display;
2174 ec->tty = tty_create(&ec->base, vt_func, tty);
2175 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002176 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002177 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002178 }
2179
David Herrmann0af066f2012-10-29 19:21:16 +01002180 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002181 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002182 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002183 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002184 }
David Herrmann0af066f2012-10-29 19:21:16 +01002185 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002186
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002187 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002188 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002189 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002190 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002191
2192 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002193 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002194
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002195 ec->base.focus = 1;
2196
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002197 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002198
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002199 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002200 weston_compositor_add_key_binding(&ec->base, key,
2201 MODIFIER_CTRL | MODIFIER_ALT,
2202 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002203
Jesse Barnes58ef3792012-02-23 09:45:49 -05002204 wl_list_init(&ec->sprite_list);
2205 create_sprites(ec);
2206
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002207 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002208 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002209 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002210 }
2211
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002212 path = NULL;
2213
Tiago Vignattice03ec32011-12-19 01:14:03 +02002214 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002215
2216 loop = wl_display_get_event_loop(ec->base.wl_display);
2217 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002218 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002219 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002220
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002221 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2222 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002223 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002224 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002225 }
2226 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2227 "drm", NULL);
2228 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002229 wl_event_loop_add_fd(loop,
2230 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002231 WL_EVENT_READABLE, udev_drm_event, ec);
2232
2233 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002234 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002235 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002236 }
2237
Daniel Stonea96b93c2012-06-22 14:04:37 +01002238 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002239
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002240 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002241 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002242 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002243 planes_binding, ec);
2244 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2245 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002246
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002247 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002248
2249err_udev_monitor:
2250 wl_event_source_remove(ec->udev_drm_source);
2251 udev_monitor_unref(ec->udev_monitor);
2252err_drm_source:
2253 wl_event_source_remove(ec->drm_source);
2254 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2255 evdev_input_destroy(weston_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002256err_sprite:
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01002257 gl_renderer_destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002258 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002259 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002260err_udev_dev:
2261 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002262err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002263 tty_destroy(ec->tty);
2264err_udev:
2265 udev_unref(ec->udev);
2266err_compositor:
2267 weston_compositor_shutdown(&ec->base);
2268err_base:
2269 free(ec);
2270 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002271}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002272
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002273static int
2274set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2275{
2276 mode->flags = 0;
2277
2278 if (strcmp(hsync, "+hsync") == 0)
2279 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2280 else if (strcmp(hsync, "-hsync") == 0)
2281 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2282 else
2283 return -1;
2284
2285 if (strcmp(vsync, "+vsync") == 0)
2286 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2287 else if (strcmp(vsync, "-vsync") == 0)
2288 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2289 else
2290 return -1;
2291
2292 return 0;
2293}
2294
2295static int
2296check_for_modeline(struct drm_configured_output *output)
2297{
2298 drmModeModeInfo mode;
2299 char hsync[16];
2300 char vsync[16];
2301 char mode_name[16];
2302 float fclock;
2303
2304 mode.type = DRM_MODE_TYPE_USERDEF;
2305 mode.hskew = 0;
2306 mode.vscan = 0;
2307 mode.vrefresh = 0;
2308
2309 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2310 &fclock, &mode.hdisplay,
2311 &mode.hsync_start,
2312 &mode.hsync_end, &mode.htotal,
2313 &mode.vdisplay,
2314 &mode.vsync_start,
2315 &mode.vsync_end, &mode.vtotal,
2316 hsync, vsync) == 11) {
2317 if (set_sync_flags(&mode, hsync, vsync))
2318 return -1;
2319
2320 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2321 strcpy(mode.name, mode_name);
2322
2323 mode.clock = fclock * 1000;
2324 } else
2325 return -1;
2326
2327 output->crtc_mode = mode;
2328
2329 return 0;
2330}
2331
Scott Moreau8ab5d452012-07-30 19:51:08 -06002332static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002333drm_output_set_transform(struct drm_configured_output *output)
2334{
2335 if (!output_transform) {
2336 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2337 return;
2338 }
2339
2340 if (!strcmp(output_transform, "normal"))
2341 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2342 else if (!strcmp(output_transform, "90"))
2343 output->transform = WL_OUTPUT_TRANSFORM_90;
2344 else if (!strcmp(output_transform, "180"))
2345 output->transform = WL_OUTPUT_TRANSFORM_180;
2346 else if (!strcmp(output_transform, "270"))
2347 output->transform = WL_OUTPUT_TRANSFORM_270;
2348 else if (!strcmp(output_transform, "flipped"))
2349 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2350 else if (!strcmp(output_transform, "flipped-90"))
2351 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2352 else if (!strcmp(output_transform, "flipped-180"))
2353 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2354 else if (!strcmp(output_transform, "flipped-270"))
2355 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2356 else {
2357 weston_log("Invalid transform \"%s\" for output %s\n",
2358 output_transform, output_name);
2359 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2360 }
2361
2362 free(output_transform);
2363 output_transform = NULL;
2364}
2365
2366static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002367output_section_done(void *data)
2368{
2369 struct drm_configured_output *output;
2370
2371 output = malloc(sizeof *output);
2372
Scott Moreau1bad5db2012-08-18 01:04:05 -06002373 if (!output || !output_name || (output_name[0] == 'X') ||
2374 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002375 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002376 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002377 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002378 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002379 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002380 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002381 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002382 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002383 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002384
2385 output->config = OUTPUT_CONFIG_INVALID;
2386 output->name = output_name;
2387 output->mode = output_mode;
2388
Scott Moreau1bad5db2012-08-18 01:04:05 -06002389 if (output_mode) {
2390 if (strcmp(output_mode, "off") == 0)
2391 output->config = OUTPUT_CONFIG_OFF;
2392 else if (strcmp(output_mode, "preferred") == 0)
2393 output->config = OUTPUT_CONFIG_PREFERRED;
2394 else if (strcmp(output_mode, "current") == 0)
2395 output->config = OUTPUT_CONFIG_CURRENT;
2396 else if (sscanf(output_mode, "%dx%d",
2397 &output->width, &output->height) == 2)
2398 output->config = OUTPUT_CONFIG_MODE;
2399 else if (check_for_modeline(output) == 0)
2400 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002401
Scott Moreau1bad5db2012-08-18 01:04:05 -06002402 if (output->config == OUTPUT_CONFIG_INVALID)
2403 weston_log("Invalid mode \"%s\" for output %s\n",
2404 output_mode, output_name);
2405 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002406 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002407
2408 drm_output_set_transform(output);
2409
2410 wl_list_insert(&configured_output_list, &output->link);
2411
2412 if (output_transform)
2413 free(output_transform);
2414 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002415}
2416
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002417WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002418backend_init(struct wl_display *display, int argc, char *argv[],
2419 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002420{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002421 int connector = 0, tty = 0;
2422 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002423
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002424 const struct weston_option drm_options[] = {
2425 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2426 { WESTON_OPTION_STRING, "seat", 0, &seat },
2427 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002428 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002429 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002430
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002431 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002432
Scott Moreau8ab5d452012-07-30 19:51:08 -06002433 wl_list_init(&configured_output_list);
2434
2435 const struct config_key drm_config_keys[] = {
2436 { "name", CONFIG_KEY_STRING, &output_name },
2437 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002438 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002439 };
2440
2441 const struct config_section config_section[] = {
2442 { "output", drm_config_keys,
2443 ARRAY_LENGTH(drm_config_keys), output_section_done },
2444 };
2445
2446 parse_config_file(config_file, config_section,
2447 ARRAY_LENGTH(config_section), NULL);
2448
Daniel Stonec1be8e52012-06-01 11:14:02 -04002449 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2450 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002451}