blob: 9c9d54a4de4887ce913fa590ca843691cc77117a [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020043#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010044#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Kristian Høgsberg061c4252012-06-28 11:28:15 -040046static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060047static char *output_name;
48static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060049static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060050static struct wl_list configured_output_list;
51
52enum output_config {
53 OUTPUT_CONFIG_INVALID = 0,
54 OUTPUT_CONFIG_OFF,
55 OUTPUT_CONFIG_PREFERRED,
56 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060057 OUTPUT_CONFIG_MODE,
58 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060059};
60
61struct drm_configured_output {
62 char *name;
63 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060064 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060066 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060067 enum output_config config;
68 struct wl_list link;
69};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040070
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050072 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
74 struct udev *udev;
75 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010077 struct udev_monitor *udev_monitor;
78 struct wl_event_source *udev_drm_source;
79
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010081 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 int fd;
83 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020084 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050085 uint32_t *crtcs;
86 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050087 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010088 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050089 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Kristian Høgsberg8a015802012-08-09 17:19:23 -040095 int32_t min_width, max_width;
96 int32_t min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -050097
Jesse Barnes58ef3792012-02-23 09:45:49 -050098 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050099 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200100 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101
Rob Clarkab5b1e32012-08-09 13:24:45 -0500102 int cursors_are_broken;
103
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200104 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400105};
106
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400107struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500108 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109 drmModeModeInfo mode_info;
110};
111
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300112struct drm_output;
113
114struct drm_fb {
115 struct gbm_bo *bo;
116 struct drm_output *output;
117 uint32_t fb_id;
118 int is_client_buffer;
119 struct wl_buffer *buffer;
120 struct wl_listener buffer_destroy_listener;
121};
122
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400123struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500124 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400126 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400127 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500128 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400129 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700130 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200131
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300132 int vblank_pending;
133 int page_flip_pending;
134
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400135 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400136 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400137 struct weston_plane cursor_plane;
138 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400139 struct weston_surface *cursor_surface;
140 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300141 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200142 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143};
144
Jesse Barnes58ef3792012-02-23 09:45:49 -0500145/*
146 * An output has a primary display plane plus zero or more sprites for
147 * blending display contents.
148 */
149struct drm_sprite {
150 struct wl_list link;
151
152 uint32_t fb_id;
153 uint32_t pending_fb_id;
154 struct weston_surface *surface;
155 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400156 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500157
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300158 struct drm_output *output;
159
Jesse Barnes58ef3792012-02-23 09:45:49 -0500160 struct drm_compositor *compositor;
161
162 struct wl_listener destroy_listener;
163 struct wl_listener pending_destroy_listener;
164
165 uint32_t possible_crtcs;
166 uint32_t plane_id;
167 uint32_t count_formats;
168
169 int32_t src_x, src_y;
170 uint32_t src_w, src_h;
171 uint32_t dest_x, dest_y;
172 uint32_t dest_w, dest_h;
173
174 uint32_t formats[];
175};
176
Pekka Paalanen33156972012-08-03 13:30:30 -0400177struct drm_seat {
178 struct weston_seat base;
179 struct wl_list devices_list;
180 struct udev_monitor *udev_monitor;
181 struct wl_event_source *udev_monitor_source;
182 char *seat_id;
183};
184
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400185static void
186drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400187
Jesse Barnes58ef3792012-02-23 09:45:49 -0500188static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500189drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
190{
191 struct weston_compositor *ec = output_base->compositor;
192 struct drm_compositor *c =(struct drm_compositor *) ec;
193 struct drm_output *output = (struct drm_output *) output_base;
194 int crtc;
195
196 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
197 if (c->crtcs[crtc] != output->crtc_id)
198 continue;
199
200 if (supported & (1 << crtc))
201 return -1;
202 }
203
204 return 0;
205}
206
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300207static void
208drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
209{
210 struct drm_fb *fb = data;
211 struct gbm_device *gbm = gbm_bo_get_device(bo);
212
213 if (fb->fb_id)
214 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
215
216 if (fb->buffer) {
217 weston_buffer_post_release(fb->buffer);
218 wl_list_remove(&fb->buffer_destroy_listener.link);
219 }
220
221 free(data);
222}
223
224static struct drm_fb *
Ander Conselvan de Oliveiraaf696af2012-11-09 14:19:04 +0200225drm_fb_get_from_bo(struct gbm_bo *bo)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300226{
227 struct drm_fb *fb = gbm_bo_get_user_data(bo);
228 struct drm_compositor *compositor =
229 (struct drm_compositor *) output->base.compositor;
230 uint32_t width, height, stride, handle;
231 int ret;
232
233 if (fb)
234 return fb;
235
236 fb = malloc(sizeof *fb);
237
238 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300239 fb->is_client_buffer = 0;
240 fb->buffer = NULL;
241
242 width = gbm_bo_get_width(bo);
243 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400244 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300245 handle = gbm_bo_get_handle(bo).u32;
246
247 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
248 stride, handle, &fb->fb_id);
249 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200250 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300251 free(fb);
252 return NULL;
253 }
254
255 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
256
257 return fb;
258}
259
260static void
261fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
262{
263 struct drm_fb *fb = container_of(listener, struct drm_fb,
264 buffer_destroy_listener);
265
266 fb->buffer = NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300267}
268
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400269static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400270drm_output_prepare_scanout_surface(struct weston_output *_output,
271 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500272{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400273 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500274 struct drm_compositor *c =
275 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300276 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500277
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500278 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200279 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200280 es->geometry.width != output->base.current->width ||
281 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200282 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400283 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400284 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500285
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400286 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
287 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500288
Rob Bradford9b101872012-09-14 23:25:41 +0100289 /* Unable to use the buffer for scanout */
290 if (!bo)
291 return NULL;
292
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300293 /* Need to verify output->region contained in surface opaque
294 * region. Or maybe just that format doesn't have alpha.
295 * For now, scanout only if format is XRGB8888. */
296 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
297 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400298 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300299 }
300
Ander Conselvan de Oliveiraaf696af2012-11-09 14:19:04 +0200301 output->next = drm_fb_get_from_bo(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300302 if (!output->next) {
303 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400304 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300305 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500306
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300307 output->next->is_client_buffer = 1;
308 output->next->buffer = es->buffer;
309 output->next->buffer->busy_count++;
310 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
311
312 wl_signal_add(&output->next->buffer->resource.destroy_signal,
313 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500314
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400315 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500316}
317
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500318static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400319drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400320{
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400321 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300322 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400323
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400324 ec->renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400325
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300326 bo = gbm_surface_lock_front_buffer(output->surface);
327 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200328 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400329 return;
330 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331
Ander Conselvan de Oliveiraaf696af2012-11-09 14:19:04 +0200332 output->next = drm_fb_get_from_bo(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300333 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200334 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300335 gbm_surface_release_buffer(output->surface, bo);
336 return;
337 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400338}
339
340static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500341drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400342 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100343{
344 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500345 struct drm_compositor *compositor =
346 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500347 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400348 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500349 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100350
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300351 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400352 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300353 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400354 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100355
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400356 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300357 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400358 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400360 &output->connector_id, 1,
361 &mode->mode_info);
362 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200363 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400364 return;
365 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200366 }
367
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500368 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300369 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500370 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200371 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500372 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500373 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100374
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300375 output->page_flip_pending = 1;
376
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400377 drm_output_set_cursor(output);
378
Jesse Barnes58ef3792012-02-23 09:45:49 -0500379 /*
380 * Now, update all the sprite surfaces
381 */
382 wl_list_for_each(s, &compositor->sprite_list, link) {
383 uint32_t flags = 0;
384 drmVBlank vbl = {
385 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
386 .request.sequence = 1,
387 };
388
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200389 if ((!s->fb_id && !s->pending_fb_id) ||
390 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500391 continue;
392
393 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200394 output->crtc_id,
395 compositor->sprites_hidden ?
396 0 : s->pending_fb_id,
397 flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500398 s->dest_x, s->dest_y,
399 s->dest_w, s->dest_h,
400 s->src_x, s->src_y,
401 s->src_w, s->src_h);
402 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200403 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500404 ret, strerror(errno));
405
Rob Clark5ca1a472012-08-08 20:27:37 -0500406 if (output->pipe > 0)
407 vbl.request.type |= DRM_VBLANK_SECONDARY;
408
Jesse Barnes58ef3792012-02-23 09:45:49 -0500409 /*
410 * Queue a vblank signal so we know when the surface
411 * becomes active on the display or has been replaced.
412 */
413 vbl.request.signal = (unsigned long)s;
414 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
415 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200416 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500417 ret, strerror(errno));
418 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300419
420 s->output = output;
421 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500422 }
423
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500424 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400425}
426
427static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500428vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
429 void *data)
430{
431 struct drm_sprite *s = (struct drm_sprite *)data;
432 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300433 struct drm_output *output = s->output;
434 uint32_t msecs;
435
436 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500437
438 if (s->surface) {
439 weston_buffer_post_release(s->surface->buffer);
440 wl_list_remove(&s->destroy_listener.link);
441 s->surface = NULL;
442 drmModeRmFB(c->drm.fd, s->fb_id);
443 s->fb_id = 0;
444 }
445
446 if (s->pending_surface) {
447 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400448 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
449 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500450 s->surface = s->pending_surface;
451 s->pending_surface = NULL;
452 s->fb_id = s->pending_fb_id;
453 s->pending_fb_id = 0;
454 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300455
456 if (!output->page_flip_pending) {
457 msecs = sec * 1000 + usec / 1000;
458 weston_output_finish_frame(&output->base, msecs);
459 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500460}
461
462static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400463page_flip_handler(int fd, unsigned int frame,
464 unsigned int sec, unsigned int usec, void *data)
465{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200466 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400467 uint32_t msecs;
468
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300469 output->page_flip_pending = 0;
470
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300471 if (output->current) {
472 if (output->current->is_client_buffer)
473 gbm_bo_destroy(output->current->bo);
474 else
475 gbm_surface_release_buffer(output->surface,
476 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200477 }
478
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300479 output->current = output->next;
480 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400481
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300482 if (!output->vblank_pending) {
483 msecs = sec * 1000 + usec / 1000;
484 weston_output_finish_frame(&output->base, msecs);
485 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200486}
487
488static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500489drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
490{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400491 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500492
493 for (i = 0; i < s->count_formats; i++)
494 if (s->formats[i] == format)
495 return 1;
496
497 return 0;
498}
499
500static int
501drm_surface_transform_supported(struct weston_surface *es)
502{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400503 struct weston_matrix *matrix = &es->transform.matrix;
504 int i;
505
506 if (!es->transform.enabled)
507 return 1;
508
509 for (i = 0; i < 16; i++) {
510 switch (i) {
511 case 10:
512 case 15:
513 if (matrix->d[i] != 1.0)
514 return 0;
515 break;
516 case 0:
517 case 5:
518 case 12:
519 case 13:
520 break;
521 default:
522 if (matrix->d[i] != 0.0)
523 return 0;
524 break;
525 }
526 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500527
528 return 1;
529}
530
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400531static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500532drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400533 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500534{
535 struct weston_compositor *ec = output_base->compositor;
536 struct drm_compositor *c =(struct drm_compositor *) ec;
537 struct drm_sprite *s;
538 int found = 0;
539 EGLint handle, stride;
540 struct gbm_bo *bo;
541 uint32_t fb_id = 0;
542 uint32_t handles[4], pitches[4], offsets[4];
543 int ret = 0;
544 pixman_region32_t dest_rect, src_rect;
545 pixman_box32_t *box;
546 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400547 wl_fixed_t sx1, sy1, sx2, sy2;
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400548 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500549
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500550 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400551 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500552
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300553 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400554 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300555
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400556 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400557 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500558
Rob Clark702ffae2012-08-09 14:18:27 -0500559 if (wl_buffer_is_shm(es->buffer))
560 return NULL;
561
Jesse Barnes58ef3792012-02-23 09:45:49 -0500562 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400563 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500564
Jesse Barnes58ef3792012-02-23 09:45:49 -0500565 wl_list_for_each(s, &c->sprite_list, link) {
566 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
567 continue;
568
569 if (!s->pending_fb_id) {
570 found = 1;
571 break;
572 }
573 }
574
575 /* No sprites available */
576 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400577 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578
Rob Clark4339add2012-08-09 14:18:28 -0500579 width = es->geometry.width;
580 height = es->geometry.height;
581
582 /* If geometry is out of bounds, don't even bother trying because
583 * we know the AddFB2() call will fail:
584 */
585 if (c->min_width > width || width > c->max_width ||
586 c->min_height > height || height > c->max_height)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400587 return NULL;
Rob Clark4339add2012-08-09 14:18:28 -0500588
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400589 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
590 es->buffer, GBM_BO_USE_SCANOUT);
591 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400592 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400593
Jesse Barnes58ef3792012-02-23 09:45:49 -0500594 format = gbm_bo_get_format(bo);
595 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400596 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500597
598 gbm_bo_destroy(bo);
599
600 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400601 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602
603 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400604 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605
606 handles[0] = handle;
607 pitches[0] = stride;
608 offsets[0] = 0;
609
Rob Clark4339add2012-08-09 14:18:28 -0500610 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611 format, handles, pitches, offsets,
612 &fb_id, 0);
613 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200614 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500615 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400616 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500617 }
618
Jesse Barnes58ef3792012-02-23 09:45:49 -0500619 s->pending_fb_id = fb_id;
620 s->pending_surface = es;
621 es->buffer->busy_count++;
622
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400623 box = pixman_region32_extents(&es->transform.boundingbox);
624 s->plane.x = box->x1;
625 s->plane.y = box->y1;
626
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 /*
628 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200629 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500630 * for us already).
631 */
632 pixman_region32_init(&dest_rect);
633 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
634 &output_base->region);
635 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
636 box = pixman_region32_extents(&dest_rect);
637 s->dest_x = box->x1;
638 s->dest_y = box->y1;
639 s->dest_w = box->x2 - box->x1;
640 s->dest_h = box->y2 - box->y1;
641 pixman_region32_fini(&dest_rect);
642
643 pixman_region32_init(&src_rect);
644 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
645 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500646 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400647
648 weston_surface_from_global_fixed(es,
649 wl_fixed_from_int(box->x1),
650 wl_fixed_from_int(box->y1),
651 &sx1, &sy1);
652 weston_surface_from_global_fixed(es,
653 wl_fixed_from_int(box->x2),
654 wl_fixed_from_int(box->y2),
655 &sx2, &sy2);
656
657 if (sx1 < 0)
658 sx1 = 0;
659 if (sy1 < 0)
660 sy1 = 0;
661 if (sx2 > wl_fixed_from_int(es->geometry.width))
662 sx2 = wl_fixed_from_int(es->geometry.width);
663 if (sy2 > wl_fixed_from_int(es->geometry.height))
664 sy2 = wl_fixed_from_int(es->geometry.height);
665
666 s->src_x = sx1 << 8;
667 s->src_y = sy1 << 8;
668 s->src_w = (sx2 - sx1) << 8;
669 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500670 pixman_region32_fini(&src_rect);
671
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400672 wl_signal_add(&es->buffer->resource.destroy_signal,
673 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400674
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400675 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500676}
677
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400678static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400679drm_output_prepare_cursor_surface(struct weston_output *output_base,
680 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500681{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400682 struct drm_compositor *c =
683 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400684 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400685
686 if (output->cursor_surface)
687 return NULL;
688 if (es->output_mask != (1u << output_base->id))
689 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500690 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400691 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400692 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
693 es->geometry.width > 64 || es->geometry.height > 64)
694 return NULL;
695
696 output->cursor_surface = es;
697
698 return &output->cursor_plane;
699}
700
701static void
702drm_output_set_cursor(struct drm_output *output)
703{
704 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400705 struct drm_compositor *c =
706 (struct drm_compositor *) output->base.compositor;
707 EGLint handle, stride;
708 struct gbm_bo *bo;
709 uint32_t buf[64 * 64];
710 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400711 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500712
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400713 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400714 if (es == NULL) {
715 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
716 return;
717 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500718
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400719 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
720 pixman_region32_fini(&output->cursor_plane.damage);
721 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400722 output->current_cursor ^= 1;
723 bo = output->cursor_bo[output->current_cursor];
724 memset(buf, 0, sizeof buf);
725 stride = wl_shm_buffer_get_stride(es->buffer);
726 s = wl_shm_buffer_get_data(es->buffer);
727 for (i = 0; i < es->geometry.height; i++)
728 memcpy(buf + i * 64, s + i * stride,
729 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500730
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400731 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300732 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400733
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400734 handle = gbm_bo_get_handle(bo).s32;
735 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500736 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300737 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500738 c->cursors_are_broken = 1;
739 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400740 }
741
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400742 x = es->geometry.x - output->base.x;
743 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400744 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500745 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400746 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500747 c->cursors_are_broken = 1;
748 }
749
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400750 output->cursor_plane.x = x;
751 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400752 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500753}
754
Jesse Barnes58ef3792012-02-23 09:45:49 -0500755static void
756drm_assign_planes(struct weston_output *output)
757{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400758 struct drm_compositor *c =
759 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200760 struct drm_output *drm_output = (struct drm_output *) output;
761 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400762 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500763 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400764 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500765
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200766 /* Reset the opaque region of the planes */
767 pixman_region32_fini(&drm_output->cursor_plane.opaque);
768 pixman_region32_init(&drm_output->cursor_plane.opaque);
769 pixman_region32_fini(&drm_output->fb_plane.opaque);
770 pixman_region32_init(&drm_output->fb_plane.opaque);
771
772 wl_list_for_each (s, &c->sprite_list, link) {
773 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
774 continue;
775
776 pixman_region32_fini(&s->plane.opaque);
777 pixman_region32_init(&s->plane.opaque);
778 }
779
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780 /*
781 * Find a surface for each sprite in the output using some heuristics:
782 * 1) size
783 * 2) frequency of update
784 * 3) opacity (though some hw might support alpha blending)
785 * 4) clipping (this can be fixed with color keys)
786 *
787 * The idea is to save on blitting since this should save power.
788 * If we can get a large video surface on the sprite for example,
789 * the main display surface may not need to update at all, and
790 * the client buffer can be used directly for the sprite surface
791 * as we do for flipping full screen surfaces.
792 */
793 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400794 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400795 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796 pixman_region32_init(&surface_overlap);
797 pixman_region32_intersect(&surface_overlap, &overlap,
798 &es->transform.boundingbox);
799
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400800 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400801 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400802 next_plane = primary;
803 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400804 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400805 if (next_plane == NULL)
806 next_plane = drm_output_prepare_scanout_surface(output, es);
807 if (next_plane == NULL)
808 next_plane = drm_output_prepare_overlay_surface(output, es);
809 if (next_plane == NULL)
810 next_plane = primary;
811 weston_surface_move_to_plane(es, next_plane);
812 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500813 pixman_region32_union(&overlap, &overlap,
814 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400815
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816 pixman_region32_fini(&surface_overlap);
817 }
818 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500819}
820
Matt Roper361d2ad2011-08-29 13:52:23 -0700821static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500822drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700823{
824 struct drm_output *output = (struct drm_output *) output_base;
825 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200826 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700827 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700828
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200829 if (output->backlight)
830 backlight_destroy(output->backlight);
831
Matt Roper361d2ad2011-08-29 13:52:23 -0700832 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400833 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700834
835 /* Restore original CRTC state */
836 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200837 origcrtc->x, origcrtc->y,
838 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700839 drmModeFreeCrtc(origcrtc);
840
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200841 c->crtc_allocator &= ~(1 << output->crtc_id);
842 c->connector_allocator &= ~(1 << output->connector_id);
843
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400844 eglDestroySurface(c->base.egl_display, output->base.egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400845 gbm_surface_destroy(output->surface);
846
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400847 weston_plane_release(&output->fb_plane);
848 weston_plane_release(&output->cursor_plane);
849
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500850 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200851 wl_list_remove(&output->base.link);
852
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400853 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700854 free(output);
855}
856
Alex Wub7b8bda2012-04-17 17:20:48 +0800857static struct drm_mode *
858choose_mode (struct drm_output *output, struct weston_mode *target_mode)
859{
860 struct drm_mode *tmp_mode = NULL, *mode;
861
862 if (output->base.current->width == target_mode->width &&
863 output->base.current->height == target_mode->height &&
864 (output->base.current->refresh == target_mode->refresh ||
865 target_mode->refresh == 0))
866 return (struct drm_mode *)output->base.current;
867
868 wl_list_for_each(mode, &output->base.mode_list, base.link) {
869 if (mode->mode_info.hdisplay == target_mode->width &&
870 mode->mode_info.vdisplay == target_mode->height) {
871 if (mode->mode_info.vrefresh == target_mode->refresh ||
872 target_mode->refresh == 0) {
873 return mode;
874 } else if (!tmp_mode)
875 tmp_mode = mode;
876 }
877 }
878
879 return tmp_mode;
880}
881
882static int
883drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
884{
885 struct drm_output *output;
886 struct drm_mode *drm_mode;
887 int ret;
888 struct drm_compositor *ec;
889 struct gbm_surface *surface;
890 EGLSurface egl_surface;
891
892 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200893 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800894 return -1;
895 }
896
897 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200898 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800899 return -1;
900 }
901
902 ec = (struct drm_compositor *)output_base->compositor;
903 output = (struct drm_output *)output_base;
904 drm_mode = choose_mode (output, mode);
905
906 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200907 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800908 return -1;
909 } else if (&drm_mode->base == output->base.current) {
910 return 0;
911 } else if (drm_mode->base.width == output->base.current->width &&
912 drm_mode->base.height == output->base.current->height) {
913 /* only change refresh value */
914 ret = drmModeSetCrtc(ec->drm.fd,
915 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300916 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800917 &output->connector_id, 1, &drm_mode->mode_info);
918
919 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200920 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800921 drm_mode->base.width,
922 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400923 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800924 ret = -1;
925 } else {
926 output->base.current->flags = 0;
927 output->base.current = &drm_mode->base;
928 drm_mode->base.flags =
929 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
930 ret = 0;
931 }
932
933 return ret;
934 }
935
936 drm_mode->base.flags =
937 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
938
939 surface = gbm_surface_create(ec->gbm,
940 drm_mode->base.width,
941 drm_mode->base.height,
942 GBM_FORMAT_XRGB8888,
943 GBM_BO_USE_SCANOUT |
944 GBM_BO_USE_RENDERING);
945 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200946 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800947 return -1;
948 }
949
950 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400951 eglCreateWindowSurface(ec->base.egl_display,
952 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800953 surface, NULL);
954
955 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200956 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800957 goto err;
958 }
959
960 ret = drmModeSetCrtc(ec->drm.fd,
961 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300962 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800963 &output->connector_id, 1, &drm_mode->mode_info);
964 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200965 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800966 goto err;
967 }
968
969 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300970 if (output->current) {
971 if (output->current->is_client_buffer)
972 gbm_bo_destroy(output->current->bo);
973 else
974 gbm_surface_release_buffer(output->surface,
975 output->current->bo);
976 }
977 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800978
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300979 if (output->next) {
980 if (output->next->is_client_buffer)
981 gbm_bo_destroy(output->next->bo);
982 else
983 gbm_surface_release_buffer(output->surface,
984 output->next->bo);
985 }
986 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800987
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400988 eglDestroySurface(ec->base.egl_display, output->base.egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800989 gbm_surface_destroy(output->surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400990 output->base.egl_surface = egl_surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800991 output->surface = surface;
992
993 /*update output*/
994 output->base.current = &drm_mode->base;
995 output->base.dirty = 1;
996 weston_output_move(&output->base, output->base.x, output->base.y);
997 return 0;
998
999err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001000 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001001 gbm_surface_destroy(surface);
1002 return -1;
1003}
1004
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001005static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001006on_drm_input(int fd, uint32_t mask, void *data)
1007{
1008 drmEventContext evctx;
1009
1010 memset(&evctx, 0, sizeof evctx);
1011 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1012 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001013 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001014 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001015
1016 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001017}
1018
1019static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001020init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001021{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001022 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001023 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001024 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001025 static const EGLint config_attribs[] = {
1026 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1027 EGL_RED_SIZE, 1,
1028 EGL_GREEN_SIZE, 1,
1029 EGL_BLUE_SIZE, 1,
1030 EGL_ALPHA_SIZE, 0,
1031 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1032 EGL_NONE
1033 };
1034
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001035 sysnum = udev_device_get_sysnum(device);
1036 if (sysnum)
1037 ec->drm.id = atoi(sysnum);
1038 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001039 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001040 return -1;
1041 }
1042
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001043 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001044 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001045 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001046 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001047 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001048 udev_device_get_devnode(device));
1049 return -1;
1050 }
1051
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001052 weston_log("using %s\n", filename);
1053
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001054 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001055 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001056 ec->base.egl_display = eglGetDisplay(ec->gbm);
1057 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001058 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001059 return -1;
1060 }
1061
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001062 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001063 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001064 return -1;
1065 }
1066
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001067 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1068 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001069 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001070 return -1;
1071 }
1072
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001073 return 0;
1074}
1075
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001076static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001077drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1078{
1079 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001080 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001081
1082 mode = malloc(sizeof *mode);
1083 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001084 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001085
1086 mode->base.flags = 0;
1087 mode->base.width = info->hdisplay;
1088 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001089
1090 /* Calculate higher precision (mHz) refresh rate */
1091 refresh = (info->clock * 1000000LL / info->htotal +
1092 info->vtotal / 2) / info->vtotal;
1093
1094 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1095 refresh *= 2;
1096 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1097 refresh /= 2;
1098 if (info->vscan > 1)
1099 refresh /= info->vscan;
1100
1101 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001102 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001103
1104 if (info->type & DRM_MODE_TYPE_PREFERRED)
1105 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1106
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001107 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1108
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001109 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001110}
1111
1112static int
1113drm_subpixel_to_wayland(int drm_value)
1114{
1115 switch (drm_value) {
1116 default:
1117 case DRM_MODE_SUBPIXEL_UNKNOWN:
1118 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1119 case DRM_MODE_SUBPIXEL_NONE:
1120 return WL_OUTPUT_SUBPIXEL_NONE;
1121 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1122 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1123 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1124 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1125 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1126 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1127 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1128 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1129 }
1130}
1131
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001132static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001133sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001134{
1135 struct drm_sprite *sprite =
1136 container_of(listener, struct drm_sprite,
1137 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001138 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001139
1140 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001141 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1142 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001143}
1144
1145static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001146sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001147{
1148 struct drm_sprite *sprite =
1149 container_of(listener, struct drm_sprite,
1150 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001151 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001152
1153 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001154 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1155 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001156}
1157
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001158/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001159static uint32_t
1160drm_get_backlight(struct drm_output *output)
1161{
1162 long brightness, max_brightness, norm;
1163
1164 brightness = backlight_get_brightness(output->backlight);
1165 max_brightness = backlight_get_max_brightness(output->backlight);
1166
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001167 /* convert it on a scale of 0 to 255 */
1168 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001169
1170 return (uint32_t) norm;
1171}
1172
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001173/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001174static void
1175drm_set_backlight(struct weston_output *output_base, uint32_t value)
1176{
1177 struct drm_output *output = (struct drm_output *) output_base;
1178 long max_brightness, new_brightness;
1179
1180 if (!output->backlight)
1181 return;
1182
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001183 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001184 return;
1185
1186 max_brightness = backlight_get_max_brightness(output->backlight);
1187
1188 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001189 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001190
1191 backlight_set_brightness(output->backlight, new_brightness);
1192}
1193
1194static drmModePropertyPtr
1195drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1196{
1197 drmModePropertyPtr props;
1198 int i;
1199
1200 for (i = 0; i < connector->count_props; i++) {
1201 props = drmModeGetProperty(fd, connector->props[i]);
1202 if (!props)
1203 continue;
1204
1205 if (!strcmp(props->name, name))
1206 return props;
1207
1208 drmModeFreeProperty(props);
1209 }
1210
1211 return NULL;
1212}
1213
1214static void
1215drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1216{
1217 struct drm_output *output = (struct drm_output *) output_base;
1218 struct weston_compositor *ec = output_base->compositor;
1219 struct drm_compositor *c = (struct drm_compositor *) ec;
1220 drmModeConnectorPtr connector;
1221 drmModePropertyPtr prop;
1222
1223 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1224 if (!connector)
1225 return;
1226
1227 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1228 if (!prop) {
1229 drmModeFreeConnector(connector);
1230 return;
1231 }
1232
1233 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1234 prop->prop_id, level);
1235 drmModeFreeProperty(prop);
1236 drmModeFreeConnector(connector);
1237}
1238
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001239static const char *connector_type_names[] = {
1240 "None",
1241 "VGA",
1242 "DVI",
1243 "DVI",
1244 "DVI",
1245 "Composite",
1246 "TV",
1247 "LVDS",
1248 "CTV",
1249 "DIN",
1250 "DP",
1251 "HDMI",
1252 "HDMI",
1253 "TV",
1254 "eDP",
1255};
1256
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001257static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001258find_crtc_for_connector(struct drm_compositor *ec,
1259 drmModeRes *resources, drmModeConnector *connector)
1260{
1261 drmModeEncoder *encoder;
1262 uint32_t possible_crtcs;
1263 int i, j;
1264
1265 for (j = 0; j < connector->count_encoders; j++) {
1266 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1267 if (encoder == NULL) {
1268 weston_log("Failed to get encoder.\n");
1269 return -1;
1270 }
1271 possible_crtcs = encoder->possible_crtcs;
1272 drmModeFreeEncoder(encoder);
1273
1274 for (i = 0; i < resources->count_crtcs; i++) {
1275 if (possible_crtcs & (1 << i) &&
1276 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1277 return i;
1278 }
1279 }
1280
1281 return -1;
1282}
1283
1284static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001285create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001286 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001287 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001288 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001289{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001290 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001291 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1292 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001293 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001294 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001295 drmModeModeInfo crtc_mode;
1296 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001297 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001298 char name[32];
1299 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001300
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001301 i = find_crtc_for_connector(ec, resources, connector);
1302 if (i < 0) {
1303 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001304 return -1;
1305 }
1306
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001307 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001308 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001309 return -1;
1310
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001311 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1313 output->base.make = "unknown";
1314 output->base.model = "unknown";
1315 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001316
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001317 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1318 type_name = connector_type_names[connector->connector_type];
1319 else
1320 type_name = "UNKNOWN";
1321 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1322 output->name = strdup(name);
1323
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001324 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001325 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001326 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001327 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001328 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001329
Matt Roper361d2ad2011-08-29 13:52:23 -07001330 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1331
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001332 /* Get the current mode on the crtc that's currently driving
1333 * this connector. */
1334 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001335 memset(&crtc_mode, 0, sizeof crtc_mode);
1336 if (encoder != NULL) {
1337 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1338 drmModeFreeEncoder(encoder);
1339 if (crtc == NULL)
1340 goto err_free;
1341 if (crtc->mode_valid)
1342 crtc_mode = crtc->mode;
1343 drmModeFreeCrtc(crtc);
1344 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001345
David Herrmann0f0d54e2011-12-08 17:05:45 +01001346 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001347 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1348 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001349 goto err_free;
1350 }
1351
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001352 preferred = NULL;
1353 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001354 configured = NULL;
1355
1356 wl_list_for_each(temp, &configured_output_list, link) {
1357 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001358 if (temp->mode)
1359 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001360 temp->name, temp->mode);
1361 o = temp;
1362 break;
1363 }
1364 }
1365
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001366 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001367 weston_log("Disabling output %s\n", o->name);
1368
1369 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1370 0, 0, 0, 0, 0, NULL);
1371 goto err_free;
1372 }
1373
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001374 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001375 if (o && o->config == OUTPUT_CONFIG_MODE &&
1376 o->width == drm_mode->base.width &&
1377 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001378 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001379 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001380 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001381 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001382 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001383 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001384
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001385 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001386 configured = drm_output_add_mode(output, &o->crtc_mode);
1387 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001388 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001389 current = configured;
1390 }
1391
Wang Quanxianacb805a2012-07-30 18:09:46 -04001392 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001393 current = drm_output_add_mode(output, &crtc_mode);
1394 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001395 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001396 }
1397
Scott Moreau8ab5d452012-07-30 19:51:08 -06001398 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1399 configured = current;
1400
Wang Quanxianacb805a2012-07-30 18:09:46 -04001401 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001402 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001403 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001404 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001405 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001406 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001407 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001408 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001409
1410 if (output->base.current == NULL) {
1411 weston_log("no available modes for %s\n", output->name);
1412 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001413 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001414
Wang Quanxianacb805a2012-07-30 18:09:46 -04001415 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1416
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001417 output->surface = gbm_surface_create(ec->gbm,
1418 output->base.current->width,
1419 output->base.current->height,
1420 GBM_FORMAT_XRGB8888,
1421 GBM_BO_USE_SCANOUT |
1422 GBM_BO_USE_RENDERING);
1423 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001424 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001425 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001426 }
1427
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001428 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001429 eglCreateWindowSurface(ec->base.egl_display,
1430 ec->base.egl_config,
1431 output->surface,
1432 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001433 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001434 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001435 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001436 }
1437
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001438 output->cursor_bo[0] =
1439 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1440 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1441 output->cursor_bo[1] =
1442 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1443 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001444 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1445 weston_log("cursor buffers unavailable, using gl cursors\n");
1446 ec->cursors_are_broken = 1;
1447 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001448
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001449 output->backlight = backlight_init(drm_device,
1450 connector->connector_type);
1451 if (output->backlight) {
1452 output->base.set_backlight = drm_set_backlight;
1453 output->base.backlight_current = drm_get_backlight(output);
1454 }
1455
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001456 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001457 connector->mmWidth, connector->mmHeight,
1458 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001459
1460 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1461
Alex Wubd3354b2012-04-17 17:20:49 +08001462 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001463 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001464 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001465 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001466 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001467 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001468
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001469 weston_plane_init(&output->cursor_plane, 0, 0);
1470 weston_plane_init(&output->fb_plane, 0, 0);
1471
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001472 weston_log("Output %s, (connector %d, crtc %d)\n",
1473 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001474 wl_list_for_each(m, &output->base.mode_list, link)
1475 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1476 m->width, m->height, m->refresh / 1000.0,
1477 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1478 ", preferred" : "",
1479 m->flags & WL_OUTPUT_MODE_CURRENT ?
1480 ", current" : "",
1481 connector->count_modes == 0 ?
1482 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001483
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001484 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001485
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001486err_surface:
1487 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001488err_free:
1489 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1490 base.link) {
1491 wl_list_remove(&drm_mode->base.link);
1492 free(drm_mode);
1493 }
1494
1495 drmModeFreeCrtc(output->original_crtc);
1496 ec->crtc_allocator &= ~(1 << output->crtc_id);
1497 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001498 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001499 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001500
David Herrmann0f0d54e2011-12-08 17:05:45 +01001501 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001502}
1503
Jesse Barnes58ef3792012-02-23 09:45:49 -05001504static void
1505create_sprites(struct drm_compositor *ec)
1506{
1507 struct drm_sprite *sprite;
1508 drmModePlaneRes *plane_res;
1509 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001510 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001511
1512 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1513 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001514 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001515 strerror(errno));
1516 return;
1517 }
1518
1519 for (i = 0; i < plane_res->count_planes; i++) {
1520 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1521 if (!plane)
1522 continue;
1523
1524 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1525 plane->count_formats));
1526 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001527 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001528 __func__);
1529 free(plane);
1530 continue;
1531 }
1532
1533 memset(sprite, 0, sizeof *sprite);
1534
1535 sprite->possible_crtcs = plane->possible_crtcs;
1536 sprite->plane_id = plane->plane_id;
1537 sprite->surface = NULL;
1538 sprite->pending_surface = NULL;
1539 sprite->fb_id = 0;
1540 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001541 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1542 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001543 sprite_handle_pending_buffer_destroy;
1544 sprite->compositor = ec;
1545 sprite->count_formats = plane->count_formats;
1546 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001547 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001548 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001549 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001550
1551 wl_list_insert(&ec->sprite_list, &sprite->link);
1552 }
1553
1554 free(plane_res->planes);
1555 free(plane_res);
1556}
1557
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001558static void
1559destroy_sprites(struct drm_compositor *compositor)
1560{
1561 struct drm_sprite *sprite, *next;
1562 struct drm_output *output;
1563
1564 output = container_of(compositor->base.output_list.next,
1565 struct drm_output, base.link);
1566
1567 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1568 drmModeSetPlane(compositor->drm.fd,
1569 sprite->plane_id,
1570 output->crtc_id, 0, 0,
1571 0, 0, 0, 0, 0, 0, 0, 0);
1572 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001573 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001574 free(sprite);
1575 }
1576}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001577
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001578static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001579create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001580 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001581{
1582 drmModeConnector *connector;
1583 drmModeRes *resources;
1584 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001585 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001586
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001587 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001588 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001589 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001590 return -1;
1591 }
1592
Jesse Barnes58ef3792012-02-23 09:45:49 -05001593 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001594 if (!ec->crtcs) {
1595 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001596 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001597 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001598
Rob Clark4339add2012-08-09 14:18:28 -05001599 ec->min_width = resources->min_width;
1600 ec->max_width = resources->max_width;
1601 ec->min_height = resources->min_height;
1602 ec->max_height = resources->max_height;
1603
Jesse Barnes58ef3792012-02-23 09:45:49 -05001604 ec->num_crtcs = resources->count_crtcs;
1605 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1606
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001607 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001608 connector = drmModeGetConnector(ec->drm.fd,
1609 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001610 if (connector == NULL)
1611 continue;
1612
1613 if (connector->connection == DRM_MODE_CONNECTED &&
1614 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001615 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001616 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001617 connector, x, y,
1618 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001619 drmModeFreeConnector(connector);
1620 continue;
1621 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001622
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001623 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001624 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001625 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001626 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001627
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001628 drmModeFreeConnector(connector);
1629 }
1630
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001631 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001632 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001633 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001634 return -1;
1635 }
1636
1637 drmModeFreeResources(resources);
1638
1639 return 0;
1640}
1641
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001642static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001643update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001644{
1645 drmModeConnector *connector;
1646 drmModeRes *resources;
1647 struct drm_output *output, *next;
1648 int x = 0, y = 0;
1649 int x_offset = 0, y_offset = 0;
1650 uint32_t connected = 0, disconnects = 0;
1651 int i;
1652
1653 resources = drmModeGetResources(ec->drm.fd);
1654 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001655 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001656 return;
1657 }
1658
1659 /* collect new connects */
1660 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001661 int connector_id = resources->connectors[i];
1662
1663 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001664 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001665 continue;
1666
David Herrmann7551cff2011-12-08 17:05:43 +01001667 if (connector->connection != DRM_MODE_CONNECTED) {
1668 drmModeFreeConnector(connector);
1669 continue;
1670 }
1671
Benjamin Franzke117483d2011-08-30 11:38:26 +02001672 connected |= (1 << connector_id);
1673
1674 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001675 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001676 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001677 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678
1679 /* XXX: not yet needed, we die with 0 outputs */
1680 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001681 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001682 else
1683 x = 0;
1684 y = 0;
1685 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001686 connector, x, y,
1687 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001688 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001689
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001690 }
1691 drmModeFreeConnector(connector);
1692 }
1693 drmModeFreeResources(resources);
1694
1695 disconnects = ec->connector_allocator & ~connected;
1696 if (disconnects) {
1697 wl_list_for_each_safe(output, next, &ec->base.output_list,
1698 base.link) {
1699 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001700 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001701 output->base.x - x_offset,
1702 output->base.y - y_offset);
1703 }
1704
1705 if (disconnects & (1 << output->connector_id)) {
1706 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001707 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001708 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001709 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001710 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001711 }
1712 }
1713 }
1714
1715 /* FIXME: handle zero outputs, without terminating */
1716 if (ec->connector_allocator == 0)
1717 wl_display_terminate(ec->base.wl_display);
1718}
1719
1720static int
David Herrmannd7488c22012-03-11 20:05:21 +01001721udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001722{
David Herrmannd7488c22012-03-11 20:05:21 +01001723 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001724 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001725
1726 sysnum = udev_device_get_sysnum(device);
1727 if (!sysnum || atoi(sysnum) != ec->drm.id)
1728 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001729
David Herrmann6ac52db2012-03-11 20:05:22 +01001730 val = udev_device_get_property_value(device, "HOTPLUG");
1731 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001732 return 0;
1733
David Herrmann6ac52db2012-03-11 20:05:22 +01001734 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001735}
1736
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001737static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001738udev_drm_event(int fd, uint32_t mask, void *data)
1739{
1740 struct drm_compositor *ec = data;
1741 struct udev_device *event;
1742
1743 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001744
David Herrmannd7488c22012-03-11 20:05:21 +01001745 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001746 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001747
1748 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001749
1750 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001751}
1752
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001753static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001754drm_restore(struct weston_compositor *ec)
1755{
1756 struct drm_compositor *d = (struct drm_compositor *) ec;
1757
1758 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1759 weston_log("failed to drop master: %m\n");
1760 tty_reset(d->tty);
1761}
1762
Pekka Paalanen33156972012-08-03 13:30:30 -04001763static const char default_seat[] = "seat0";
1764
1765static void
1766device_added(struct udev_device *udev_device, struct drm_seat *master)
1767{
1768 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001769 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001770 const char *devnode;
1771 const char *device_seat;
1772 int fd;
1773
1774 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1775 if (!device_seat)
1776 device_seat = default_seat;
1777
1778 if (strcmp(device_seat, master->seat_id))
1779 return;
1780
1781 c = master->base.compositor;
1782 devnode = udev_device_get_devnode(udev_device);
1783
1784 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001785 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001786 * read. mtdev_get() also expects this. */
1787 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1788 if (fd < 0) {
1789 weston_log("opening input device '%s' failed.\n", devnode);
1790 return;
1791 }
1792
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001793 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001794 if (!device) {
1795 close(fd);
1796 weston_log("not using input device '%s'.\n", devnode);
1797 return;
1798 }
1799
1800 wl_list_insert(master->devices_list.prev, &device->link);
1801}
1802
1803static void
1804evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1805{
1806 struct drm_seat *seat = (struct drm_seat *) seat_base;
1807 struct udev_enumerate *e;
1808 struct udev_list_entry *entry;
1809 struct udev_device *device;
1810 const char *path, *sysname;
1811
1812 e = udev_enumerate_new(udev);
1813 udev_enumerate_add_match_subsystem(e, "input");
1814 udev_enumerate_scan_devices(e);
1815 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1816 path = udev_list_entry_get_name(entry);
1817 device = udev_device_new_from_syspath(udev, path);
1818
1819 sysname = udev_device_get_sysname(device);
1820 if (strncmp("event", sysname, 5) != 0) {
1821 udev_device_unref(device);
1822 continue;
1823 }
1824
1825 device_added(device, seat);
1826
1827 udev_device_unref(device);
1828 }
1829 udev_enumerate_unref(e);
1830
1831 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1832
1833 if (wl_list_empty(&seat->devices_list)) {
1834 weston_log(
1835 "warning: no input devices on entering Weston. "
1836 "Possible causes:\n"
1837 "\t- no permissions to read /dev/input/event*\n"
1838 "\t- seats misconfigured "
1839 "(Weston backend option 'seat', "
1840 "udev device property ID_SEAT)\n");
1841 }
1842}
1843
1844static int
1845evdev_udev_handler(int fd, uint32_t mask, void *data)
1846{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001847 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001848 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001849 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001850 const char *action;
1851 const char *devnode;
1852
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001853 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001854 if (!udev_device)
1855 return 1;
1856
1857 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001858 if (!action)
1859 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001860
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001861 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1862 goto out;
1863
1864 if (!strcmp(action, "add")) {
1865 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001866 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001867 else if (!strcmp(action, "remove")) {
1868 devnode = udev_device_get_devnode(udev_device);
1869 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1870 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001871 weston_log("input device %s, %s removed\n",
1872 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001873 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001874 break;
1875 }
1876 }
1877
1878out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001879 udev_device_unref(udev_device);
1880
1881 return 0;
1882}
1883
1884static int
1885evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1886{
1887 struct drm_seat *master = (struct drm_seat *) seat_base;
1888 struct wl_event_loop *loop;
1889 struct weston_compositor *c = master->base.compositor;
1890 int fd;
1891
1892 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1893 if (!master->udev_monitor) {
1894 weston_log("udev: failed to create the udev monitor\n");
1895 return 0;
1896 }
1897
1898 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1899 "input", NULL);
1900
1901 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1902 weston_log("udev: failed to bind the udev monitor\n");
1903 udev_monitor_unref(master->udev_monitor);
1904 return 0;
1905 }
1906
1907 loop = wl_display_get_event_loop(c->wl_display);
1908 fd = udev_monitor_get_fd(master->udev_monitor);
1909 master->udev_monitor_source =
1910 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1911 evdev_udev_handler, master);
1912 if (!master->udev_monitor_source) {
1913 udev_monitor_unref(master->udev_monitor);
1914 return 0;
1915 }
1916
1917 return 1;
1918}
1919
1920static void
1921evdev_disable_udev_monitor(struct weston_seat *seat_base)
1922{
1923 struct drm_seat *seat = (struct drm_seat *) seat_base;
1924
1925 if (!seat->udev_monitor)
1926 return;
1927
1928 udev_monitor_unref(seat->udev_monitor);
1929 seat->udev_monitor = NULL;
1930 wl_event_source_remove(seat->udev_monitor_source);
1931 seat->udev_monitor_source = NULL;
1932}
1933
1934static void
1935drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1936{
1937 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001938 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001939
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001940 wl_list_for_each(device, &seat->devices_list, link)
1941 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001942}
1943
1944static void
1945evdev_input_create(struct weston_compositor *c, struct udev *udev,
1946 const char *seat_id)
1947{
1948 struct drm_seat *seat;
1949
1950 seat = malloc(sizeof *seat);
1951 if (seat == NULL)
1952 return;
1953
1954 memset(seat, 0, sizeof *seat);
1955 weston_seat_init(&seat->base, c);
1956 seat->base.led_update = drm_led_update;
1957
1958 wl_list_init(&seat->devices_list);
1959 seat->seat_id = strdup(seat_id);
1960 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1961 free(seat->seat_id);
1962 free(seat);
1963 return;
1964 }
1965
1966 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001967}
1968
1969static void
1970evdev_remove_devices(struct weston_seat *seat_base)
1971{
1972 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001973 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001974
1975 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001976 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001977
Pekka Paalanend8583512012-08-03 14:39:11 +03001978 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001979 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001980}
1981
1982static void
1983evdev_input_destroy(struct weston_seat *seat_base)
1984{
1985 struct drm_seat *seat = (struct drm_seat *) seat_base;
1986
1987 evdev_remove_devices(seat_base);
1988 evdev_disable_udev_monitor(&seat->base);
1989
1990 weston_seat_release(seat_base);
1991 free(seat->seat_id);
1992 free(seat);
1993}
1994
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001995static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001996drm_free_configured_output(struct drm_configured_output *output)
1997{
1998 free(output->name);
1999 free(output->mode);
2000 free(output);
2001}
2002
2003static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002004drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002005{
2006 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002007 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002008 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002009
Daniel Stone37816df2012-05-16 18:45:18 +01002010 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2011 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002012 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002013 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002014
2015 wl_event_source_remove(d->udev_drm_source);
2016 wl_event_source_remove(d->drm_source);
2017
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002018 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002019
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002020 gles2_renderer_destroy(ec);
2021
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002022 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002023 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002024 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002025 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002026 eglReleaseThread();
2027
Matt Roper361d2ad2011-08-29 13:52:23 -07002028 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002029 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002030 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002031 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002032 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002033
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002034 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002035}
2036
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002037static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002038drm_compositor_set_modes(struct drm_compositor *compositor)
2039{
2040 struct drm_output *output;
2041 struct drm_mode *drm_mode;
2042 int ret;
2043
2044 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2045 drm_mode = (struct drm_mode *) output->base.current;
2046 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002047 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002048 &output->connector_id, 1,
2049 &drm_mode->mode_info);
2050 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002051 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002052 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002053 drm_mode->base.width, drm_mode->base.height,
2054 output->base.x, output->base.y);
2055 }
2056 }
2057}
2058
2059static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002060vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002061{
2062 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002063 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002064 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002065 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002066
2067 switch (event) {
2068 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002069 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002070 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002071 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002072 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002073 wl_display_terminate(compositor->wl_display);
2074 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002075 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002076 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002077 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002078 wl_list_for_each(seat, &compositor->seat_list, link) {
2079 evdev_add_devices(ec->udev, seat);
2080 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002081 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002082 break;
2083 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002084 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002085 wl_list_for_each(seat, &compositor->seat_list, link) {
2086 evdev_disable_udev_monitor(seat);
2087 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002088 }
2089
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002090 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002091 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002092 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002093
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002094 /* If we have a repaint scheduled (either from a
2095 * pending pageflip or the idle handler), make sure we
2096 * cancel that so we don't try to pageflip when we're
2097 * vt switched away. The SLEEPING state will prevent
2098 * further attemps at repainting. When we switch
2099 * back, we schedule a repaint, which will process
2100 * pending frame callbacks. */
2101
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002102 wl_list_for_each(output, &ec->base.output_list, base.link) {
2103 output->base.repaint_needed = 0;
2104 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002105 }
2106
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002107 output = container_of(ec->base.output_list.next,
2108 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002109
2110 wl_list_for_each(sprite, &ec->sprite_list, link)
2111 drmModeSetPlane(ec->drm.fd,
2112 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002113 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002114 0, 0, 0, 0, 0, 0, 0, 0);
2115
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002116 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002117 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002118
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002119 break;
2120 };
2121}
2122
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002123static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002124switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002125{
2126 struct drm_compositor *ec = data;
2127
Daniel Stone325fc2d2012-05-30 16:31:58 +01002128 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002129}
2130
David Herrmann0af066f2012-10-29 19:21:16 +01002131/*
2132 * Find primary GPU
2133 * Some systems may have multiple DRM devices attached to a single seat. This
2134 * function loops over all devices and tries to find a PCI device with the
2135 * boot_vga sysfs attribute set to 1.
2136 * If no such device is found, the first DRM device reported by udev is used.
2137 */
2138static struct udev_device*
2139find_primary_gpu(struct drm_compositor *ec, const char *seat)
2140{
2141 struct udev_enumerate *e;
2142 struct udev_list_entry *entry;
2143 const char *path, *device_seat, *id;
2144 struct udev_device *device, *drm_device, *pci;
2145
2146 e = udev_enumerate_new(ec->udev);
2147 udev_enumerate_add_match_subsystem(e, "drm");
2148 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2149
2150 udev_enumerate_scan_devices(e);
2151 drm_device = NULL;
2152 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2153 path = udev_list_entry_get_name(entry);
2154 device = udev_device_new_from_syspath(ec->udev, path);
2155 if (!device)
2156 continue;
2157 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2158 if (!device_seat)
2159 device_seat = default_seat;
2160 if (strcmp(device_seat, seat)) {
2161 udev_device_unref(device);
2162 continue;
2163 }
2164
2165 pci = udev_device_get_parent_with_subsystem_devtype(device,
2166 "pci", NULL);
2167 if (pci) {
2168 id = udev_device_get_sysattr_value(pci, "boot_vga");
2169 if (id && !strcmp(id, "1")) {
2170 if (drm_device)
2171 udev_device_unref(drm_device);
2172 drm_device = device;
2173 break;
2174 }
2175 }
2176
2177 if (!drm_device)
2178 drm_device = device;
2179 else
2180 udev_device_unref(device);
2181 }
2182
2183 udev_enumerate_unref(e);
2184 return drm_device;
2185}
2186
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002187static void
2188hide_sprites_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2189 void *data)
2190{
2191 struct drm_compositor *c = data;
2192
2193 c->sprites_hidden ^= 1;
2194}
2195
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002196static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002197drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002198 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002199 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002200{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002201 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002202 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002203 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002204 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002205 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002206 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002207
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002208 weston_log("initializing drm backend\n");
2209
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002210 ec = malloc(sizeof *ec);
2211 if (ec == NULL)
2212 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002213 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002214
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002215 /* KMS support for sprites is not complete yet, so disable the
2216 * functionality for now. */
2217 ec->sprites_are_broken = 1;
2218
Daniel Stone725c2c32012-06-22 14:04:36 +01002219 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002220 config_file) < 0) {
2221 weston_log("weston_compositor_init failed\n");
2222 goto err_base;
2223 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002224
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002225 ec->udev = udev_new();
2226 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002227 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002228 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002229 }
2230
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002231 ec->base.wl_display = display;
2232 ec->tty = tty_create(&ec->base, vt_func, tty);
2233 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002234 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002235 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002236 }
2237
David Herrmann0af066f2012-10-29 19:21:16 +01002238 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002239 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002240 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002241 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002242 }
David Herrmann0af066f2012-10-29 19:21:16 +01002243 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002244
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002245 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002246 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002247 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002248 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002249
2250 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002251 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002252
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002253 ec->base.focus = 1;
2254
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002255 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002256
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002257 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002258 weston_compositor_add_key_binding(&ec->base, key,
2259 MODIFIER_CTRL | MODIFIER_ALT,
2260 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002261
Jesse Barnes58ef3792012-02-23 09:45:49 -05002262 wl_list_init(&ec->sprite_list);
2263 create_sprites(ec);
2264
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002265 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002266 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002267 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002268 }
2269
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002270 if (gles2_renderer_init(&ec->base) < 0)
2271 goto err_egl;
2272
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002273 path = NULL;
2274
Tiago Vignattice03ec32011-12-19 01:14:03 +02002275 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002276
2277 loop = wl_display_get_event_loop(ec->base.wl_display);
2278 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002279 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002280 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002281
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002282 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2283 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002284 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002285 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002286 }
2287 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2288 "drm", NULL);
2289 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002290 wl_event_loop_add_fd(loop,
2291 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002292 WL_EVENT_READABLE, udev_drm_event, ec);
2293
2294 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002295 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002296 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002297 }
2298
Daniel Stonea96b93c2012-06-22 14:04:37 +01002299 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002300
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002301 weston_compositor_add_debug_binding(&ec->base, KEY_O,
2302 hide_sprites_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002303
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002304 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002305
2306err_udev_monitor:
2307 wl_event_source_remove(ec->udev_drm_source);
2308 udev_monitor_unref(ec->udev_monitor);
2309err_drm_source:
2310 wl_event_source_remove(ec->drm_source);
2311 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2312 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002313err_egl:
2314 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2315 EGL_NO_CONTEXT);
2316 eglTerminate(ec->base.egl_display);
2317 eglReleaseThread();
2318 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002319err_sprite:
2320 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002321err_udev_dev:
2322 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002323err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002324 tty_destroy(ec->tty);
2325err_udev:
2326 udev_unref(ec->udev);
2327err_compositor:
2328 weston_compositor_shutdown(&ec->base);
2329err_base:
2330 free(ec);
2331 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002332}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002333
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002334static int
2335set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2336{
2337 mode->flags = 0;
2338
2339 if (strcmp(hsync, "+hsync") == 0)
2340 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2341 else if (strcmp(hsync, "-hsync") == 0)
2342 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2343 else
2344 return -1;
2345
2346 if (strcmp(vsync, "+vsync") == 0)
2347 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2348 else if (strcmp(vsync, "-vsync") == 0)
2349 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2350 else
2351 return -1;
2352
2353 return 0;
2354}
2355
2356static int
2357check_for_modeline(struct drm_configured_output *output)
2358{
2359 drmModeModeInfo mode;
2360 char hsync[16];
2361 char vsync[16];
2362 char mode_name[16];
2363 float fclock;
2364
2365 mode.type = DRM_MODE_TYPE_USERDEF;
2366 mode.hskew = 0;
2367 mode.vscan = 0;
2368 mode.vrefresh = 0;
2369
2370 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2371 &fclock, &mode.hdisplay,
2372 &mode.hsync_start,
2373 &mode.hsync_end, &mode.htotal,
2374 &mode.vdisplay,
2375 &mode.vsync_start,
2376 &mode.vsync_end, &mode.vtotal,
2377 hsync, vsync) == 11) {
2378 if (set_sync_flags(&mode, hsync, vsync))
2379 return -1;
2380
2381 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2382 strcpy(mode.name, mode_name);
2383
2384 mode.clock = fclock * 1000;
2385 } else
2386 return -1;
2387
2388 output->crtc_mode = mode;
2389
2390 return 0;
2391}
2392
Scott Moreau8ab5d452012-07-30 19:51:08 -06002393static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002394drm_output_set_transform(struct drm_configured_output *output)
2395{
2396 if (!output_transform) {
2397 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2398 return;
2399 }
2400
2401 if (!strcmp(output_transform, "normal"))
2402 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2403 else if (!strcmp(output_transform, "90"))
2404 output->transform = WL_OUTPUT_TRANSFORM_90;
2405 else if (!strcmp(output_transform, "180"))
2406 output->transform = WL_OUTPUT_TRANSFORM_180;
2407 else if (!strcmp(output_transform, "270"))
2408 output->transform = WL_OUTPUT_TRANSFORM_270;
2409 else if (!strcmp(output_transform, "flipped"))
2410 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2411 else if (!strcmp(output_transform, "flipped-90"))
2412 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2413 else if (!strcmp(output_transform, "flipped-180"))
2414 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2415 else if (!strcmp(output_transform, "flipped-270"))
2416 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2417 else {
2418 weston_log("Invalid transform \"%s\" for output %s\n",
2419 output_transform, output_name);
2420 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2421 }
2422
2423 free(output_transform);
2424 output_transform = NULL;
2425}
2426
2427static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002428output_section_done(void *data)
2429{
2430 struct drm_configured_output *output;
2431
2432 output = malloc(sizeof *output);
2433
Scott Moreau1bad5db2012-08-18 01:04:05 -06002434 if (!output || !output_name || (output_name[0] == 'X') ||
2435 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002436 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002437 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002438 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002439 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002440 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002441 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002442 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002443 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002444 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002445
2446 output->config = OUTPUT_CONFIG_INVALID;
2447 output->name = output_name;
2448 output->mode = output_mode;
2449
Scott Moreau1bad5db2012-08-18 01:04:05 -06002450 if (output_mode) {
2451 if (strcmp(output_mode, "off") == 0)
2452 output->config = OUTPUT_CONFIG_OFF;
2453 else if (strcmp(output_mode, "preferred") == 0)
2454 output->config = OUTPUT_CONFIG_PREFERRED;
2455 else if (strcmp(output_mode, "current") == 0)
2456 output->config = OUTPUT_CONFIG_CURRENT;
2457 else if (sscanf(output_mode, "%dx%d",
2458 &output->width, &output->height) == 2)
2459 output->config = OUTPUT_CONFIG_MODE;
2460 else if (check_for_modeline(output) == 0)
2461 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002462
Scott Moreau1bad5db2012-08-18 01:04:05 -06002463 if (output->config == OUTPUT_CONFIG_INVALID)
2464 weston_log("Invalid mode \"%s\" for output %s\n",
2465 output_mode, output_name);
2466 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002467 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002468
2469 drm_output_set_transform(output);
2470
2471 wl_list_insert(&configured_output_list, &output->link);
2472
2473 if (output_transform)
2474 free(output_transform);
2475 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002476}
2477
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002478WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002479backend_init(struct wl_display *display, int argc, char *argv[],
2480 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002481{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002482 int connector = 0, tty = 0;
2483 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002484
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002485 const struct weston_option drm_options[] = {
2486 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2487 { WESTON_OPTION_STRING, "seat", 0, &seat },
2488 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002489 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002490 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002491
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002492 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002493
Scott Moreau8ab5d452012-07-30 19:51:08 -06002494 wl_list_init(&configured_output_list);
2495
2496 const struct config_key drm_config_keys[] = {
2497 { "name", CONFIG_KEY_STRING, &output_name },
2498 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002499 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002500 };
2501
2502 const struct config_section config_section[] = {
2503 { "output", drm_config_keys,
2504 ARRAY_LENGTH(drm_config_keys), output_section_done },
2505 };
2506
2507 parse_config_file(config_file, config_section,
2508 ARRAY_LENGTH(config_section), NULL);
2509
Daniel Stonec1be8e52012-06-01 11:14:02 -04002510 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2511 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002512}