blob: 113328173c076a461ef295f6bed54065e4812c4a [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;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100
Rob Clarkab5b1e32012-08-09 13:24:45 -0500101 int cursors_are_broken;
102
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200103 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400104};
105
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400106struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500107 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400108 drmModeModeInfo mode_info;
109};
110
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300111struct drm_output;
112
113struct drm_fb {
114 struct gbm_bo *bo;
115 struct drm_output *output;
116 uint32_t fb_id;
117 int is_client_buffer;
118 struct wl_buffer *buffer;
119 struct wl_listener buffer_destroy_listener;
120};
121
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400122struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500123 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400124
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400125 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500127 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400128 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700129 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200130
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300131 int vblank_pending;
132 int page_flip_pending;
133
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400134 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400135 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400136 struct weston_plane cursor_plane;
137 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400138 struct weston_surface *cursor_surface;
139 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300140 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200141 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400142};
143
Jesse Barnes58ef3792012-02-23 09:45:49 -0500144/*
145 * An output has a primary display plane plus zero or more sprites for
146 * blending display contents.
147 */
148struct drm_sprite {
149 struct wl_list link;
150
151 uint32_t fb_id;
152 uint32_t pending_fb_id;
153 struct weston_surface *surface;
154 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400155 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500156
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300157 struct drm_output *output;
158
Jesse Barnes58ef3792012-02-23 09:45:49 -0500159 struct drm_compositor *compositor;
160
161 struct wl_listener destroy_listener;
162 struct wl_listener pending_destroy_listener;
163
164 uint32_t possible_crtcs;
165 uint32_t plane_id;
166 uint32_t count_formats;
167
168 int32_t src_x, src_y;
169 uint32_t src_w, src_h;
170 uint32_t dest_x, dest_y;
171 uint32_t dest_w, dest_h;
172
173 uint32_t formats[];
174};
175
Pekka Paalanen33156972012-08-03 13:30:30 -0400176struct drm_seat {
177 struct weston_seat base;
178 struct wl_list devices_list;
179 struct udev_monitor *udev_monitor;
180 struct wl_event_source *udev_monitor_source;
181 char *seat_id;
182};
183
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400184static void
185drm_output_set_cursor(struct drm_output *output);
186static void
187drm_disable_unused_sprites(struct weston_output *output_base);
188
Jesse Barnes58ef3792012-02-23 09:45:49 -0500189static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500190drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
191{
192 struct weston_compositor *ec = output_base->compositor;
193 struct drm_compositor *c =(struct drm_compositor *) ec;
194 struct drm_output *output = (struct drm_output *) output_base;
195 int crtc;
196
197 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
198 if (c->crtcs[crtc] != output->crtc_id)
199 continue;
200
201 if (supported & (1 << crtc))
202 return -1;
203 }
204
205 return 0;
206}
207
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300208static void
209drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
210{
211 struct drm_fb *fb = data;
212 struct gbm_device *gbm = gbm_bo_get_device(bo);
213
214 if (fb->fb_id)
215 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
216
217 if (fb->buffer) {
218 weston_buffer_post_release(fb->buffer);
219 wl_list_remove(&fb->buffer_destroy_listener.link);
220 }
221
222 free(data);
223}
224
225static struct drm_fb *
226drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
227{
228 struct drm_fb *fb = gbm_bo_get_user_data(bo);
229 struct drm_compositor *compositor =
230 (struct drm_compositor *) output->base.compositor;
231 uint32_t width, height, stride, handle;
232 int ret;
233
234 if (fb)
235 return fb;
236
237 fb = malloc(sizeof *fb);
238
239 fb->bo = bo;
240 fb->output = output;
241 fb->is_client_buffer = 0;
242 fb->buffer = NULL;
243
244 width = gbm_bo_get_width(bo);
245 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400246 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300247 handle = gbm_bo_get_handle(bo).u32;
248
249 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
250 stride, handle, &fb->fb_id);
251 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200252 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300253 free(fb);
254 return NULL;
255 }
256
257 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
258
259 return fb;
260}
261
262static void
263fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
264{
265 struct drm_fb *fb = container_of(listener, struct drm_fb,
266 buffer_destroy_listener);
267
268 fb->buffer = NULL;
269
270 if (fb == fb->output->next ||
271 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400272 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300273}
274
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400275static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400276drm_output_prepare_scanout_surface(struct weston_output *_output,
277 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500278{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400279 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500280 struct drm_compositor *c =
281 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300282 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500283
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500284 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200285 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200286 es->geometry.width != output->base.current->width ||
287 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200288 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400289 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400290 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500291
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400292 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
293 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500294
Rob Bradford9b101872012-09-14 23:25:41 +0100295 /* Unable to use the buffer for scanout */
296 if (!bo)
297 return NULL;
298
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300299 /* Need to verify output->region contained in surface opaque
300 * region. Or maybe just that format doesn't have alpha.
301 * For now, scanout only if format is XRGB8888. */
302 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
303 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400304 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300305 }
306
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300307 output->next = drm_fb_get_from_bo(bo, output);
308 if (!output->next) {
309 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400310 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300311 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500312
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300313 output->next->is_client_buffer = 1;
314 output->next->buffer = es->buffer;
315 output->next->buffer->busy_count++;
316 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
317
318 wl_signal_add(&output->next->buffer->resource.destroy_signal,
319 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500320
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400321 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500322}
323
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500324static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400325drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400326{
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400327 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300328 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400329
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400330 ec->renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400331
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300332 bo = gbm_surface_lock_front_buffer(output->surface);
333 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200334 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400335 return;
336 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300337
338 output->next = drm_fb_get_from_bo(bo, output);
339 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200340 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341 gbm_surface_release_buffer(output->surface, bo);
342 return;
343 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400344}
345
346static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500347drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400348 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100349{
350 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500351 struct drm_compositor *compositor =
352 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500353 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400354 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500355 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100356
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300357 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400358 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400360 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100361
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400362 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300363 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400364 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400366 &output->connector_id, 1,
367 &mode->mode_info);
368 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200369 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400370 return;
371 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200372 }
373
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500374 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300375 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500376 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200377 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500378 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500379 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100380
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300381 output->page_flip_pending = 1;
382
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400383 drm_output_set_cursor(output);
384
Jesse Barnes58ef3792012-02-23 09:45:49 -0500385 /*
386 * Now, update all the sprite surfaces
387 */
388 wl_list_for_each(s, &compositor->sprite_list, link) {
389 uint32_t flags = 0;
390 drmVBlank vbl = {
391 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
392 .request.sequence = 1,
393 };
394
395 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
396 continue;
397
398 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
399 output->crtc_id, s->pending_fb_id, flags,
400 s->dest_x, s->dest_y,
401 s->dest_w, s->dest_h,
402 s->src_x, s->src_y,
403 s->src_w, s->src_h);
404 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200405 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500406 ret, strerror(errno));
407
Rob Clark5ca1a472012-08-08 20:27:37 -0500408 if (output->pipe > 0)
409 vbl.request.type |= DRM_VBLANK_SECONDARY;
410
Jesse Barnes58ef3792012-02-23 09:45:49 -0500411 /*
412 * Queue a vblank signal so we know when the surface
413 * becomes active on the display or has been replaced.
414 */
415 vbl.request.signal = (unsigned long)s;
416 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
417 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200418 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500419 ret, strerror(errno));
420 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300421
422 s->output = output;
423 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500424 }
425
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400426 drm_disable_unused_sprites(&output->base);
427
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500428 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400429}
430
431static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500432vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
433 void *data)
434{
435 struct drm_sprite *s = (struct drm_sprite *)data;
436 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300437 struct drm_output *output = s->output;
438 uint32_t msecs;
439
440 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500441
442 if (s->surface) {
443 weston_buffer_post_release(s->surface->buffer);
444 wl_list_remove(&s->destroy_listener.link);
445 s->surface = NULL;
446 drmModeRmFB(c->drm.fd, s->fb_id);
447 s->fb_id = 0;
448 }
449
450 if (s->pending_surface) {
451 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400452 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
453 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500454 s->surface = s->pending_surface;
455 s->pending_surface = NULL;
456 s->fb_id = s->pending_fb_id;
457 s->pending_fb_id = 0;
458 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300459
460 if (!output->page_flip_pending) {
461 msecs = sec * 1000 + usec / 1000;
462 weston_output_finish_frame(&output->base, msecs);
463 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500464}
465
466static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400467page_flip_handler(int fd, unsigned int frame,
468 unsigned int sec, unsigned int usec, void *data)
469{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200470 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400471 uint32_t msecs;
472
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300473 output->page_flip_pending = 0;
474
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300475 if (output->current) {
476 if (output->current->is_client_buffer)
477 gbm_bo_destroy(output->current->bo);
478 else
479 gbm_surface_release_buffer(output->surface,
480 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200481 }
482
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300483 output->current = output->next;
484 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400485
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300486 if (!output->vblank_pending) {
487 msecs = sec * 1000 + usec / 1000;
488 weston_output_finish_frame(&output->base, msecs);
489 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200490}
491
492static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500493drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
494{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400495 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500496
497 for (i = 0; i < s->count_formats; i++)
498 if (s->formats[i] == format)
499 return 1;
500
501 return 0;
502}
503
504static int
505drm_surface_transform_supported(struct weston_surface *es)
506{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400507 struct weston_matrix *matrix = &es->transform.matrix;
508 int i;
509
510 if (!es->transform.enabled)
511 return 1;
512
513 for (i = 0; i < 16; i++) {
514 switch (i) {
515 case 10:
516 case 15:
517 if (matrix->d[i] != 1.0)
518 return 0;
519 break;
520 case 0:
521 case 5:
522 case 12:
523 case 13:
524 break;
525 default:
526 if (matrix->d[i] != 0.0)
527 return 0;
528 break;
529 }
530 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500531
532 return 1;
533}
534
Jesse Barnes58ef3792012-02-23 09:45:49 -0500535static void
536drm_disable_unused_sprites(struct weston_output *output_base)
537{
538 struct weston_compositor *ec = output_base->compositor;
539 struct drm_compositor *c =(struct drm_compositor *) ec;
540 struct drm_output *output = (struct drm_output *) output_base;
541 struct drm_sprite *s;
542 int ret;
543
544 wl_list_for_each(s, &c->sprite_list, link) {
545 if (s->pending_fb_id)
546 continue;
547
548 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
549 output->crtc_id, 0, 0,
550 0, 0, 0, 0, 0, 0, 0, 0);
551 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200552 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500553 ret, strerror(errno));
554 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300555
556 if (s->surface) {
557 s->surface = NULL;
558 wl_list_remove(&s->destroy_listener.link);
559 }
560
561 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500562 s->fb_id = 0;
563 s->pending_fb_id = 0;
564 }
565}
566
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400567static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500568drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400569 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500570{
571 struct weston_compositor *ec = output_base->compositor;
572 struct drm_compositor *c =(struct drm_compositor *) ec;
573 struct drm_sprite *s;
574 int found = 0;
575 EGLint handle, stride;
576 struct gbm_bo *bo;
577 uint32_t fb_id = 0;
578 uint32_t handles[4], pitches[4], offsets[4];
579 int ret = 0;
580 pixman_region32_t dest_rect, src_rect;
581 pixman_box32_t *box;
582 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400583 wl_fixed_t sx1, sy1, sx2, sy2;
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400584 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500585
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500586 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400587 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500588
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300589 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400590 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300591
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400592 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400593 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500594
Rob Clark702ffae2012-08-09 14:18:27 -0500595 if (wl_buffer_is_shm(es->buffer))
596 return NULL;
597
Jesse Barnes58ef3792012-02-23 09:45:49 -0500598 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400599 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 wl_list_for_each(s, &c->sprite_list, link) {
602 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
603 continue;
604
605 if (!s->pending_fb_id) {
606 found = 1;
607 break;
608 }
609 }
610
611 /* No sprites available */
612 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400613 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500614
Rob Clark4339add2012-08-09 14:18:28 -0500615 width = es->geometry.width;
616 height = es->geometry.height;
617
618 /* If geometry is out of bounds, don't even bother trying because
619 * we know the AddFB2() call will fail:
620 */
621 if (c->min_width > width || width > c->max_width ||
622 c->min_height > height || height > c->max_height)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400623 return NULL;
Rob Clark4339add2012-08-09 14:18:28 -0500624
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400625 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
626 es->buffer, GBM_BO_USE_SCANOUT);
627 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400628 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400629
Jesse Barnes58ef3792012-02-23 09:45:49 -0500630 format = gbm_bo_get_format(bo);
631 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400632 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500633
634 gbm_bo_destroy(bo);
635
636 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400637 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638
639 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400640 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641
642 handles[0] = handle;
643 pitches[0] = stride;
644 offsets[0] = 0;
645
Rob Clark4339add2012-08-09 14:18:28 -0500646 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 format, handles, pitches, offsets,
648 &fb_id, 0);
649 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200650 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500651 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400652 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653 }
654
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655 s->pending_fb_id = fb_id;
656 s->pending_surface = es;
657 es->buffer->busy_count++;
658
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400659 box = pixman_region32_extents(&es->transform.boundingbox);
660 s->plane.x = box->x1;
661 s->plane.y = box->y1;
662
Jesse Barnes58ef3792012-02-23 09:45:49 -0500663 /*
664 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200665 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500666 * for us already).
667 */
668 pixman_region32_init(&dest_rect);
669 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
670 &output_base->region);
671 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
672 box = pixman_region32_extents(&dest_rect);
673 s->dest_x = box->x1;
674 s->dest_y = box->y1;
675 s->dest_w = box->x2 - box->x1;
676 s->dest_h = box->y2 - box->y1;
677 pixman_region32_fini(&dest_rect);
678
679 pixman_region32_init(&src_rect);
680 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
681 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500682 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400683
684 weston_surface_from_global_fixed(es,
685 wl_fixed_from_int(box->x1),
686 wl_fixed_from_int(box->y1),
687 &sx1, &sy1);
688 weston_surface_from_global_fixed(es,
689 wl_fixed_from_int(box->x2),
690 wl_fixed_from_int(box->y2),
691 &sx2, &sy2);
692
693 if (sx1 < 0)
694 sx1 = 0;
695 if (sy1 < 0)
696 sy1 = 0;
697 if (sx2 > wl_fixed_from_int(es->geometry.width))
698 sx2 = wl_fixed_from_int(es->geometry.width);
699 if (sy2 > wl_fixed_from_int(es->geometry.height))
700 sy2 = wl_fixed_from_int(es->geometry.height);
701
702 s->src_x = sx1 << 8;
703 s->src_y = sy1 << 8;
704 s->src_w = (sx2 - sx1) << 8;
705 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706 pixman_region32_fini(&src_rect);
707
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400708 wl_signal_add(&es->buffer->resource.destroy_signal,
709 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400710
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400711 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500712}
713
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400714static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400715drm_output_prepare_cursor_surface(struct weston_output *output_base,
716 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500717{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400718 struct drm_compositor *c =
719 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400720 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400721
722 if (output->cursor_surface)
723 return NULL;
724 if (es->output_mask != (1u << output_base->id))
725 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500726 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400727 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400728 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
729 es->geometry.width > 64 || es->geometry.height > 64)
730 return NULL;
731
732 output->cursor_surface = es;
733
734 return &output->cursor_plane;
735}
736
737static void
738drm_output_set_cursor(struct drm_output *output)
739{
740 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400741 struct drm_compositor *c =
742 (struct drm_compositor *) output->base.compositor;
743 EGLint handle, stride;
744 struct gbm_bo *bo;
745 uint32_t buf[64 * 64];
746 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400747 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500748
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400749 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400750 if (es == NULL) {
751 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
752 return;
753 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500754
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400755 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
756 pixman_region32_fini(&output->cursor_plane.damage);
757 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400758 output->current_cursor ^= 1;
759 bo = output->cursor_bo[output->current_cursor];
760 memset(buf, 0, sizeof buf);
761 stride = wl_shm_buffer_get_stride(es->buffer);
762 s = wl_shm_buffer_get_data(es->buffer);
763 for (i = 0; i < es->geometry.height; i++)
764 memcpy(buf + i * 64, s + i * stride,
765 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500766
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400767 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300768 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400769
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400770 handle = gbm_bo_get_handle(bo).s32;
771 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500772 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300773 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500774 c->cursors_are_broken = 1;
775 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400776 }
777
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400778 x = es->geometry.x - output->base.x;
779 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400780 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500781 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400782 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500783 c->cursors_are_broken = 1;
784 }
785
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400786 output->cursor_plane.x = x;
787 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400788 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500789}
790
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791static void
792drm_assign_planes(struct weston_output *output)
793{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400794 struct drm_compositor *c =
795 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200796 struct drm_output *drm_output = (struct drm_output *) output;
797 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400798 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400800 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200802 /* Reset the opaque region of the planes */
803 pixman_region32_fini(&drm_output->cursor_plane.opaque);
804 pixman_region32_init(&drm_output->cursor_plane.opaque);
805 pixman_region32_fini(&drm_output->fb_plane.opaque);
806 pixman_region32_init(&drm_output->fb_plane.opaque);
807
808 wl_list_for_each (s, &c->sprite_list, link) {
809 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
810 continue;
811
812 pixman_region32_fini(&s->plane.opaque);
813 pixman_region32_init(&s->plane.opaque);
814 }
815
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816 /*
817 * Find a surface for each sprite in the output using some heuristics:
818 * 1) size
819 * 2) frequency of update
820 * 3) opacity (though some hw might support alpha blending)
821 * 4) clipping (this can be fixed with color keys)
822 *
823 * The idea is to save on blitting since this should save power.
824 * If we can get a large video surface on the sprite for example,
825 * the main display surface may not need to update at all, and
826 * the client buffer can be used directly for the sprite surface
827 * as we do for flipping full screen surfaces.
828 */
829 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400831 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832 pixman_region32_init(&surface_overlap);
833 pixman_region32_intersect(&surface_overlap, &overlap,
834 &es->transform.boundingbox);
835
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400836 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400837 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400838 next_plane = primary;
839 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400840 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400841 if (next_plane == NULL)
842 next_plane = drm_output_prepare_scanout_surface(output, es);
843 if (next_plane == NULL)
844 next_plane = drm_output_prepare_overlay_surface(output, es);
845 if (next_plane == NULL)
846 next_plane = primary;
847 weston_surface_move_to_plane(es, next_plane);
848 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 pixman_region32_union(&overlap, &overlap,
850 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400851
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852 pixman_region32_fini(&surface_overlap);
853 }
854 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500855}
856
Matt Roper361d2ad2011-08-29 13:52:23 -0700857static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500858drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700859{
860 struct drm_output *output = (struct drm_output *) output_base;
861 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200862 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700863 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700864
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200865 if (output->backlight)
866 backlight_destroy(output->backlight);
867
Matt Roper361d2ad2011-08-29 13:52:23 -0700868 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400869 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700870
871 /* Restore original CRTC state */
872 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200873 origcrtc->x, origcrtc->y,
874 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700875 drmModeFreeCrtc(origcrtc);
876
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200877 c->crtc_allocator &= ~(1 << output->crtc_id);
878 c->connector_allocator &= ~(1 << output->connector_id);
879
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400880 eglDestroySurface(c->base.egl_display, output->base.egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400881 gbm_surface_destroy(output->surface);
882
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400883 weston_plane_release(&output->fb_plane);
884 weston_plane_release(&output->cursor_plane);
885
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500886 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200887 wl_list_remove(&output->base.link);
888
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400889 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700890 free(output);
891}
892
Alex Wub7b8bda2012-04-17 17:20:48 +0800893static struct drm_mode *
894choose_mode (struct drm_output *output, struct weston_mode *target_mode)
895{
896 struct drm_mode *tmp_mode = NULL, *mode;
897
898 if (output->base.current->width == target_mode->width &&
899 output->base.current->height == target_mode->height &&
900 (output->base.current->refresh == target_mode->refresh ||
901 target_mode->refresh == 0))
902 return (struct drm_mode *)output->base.current;
903
904 wl_list_for_each(mode, &output->base.mode_list, base.link) {
905 if (mode->mode_info.hdisplay == target_mode->width &&
906 mode->mode_info.vdisplay == target_mode->height) {
907 if (mode->mode_info.vrefresh == target_mode->refresh ||
908 target_mode->refresh == 0) {
909 return mode;
910 } else if (!tmp_mode)
911 tmp_mode = mode;
912 }
913 }
914
915 return tmp_mode;
916}
917
918static int
919drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
920{
921 struct drm_output *output;
922 struct drm_mode *drm_mode;
923 int ret;
924 struct drm_compositor *ec;
925 struct gbm_surface *surface;
926 EGLSurface egl_surface;
927
928 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200929 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800930 return -1;
931 }
932
933 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200934 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800935 return -1;
936 }
937
938 ec = (struct drm_compositor *)output_base->compositor;
939 output = (struct drm_output *)output_base;
940 drm_mode = choose_mode (output, mode);
941
942 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200943 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800944 return -1;
945 } else if (&drm_mode->base == output->base.current) {
946 return 0;
947 } else if (drm_mode->base.width == output->base.current->width &&
948 drm_mode->base.height == output->base.current->height) {
949 /* only change refresh value */
950 ret = drmModeSetCrtc(ec->drm.fd,
951 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300952 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800953 &output->connector_id, 1, &drm_mode->mode_info);
954
955 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200956 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800957 drm_mode->base.width,
958 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400959 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800960 ret = -1;
961 } else {
962 output->base.current->flags = 0;
963 output->base.current = &drm_mode->base;
964 drm_mode->base.flags =
965 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
966 ret = 0;
967 }
968
969 return ret;
970 }
971
972 drm_mode->base.flags =
973 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
974
975 surface = gbm_surface_create(ec->gbm,
976 drm_mode->base.width,
977 drm_mode->base.height,
978 GBM_FORMAT_XRGB8888,
979 GBM_BO_USE_SCANOUT |
980 GBM_BO_USE_RENDERING);
981 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200982 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800983 return -1;
984 }
985
986 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400987 eglCreateWindowSurface(ec->base.egl_display,
988 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800989 surface, NULL);
990
991 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200992 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800993 goto err;
994 }
995
996 ret = drmModeSetCrtc(ec->drm.fd,
997 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300998 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800999 &output->connector_id, 1, &drm_mode->mode_info);
1000 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001001 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001002 goto err;
1003 }
1004
1005 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001006 if (output->current) {
1007 if (output->current->is_client_buffer)
1008 gbm_bo_destroy(output->current->bo);
1009 else
1010 gbm_surface_release_buffer(output->surface,
1011 output->current->bo);
1012 }
1013 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001014
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001015 if (output->next) {
1016 if (output->next->is_client_buffer)
1017 gbm_bo_destroy(output->next->bo);
1018 else
1019 gbm_surface_release_buffer(output->surface,
1020 output->next->bo);
1021 }
1022 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001023
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001024 eglDestroySurface(ec->base.egl_display, output->base.egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001025 gbm_surface_destroy(output->surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001026 output->base.egl_surface = egl_surface;
Alex Wub7b8bda2012-04-17 17:20:48 +08001027 output->surface = surface;
1028
1029 /*update output*/
1030 output->base.current = &drm_mode->base;
1031 output->base.dirty = 1;
1032 weston_output_move(&output->base, output->base.x, output->base.y);
1033 return 0;
1034
1035err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001036 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001037 gbm_surface_destroy(surface);
1038 return -1;
1039}
1040
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001041static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001042on_drm_input(int fd, uint32_t mask, void *data)
1043{
1044 drmEventContext evctx;
1045
1046 memset(&evctx, 0, sizeof evctx);
1047 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1048 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001049 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001050 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001051
1052 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001053}
1054
1055static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001056init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001057{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001058 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001059 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001060 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001061 static const EGLint config_attribs[] = {
1062 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1063 EGL_RED_SIZE, 1,
1064 EGL_GREEN_SIZE, 1,
1065 EGL_BLUE_SIZE, 1,
1066 EGL_ALPHA_SIZE, 0,
1067 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1068 EGL_NONE
1069 };
1070
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001071 sysnum = udev_device_get_sysnum(device);
1072 if (sysnum)
1073 ec->drm.id = atoi(sysnum);
1074 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001075 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001076 return -1;
1077 }
1078
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001079 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001080 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001081 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001082 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001083 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001084 udev_device_get_devnode(device));
1085 return -1;
1086 }
1087
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001088 weston_log("using %s\n", filename);
1089
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001090 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001091 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001092 ec->base.egl_display = eglGetDisplay(ec->gbm);
1093 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001094 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001095 return -1;
1096 }
1097
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001098 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001099 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001100 return -1;
1101 }
1102
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001103 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1104 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001105 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001106 return -1;
1107 }
1108
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001109 return 0;
1110}
1111
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001112static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001113drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1114{
1115 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001116 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001117
1118 mode = malloc(sizeof *mode);
1119 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001120 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001121
1122 mode->base.flags = 0;
1123 mode->base.width = info->hdisplay;
1124 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001125
1126 /* Calculate higher precision (mHz) refresh rate */
1127 refresh = (info->clock * 1000000LL / info->htotal +
1128 info->vtotal / 2) / info->vtotal;
1129
1130 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1131 refresh *= 2;
1132 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1133 refresh /= 2;
1134 if (info->vscan > 1)
1135 refresh /= info->vscan;
1136
1137 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001138 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001139
1140 if (info->type & DRM_MODE_TYPE_PREFERRED)
1141 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1142
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001143 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1144
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001145 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001146}
1147
1148static int
1149drm_subpixel_to_wayland(int drm_value)
1150{
1151 switch (drm_value) {
1152 default:
1153 case DRM_MODE_SUBPIXEL_UNKNOWN:
1154 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1155 case DRM_MODE_SUBPIXEL_NONE:
1156 return WL_OUTPUT_SUBPIXEL_NONE;
1157 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1158 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1159 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1160 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1161 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1162 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1163 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1164 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1165 }
1166}
1167
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001168static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001169sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001170{
1171 struct drm_sprite *sprite =
1172 container_of(listener, struct drm_sprite,
1173 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001174 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001175
1176 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001177 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1178 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001179}
1180
1181static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001182sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001183{
1184 struct drm_sprite *sprite =
1185 container_of(listener, struct drm_sprite,
1186 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001187 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001188
1189 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001190 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1191 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001192}
1193
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001194/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001195static uint32_t
1196drm_get_backlight(struct drm_output *output)
1197{
1198 long brightness, max_brightness, norm;
1199
1200 brightness = backlight_get_brightness(output->backlight);
1201 max_brightness = backlight_get_max_brightness(output->backlight);
1202
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001203 /* convert it on a scale of 0 to 255 */
1204 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001205
1206 return (uint32_t) norm;
1207}
1208
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001209/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001210static void
1211drm_set_backlight(struct weston_output *output_base, uint32_t value)
1212{
1213 struct drm_output *output = (struct drm_output *) output_base;
1214 long max_brightness, new_brightness;
1215
1216 if (!output->backlight)
1217 return;
1218
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001219 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001220 return;
1221
1222 max_brightness = backlight_get_max_brightness(output->backlight);
1223
1224 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001225 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001226
1227 backlight_set_brightness(output->backlight, new_brightness);
1228}
1229
1230static drmModePropertyPtr
1231drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1232{
1233 drmModePropertyPtr props;
1234 int i;
1235
1236 for (i = 0; i < connector->count_props; i++) {
1237 props = drmModeGetProperty(fd, connector->props[i]);
1238 if (!props)
1239 continue;
1240
1241 if (!strcmp(props->name, name))
1242 return props;
1243
1244 drmModeFreeProperty(props);
1245 }
1246
1247 return NULL;
1248}
1249
1250static void
1251drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1252{
1253 struct drm_output *output = (struct drm_output *) output_base;
1254 struct weston_compositor *ec = output_base->compositor;
1255 struct drm_compositor *c = (struct drm_compositor *) ec;
1256 drmModeConnectorPtr connector;
1257 drmModePropertyPtr prop;
1258
1259 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1260 if (!connector)
1261 return;
1262
1263 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1264 if (!prop) {
1265 drmModeFreeConnector(connector);
1266 return;
1267 }
1268
1269 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1270 prop->prop_id, level);
1271 drmModeFreeProperty(prop);
1272 drmModeFreeConnector(connector);
1273}
1274
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001275static const char *connector_type_names[] = {
1276 "None",
1277 "VGA",
1278 "DVI",
1279 "DVI",
1280 "DVI",
1281 "Composite",
1282 "TV",
1283 "LVDS",
1284 "CTV",
1285 "DIN",
1286 "DP",
1287 "HDMI",
1288 "HDMI",
1289 "TV",
1290 "eDP",
1291};
1292
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001293static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001294find_crtc_for_connector(struct drm_compositor *ec,
1295 drmModeRes *resources, drmModeConnector *connector)
1296{
1297 drmModeEncoder *encoder;
1298 uint32_t possible_crtcs;
1299 int i, j;
1300
1301 for (j = 0; j < connector->count_encoders; j++) {
1302 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1303 if (encoder == NULL) {
1304 weston_log("Failed to get encoder.\n");
1305 return -1;
1306 }
1307 possible_crtcs = encoder->possible_crtcs;
1308 drmModeFreeEncoder(encoder);
1309
1310 for (i = 0; i < resources->count_crtcs; i++) {
1311 if (possible_crtcs & (1 << i) &&
1312 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1313 return i;
1314 }
1315 }
1316
1317 return -1;
1318}
1319
1320static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001321create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001322 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001323 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001324 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001325{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001326 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001327 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1328 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001329 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001330 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001331 drmModeModeInfo crtc_mode;
1332 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001333 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001334 char name[32];
1335 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001336
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001337 i = find_crtc_for_connector(ec, resources, connector);
1338 if (i < 0) {
1339 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001340 return -1;
1341 }
1342
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001343 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001344 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001345 return -1;
1346
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001347 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001348 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1349 output->base.make = "unknown";
1350 output->base.model = "unknown";
1351 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001352
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001353 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1354 type_name = connector_type_names[connector->connector_type];
1355 else
1356 type_name = "UNKNOWN";
1357 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1358 output->name = strdup(name);
1359
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001360 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001361 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001362 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001363 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001364 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001365
Matt Roper361d2ad2011-08-29 13:52:23 -07001366 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1367
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001368 /* Get the current mode on the crtc that's currently driving
1369 * this connector. */
1370 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001371 memset(&crtc_mode, 0, sizeof crtc_mode);
1372 if (encoder != NULL) {
1373 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1374 drmModeFreeEncoder(encoder);
1375 if (crtc == NULL)
1376 goto err_free;
1377 if (crtc->mode_valid)
1378 crtc_mode = crtc->mode;
1379 drmModeFreeCrtc(crtc);
1380 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001381
David Herrmann0f0d54e2011-12-08 17:05:45 +01001382 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001383 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1384 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001385 goto err_free;
1386 }
1387
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001388 preferred = NULL;
1389 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001390 configured = NULL;
1391
1392 wl_list_for_each(temp, &configured_output_list, link) {
1393 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001394 if (temp->mode)
1395 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001396 temp->name, temp->mode);
1397 o = temp;
1398 break;
1399 }
1400 }
1401
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001402 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001403 weston_log("Disabling output %s\n", o->name);
1404
1405 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1406 0, 0, 0, 0, 0, NULL);
1407 goto err_free;
1408 }
1409
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001410 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001411 if (o && o->config == OUTPUT_CONFIG_MODE &&
1412 o->width == drm_mode->base.width &&
1413 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001414 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001415 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001416 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001417 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001418 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001419 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001420
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001421 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001422 configured = drm_output_add_mode(output, &o->crtc_mode);
1423 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001424 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001425 current = configured;
1426 }
1427
Wang Quanxianacb805a2012-07-30 18:09:46 -04001428 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001429 current = drm_output_add_mode(output, &crtc_mode);
1430 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001431 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001432 }
1433
Scott Moreau8ab5d452012-07-30 19:51:08 -06001434 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1435 configured = current;
1436
Wang Quanxianacb805a2012-07-30 18:09:46 -04001437 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001438 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001439 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001440 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001441 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001442 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001443 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001444 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001445
1446 if (output->base.current == NULL) {
1447 weston_log("no available modes for %s\n", output->name);
1448 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001449 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001450
Wang Quanxianacb805a2012-07-30 18:09:46 -04001451 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1452
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001453 output->surface = gbm_surface_create(ec->gbm,
1454 output->base.current->width,
1455 output->base.current->height,
1456 GBM_FORMAT_XRGB8888,
1457 GBM_BO_USE_SCANOUT |
1458 GBM_BO_USE_RENDERING);
1459 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001460 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001461 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001462 }
1463
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001464 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001465 eglCreateWindowSurface(ec->base.egl_display,
1466 ec->base.egl_config,
1467 output->surface,
1468 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001469 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001470 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001471 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001472 }
1473
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001474 output->cursor_bo[0] =
1475 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1476 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1477 output->cursor_bo[1] =
1478 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1479 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001480 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1481 weston_log("cursor buffers unavailable, using gl cursors\n");
1482 ec->cursors_are_broken = 1;
1483 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001484
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001485 output->backlight = backlight_init(drm_device,
1486 connector->connector_type);
1487 if (output->backlight) {
1488 output->base.set_backlight = drm_set_backlight;
1489 output->base.backlight_current = drm_get_backlight(output);
1490 }
1491
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001492 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001493 connector->mmWidth, connector->mmHeight,
1494 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001495
1496 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1497
Alex Wubd3354b2012-04-17 17:20:49 +08001498 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001499 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001500 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001501 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001502 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001503 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001504
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001505 weston_plane_init(&output->cursor_plane, 0, 0);
1506 weston_plane_init(&output->fb_plane, 0, 0);
1507
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001508 weston_log("Output %s, (connector %d, crtc %d)\n",
1509 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001510 wl_list_for_each(m, &output->base.mode_list, link)
1511 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1512 m->width, m->height, m->refresh / 1000.0,
1513 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1514 ", preferred" : "",
1515 m->flags & WL_OUTPUT_MODE_CURRENT ?
1516 ", current" : "",
1517 connector->count_modes == 0 ?
1518 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001519
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001520 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001521
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001522err_surface:
1523 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001524err_free:
1525 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1526 base.link) {
1527 wl_list_remove(&drm_mode->base.link);
1528 free(drm_mode);
1529 }
1530
1531 drmModeFreeCrtc(output->original_crtc);
1532 ec->crtc_allocator &= ~(1 << output->crtc_id);
1533 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001534 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001535 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001536
David Herrmann0f0d54e2011-12-08 17:05:45 +01001537 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001538}
1539
Jesse Barnes58ef3792012-02-23 09:45:49 -05001540static void
1541create_sprites(struct drm_compositor *ec)
1542{
1543 struct drm_sprite *sprite;
1544 drmModePlaneRes *plane_res;
1545 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001546 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001547
1548 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1549 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001550 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001551 strerror(errno));
1552 return;
1553 }
1554
1555 for (i = 0; i < plane_res->count_planes; i++) {
1556 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1557 if (!plane)
1558 continue;
1559
1560 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1561 plane->count_formats));
1562 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001563 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001564 __func__);
1565 free(plane);
1566 continue;
1567 }
1568
1569 memset(sprite, 0, sizeof *sprite);
1570
1571 sprite->possible_crtcs = plane->possible_crtcs;
1572 sprite->plane_id = plane->plane_id;
1573 sprite->surface = NULL;
1574 sprite->pending_surface = NULL;
1575 sprite->fb_id = 0;
1576 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001577 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1578 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001579 sprite_handle_pending_buffer_destroy;
1580 sprite->compositor = ec;
1581 sprite->count_formats = plane->count_formats;
1582 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001583 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001584 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001585 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001586
1587 wl_list_insert(&ec->sprite_list, &sprite->link);
1588 }
1589
1590 free(plane_res->planes);
1591 free(plane_res);
1592}
1593
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001594static void
1595destroy_sprites(struct drm_compositor *compositor)
1596{
1597 struct drm_sprite *sprite, *next;
1598 struct drm_output *output;
1599
1600 output = container_of(compositor->base.output_list.next,
1601 struct drm_output, base.link);
1602
1603 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1604 drmModeSetPlane(compositor->drm.fd,
1605 sprite->plane_id,
1606 output->crtc_id, 0, 0,
1607 0, 0, 0, 0, 0, 0, 0, 0);
1608 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001609 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001610 free(sprite);
1611 }
1612}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001613
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001614static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001615create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001616 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001617{
1618 drmModeConnector *connector;
1619 drmModeRes *resources;
1620 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001621 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001622
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001623 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001624 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001625 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001626 return -1;
1627 }
1628
Jesse Barnes58ef3792012-02-23 09:45:49 -05001629 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001630 if (!ec->crtcs) {
1631 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001632 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001633 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001634
Rob Clark4339add2012-08-09 14:18:28 -05001635 ec->min_width = resources->min_width;
1636 ec->max_width = resources->max_width;
1637 ec->min_height = resources->min_height;
1638 ec->max_height = resources->max_height;
1639
Jesse Barnes58ef3792012-02-23 09:45:49 -05001640 ec->num_crtcs = resources->count_crtcs;
1641 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1642
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001643 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001644 connector = drmModeGetConnector(ec->drm.fd,
1645 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001646 if (connector == NULL)
1647 continue;
1648
1649 if (connector->connection == DRM_MODE_CONNECTED &&
1650 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001651 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001652 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001653 connector, x, y,
1654 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001655 drmModeFreeConnector(connector);
1656 continue;
1657 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001658
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001659 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001660 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001661 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001662 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001663
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001664 drmModeFreeConnector(connector);
1665 }
1666
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001667 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001668 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001669 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001670 return -1;
1671 }
1672
1673 drmModeFreeResources(resources);
1674
1675 return 0;
1676}
1677
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001679update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001680{
1681 drmModeConnector *connector;
1682 drmModeRes *resources;
1683 struct drm_output *output, *next;
1684 int x = 0, y = 0;
1685 int x_offset = 0, y_offset = 0;
1686 uint32_t connected = 0, disconnects = 0;
1687 int i;
1688
1689 resources = drmModeGetResources(ec->drm.fd);
1690 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001691 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001692 return;
1693 }
1694
1695 /* collect new connects */
1696 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001697 int connector_id = resources->connectors[i];
1698
1699 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001700 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001701 continue;
1702
David Herrmann7551cff2011-12-08 17:05:43 +01001703 if (connector->connection != DRM_MODE_CONNECTED) {
1704 drmModeFreeConnector(connector);
1705 continue;
1706 }
1707
Benjamin Franzke117483d2011-08-30 11:38:26 +02001708 connected |= (1 << connector_id);
1709
1710 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001711 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001712 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001713 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001714
1715 /* XXX: not yet needed, we die with 0 outputs */
1716 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001717 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718 else
1719 x = 0;
1720 y = 0;
1721 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001722 connector, x, y,
1723 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001724 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001725
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001726 }
1727 drmModeFreeConnector(connector);
1728 }
1729 drmModeFreeResources(resources);
1730
1731 disconnects = ec->connector_allocator & ~connected;
1732 if (disconnects) {
1733 wl_list_for_each_safe(output, next, &ec->base.output_list,
1734 base.link) {
1735 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001736 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001737 output->base.x - x_offset,
1738 output->base.y - y_offset);
1739 }
1740
1741 if (disconnects & (1 << output->connector_id)) {
1742 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001743 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001744 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001745 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001746 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001747 }
1748 }
1749 }
1750
1751 /* FIXME: handle zero outputs, without terminating */
1752 if (ec->connector_allocator == 0)
1753 wl_display_terminate(ec->base.wl_display);
1754}
1755
1756static int
David Herrmannd7488c22012-03-11 20:05:21 +01001757udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001758{
David Herrmannd7488c22012-03-11 20:05:21 +01001759 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001760 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001761
1762 sysnum = udev_device_get_sysnum(device);
1763 if (!sysnum || atoi(sysnum) != ec->drm.id)
1764 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001765
David Herrmann6ac52db2012-03-11 20:05:22 +01001766 val = udev_device_get_property_value(device, "HOTPLUG");
1767 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001768 return 0;
1769
David Herrmann6ac52db2012-03-11 20:05:22 +01001770 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001771}
1772
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001773static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001774udev_drm_event(int fd, uint32_t mask, void *data)
1775{
1776 struct drm_compositor *ec = data;
1777 struct udev_device *event;
1778
1779 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001780
David Herrmannd7488c22012-03-11 20:05:21 +01001781 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001782 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001783
1784 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001785
1786 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001787}
1788
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001789static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001790drm_restore(struct weston_compositor *ec)
1791{
1792 struct drm_compositor *d = (struct drm_compositor *) ec;
1793
1794 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1795 weston_log("failed to drop master: %m\n");
1796 tty_reset(d->tty);
1797}
1798
Pekka Paalanen33156972012-08-03 13:30:30 -04001799static const char default_seat[] = "seat0";
1800
1801static void
1802device_added(struct udev_device *udev_device, struct drm_seat *master)
1803{
1804 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001805 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001806 const char *devnode;
1807 const char *device_seat;
1808 int fd;
1809
1810 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1811 if (!device_seat)
1812 device_seat = default_seat;
1813
1814 if (strcmp(device_seat, master->seat_id))
1815 return;
1816
1817 c = master->base.compositor;
1818 devnode = udev_device_get_devnode(udev_device);
1819
1820 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001821 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001822 * read. mtdev_get() also expects this. */
1823 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1824 if (fd < 0) {
1825 weston_log("opening input device '%s' failed.\n", devnode);
1826 return;
1827 }
1828
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001829 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001830 if (!device) {
1831 close(fd);
1832 weston_log("not using input device '%s'.\n", devnode);
1833 return;
1834 }
1835
1836 wl_list_insert(master->devices_list.prev, &device->link);
1837}
1838
1839static void
1840evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1841{
1842 struct drm_seat *seat = (struct drm_seat *) seat_base;
1843 struct udev_enumerate *e;
1844 struct udev_list_entry *entry;
1845 struct udev_device *device;
1846 const char *path, *sysname;
1847
1848 e = udev_enumerate_new(udev);
1849 udev_enumerate_add_match_subsystem(e, "input");
1850 udev_enumerate_scan_devices(e);
1851 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1852 path = udev_list_entry_get_name(entry);
1853 device = udev_device_new_from_syspath(udev, path);
1854
1855 sysname = udev_device_get_sysname(device);
1856 if (strncmp("event", sysname, 5) != 0) {
1857 udev_device_unref(device);
1858 continue;
1859 }
1860
1861 device_added(device, seat);
1862
1863 udev_device_unref(device);
1864 }
1865 udev_enumerate_unref(e);
1866
1867 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1868
1869 if (wl_list_empty(&seat->devices_list)) {
1870 weston_log(
1871 "warning: no input devices on entering Weston. "
1872 "Possible causes:\n"
1873 "\t- no permissions to read /dev/input/event*\n"
1874 "\t- seats misconfigured "
1875 "(Weston backend option 'seat', "
1876 "udev device property ID_SEAT)\n");
1877 }
1878}
1879
1880static int
1881evdev_udev_handler(int fd, uint32_t mask, void *data)
1882{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001883 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001884 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001885 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001886 const char *action;
1887 const char *devnode;
1888
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001889 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001890 if (!udev_device)
1891 return 1;
1892
1893 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001894 if (!action)
1895 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001896
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001897 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1898 goto out;
1899
1900 if (!strcmp(action, "add")) {
1901 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001902 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001903 else if (!strcmp(action, "remove")) {
1904 devnode = udev_device_get_devnode(udev_device);
1905 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1906 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001907 weston_log("input device %s, %s removed\n",
1908 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001909 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001910 break;
1911 }
1912 }
1913
1914out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001915 udev_device_unref(udev_device);
1916
1917 return 0;
1918}
1919
1920static int
1921evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1922{
1923 struct drm_seat *master = (struct drm_seat *) seat_base;
1924 struct wl_event_loop *loop;
1925 struct weston_compositor *c = master->base.compositor;
1926 int fd;
1927
1928 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1929 if (!master->udev_monitor) {
1930 weston_log("udev: failed to create the udev monitor\n");
1931 return 0;
1932 }
1933
1934 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1935 "input", NULL);
1936
1937 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1938 weston_log("udev: failed to bind the udev monitor\n");
1939 udev_monitor_unref(master->udev_monitor);
1940 return 0;
1941 }
1942
1943 loop = wl_display_get_event_loop(c->wl_display);
1944 fd = udev_monitor_get_fd(master->udev_monitor);
1945 master->udev_monitor_source =
1946 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1947 evdev_udev_handler, master);
1948 if (!master->udev_monitor_source) {
1949 udev_monitor_unref(master->udev_monitor);
1950 return 0;
1951 }
1952
1953 return 1;
1954}
1955
1956static void
1957evdev_disable_udev_monitor(struct weston_seat *seat_base)
1958{
1959 struct drm_seat *seat = (struct drm_seat *) seat_base;
1960
1961 if (!seat->udev_monitor)
1962 return;
1963
1964 udev_monitor_unref(seat->udev_monitor);
1965 seat->udev_monitor = NULL;
1966 wl_event_source_remove(seat->udev_monitor_source);
1967 seat->udev_monitor_source = NULL;
1968}
1969
1970static void
1971drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1972{
1973 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001974 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001975
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001976 wl_list_for_each(device, &seat->devices_list, link)
1977 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001978}
1979
1980static void
1981evdev_input_create(struct weston_compositor *c, struct udev *udev,
1982 const char *seat_id)
1983{
1984 struct drm_seat *seat;
1985
1986 seat = malloc(sizeof *seat);
1987 if (seat == NULL)
1988 return;
1989
1990 memset(seat, 0, sizeof *seat);
1991 weston_seat_init(&seat->base, c);
1992 seat->base.led_update = drm_led_update;
1993
1994 wl_list_init(&seat->devices_list);
1995 seat->seat_id = strdup(seat_id);
1996 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1997 free(seat->seat_id);
1998 free(seat);
1999 return;
2000 }
2001
2002 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002003}
2004
2005static void
2006evdev_remove_devices(struct weston_seat *seat_base)
2007{
2008 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002009 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002010
2011 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002012 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002013
Pekka Paalanend8583512012-08-03 14:39:11 +03002014 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002015 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002016}
2017
2018static void
2019evdev_input_destroy(struct weston_seat *seat_base)
2020{
2021 struct drm_seat *seat = (struct drm_seat *) seat_base;
2022
2023 evdev_remove_devices(seat_base);
2024 evdev_disable_udev_monitor(&seat->base);
2025
2026 weston_seat_release(seat_base);
2027 free(seat->seat_id);
2028 free(seat);
2029}
2030
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002031static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002032drm_free_configured_output(struct drm_configured_output *output)
2033{
2034 free(output->name);
2035 free(output->mode);
2036 free(output);
2037}
2038
2039static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002040drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002041{
2042 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002043 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002044 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002045
Daniel Stone37816df2012-05-16 18:45:18 +01002046 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2047 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002048 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002049 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002050
2051 wl_event_source_remove(d->udev_drm_source);
2052 wl_event_source_remove(d->drm_source);
2053
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002054 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002055
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002056 gles2_renderer_destroy(ec);
2057
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002058 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002059 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002060 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002061 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002062 eglReleaseThread();
2063
Matt Roper361d2ad2011-08-29 13:52:23 -07002064 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002065 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002066 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002067 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002068 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002069
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002070 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002071}
2072
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002073static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002074drm_compositor_set_modes(struct drm_compositor *compositor)
2075{
2076 struct drm_output *output;
2077 struct drm_mode *drm_mode;
2078 int ret;
2079
2080 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2081 drm_mode = (struct drm_mode *) output->base.current;
2082 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002083 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002084 &output->connector_id, 1,
2085 &drm_mode->mode_info);
2086 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002087 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002088 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002089 drm_mode->base.width, drm_mode->base.height,
2090 output->base.x, output->base.y);
2091 }
2092 }
2093}
2094
2095static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002096vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002097{
2098 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002099 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002100 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002101 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002102
2103 switch (event) {
2104 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002105 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002106 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002107 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002108 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002109 wl_display_terminate(compositor->wl_display);
2110 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002111 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002112 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002113 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002114 wl_list_for_each(seat, &compositor->seat_list, link) {
2115 evdev_add_devices(ec->udev, seat);
2116 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002117 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002118 break;
2119 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002120 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002121 wl_list_for_each(seat, &compositor->seat_list, link) {
2122 evdev_disable_udev_monitor(seat);
2123 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002124 }
2125
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002126 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002127 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002128 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002129
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002130 /* If we have a repaint scheduled (either from a
2131 * pending pageflip or the idle handler), make sure we
2132 * cancel that so we don't try to pageflip when we're
2133 * vt switched away. The SLEEPING state will prevent
2134 * further attemps at repainting. When we switch
2135 * back, we schedule a repaint, which will process
2136 * pending frame callbacks. */
2137
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002138 wl_list_for_each(output, &ec->base.output_list, base.link) {
2139 output->base.repaint_needed = 0;
2140 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002141 }
2142
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002143 output = container_of(ec->base.output_list.next,
2144 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002145
2146 wl_list_for_each(sprite, &ec->sprite_list, link)
2147 drmModeSetPlane(ec->drm.fd,
2148 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002149 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002150 0, 0, 0, 0, 0, 0, 0, 0);
2151
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002152 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002153 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002154
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002155 break;
2156 };
2157}
2158
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002159static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002160switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002161{
2162 struct drm_compositor *ec = data;
2163
Daniel Stone325fc2d2012-05-30 16:31:58 +01002164 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002165}
2166
David Herrmann0af066f2012-10-29 19:21:16 +01002167/*
2168 * Find primary GPU
2169 * Some systems may have multiple DRM devices attached to a single seat. This
2170 * function loops over all devices and tries to find a PCI device with the
2171 * boot_vga sysfs attribute set to 1.
2172 * If no such device is found, the first DRM device reported by udev is used.
2173 */
2174static struct udev_device*
2175find_primary_gpu(struct drm_compositor *ec, const char *seat)
2176{
2177 struct udev_enumerate *e;
2178 struct udev_list_entry *entry;
2179 const char *path, *device_seat, *id;
2180 struct udev_device *device, *drm_device, *pci;
2181
2182 e = udev_enumerate_new(ec->udev);
2183 udev_enumerate_add_match_subsystem(e, "drm");
2184 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2185
2186 udev_enumerate_scan_devices(e);
2187 drm_device = NULL;
2188 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2189 path = udev_list_entry_get_name(entry);
2190 device = udev_device_new_from_syspath(ec->udev, path);
2191 if (!device)
2192 continue;
2193 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2194 if (!device_seat)
2195 device_seat = default_seat;
2196 if (strcmp(device_seat, seat)) {
2197 udev_device_unref(device);
2198 continue;
2199 }
2200
2201 pci = udev_device_get_parent_with_subsystem_devtype(device,
2202 "pci", NULL);
2203 if (pci) {
2204 id = udev_device_get_sysattr_value(pci, "boot_vga");
2205 if (id && !strcmp(id, "1")) {
2206 if (drm_device)
2207 udev_device_unref(drm_device);
2208 drm_device = device;
2209 break;
2210 }
2211 }
2212
2213 if (!drm_device)
2214 drm_device = device;
2215 else
2216 udev_device_unref(device);
2217 }
2218
2219 udev_enumerate_unref(e);
2220 return drm_device;
2221}
2222
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002223static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002224drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002225 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002226 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002227{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002228 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002229 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002230 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002231 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002232 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002233 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002234
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002235 weston_log("initializing drm backend\n");
2236
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002237 ec = malloc(sizeof *ec);
2238 if (ec == NULL)
2239 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002240 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002241
2242 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002243 config_file) < 0) {
2244 weston_log("weston_compositor_init failed\n");
2245 goto err_base;
2246 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002247
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002248 ec->udev = udev_new();
2249 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002250 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002251 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002252 }
2253
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002254 ec->base.wl_display = display;
2255 ec->tty = tty_create(&ec->base, vt_func, tty);
2256 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002257 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002258 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002259 }
2260
David Herrmann0af066f2012-10-29 19:21:16 +01002261 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002262 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002263 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002264 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002265 }
David Herrmann0af066f2012-10-29 19:21:16 +01002266 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002267
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002268 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002269 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002270 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002271 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002272
2273 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002274 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002275
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002276 ec->base.focus = 1;
2277
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002278 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002279
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002280 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002281 weston_compositor_add_key_binding(&ec->base, key,
2282 MODIFIER_CTRL | MODIFIER_ALT,
2283 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002284
Jesse Barnes58ef3792012-02-23 09:45:49 -05002285 wl_list_init(&ec->sprite_list);
2286 create_sprites(ec);
2287
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002288 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002289 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002290 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002291 }
2292
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002293 if (gles2_renderer_init(&ec->base) < 0)
2294 goto err_egl;
2295
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002296 path = NULL;
2297
Tiago Vignattice03ec32011-12-19 01:14:03 +02002298 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002299
2300 loop = wl_display_get_event_loop(ec->base.wl_display);
2301 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002302 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002303 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002304
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002305 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2306 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002307 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002308 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002309 }
2310 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2311 "drm", NULL);
2312 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002313 wl_event_loop_add_fd(loop,
2314 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002315 WL_EVENT_READABLE, udev_drm_event, ec);
2316
2317 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002318 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002319 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002320 }
2321
Daniel Stonea96b93c2012-06-22 14:04:37 +01002322 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002323
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002324 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002325
2326err_udev_monitor:
2327 wl_event_source_remove(ec->udev_drm_source);
2328 udev_monitor_unref(ec->udev_monitor);
2329err_drm_source:
2330 wl_event_source_remove(ec->drm_source);
2331 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2332 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002333err_egl:
2334 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2335 EGL_NO_CONTEXT);
2336 eglTerminate(ec->base.egl_display);
2337 eglReleaseThread();
2338 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002339err_sprite:
2340 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002341err_udev_dev:
2342 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002343err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002344 tty_destroy(ec->tty);
2345err_udev:
2346 udev_unref(ec->udev);
2347err_compositor:
2348 weston_compositor_shutdown(&ec->base);
2349err_base:
2350 free(ec);
2351 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002352}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002353
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002354static int
2355set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2356{
2357 mode->flags = 0;
2358
2359 if (strcmp(hsync, "+hsync") == 0)
2360 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2361 else if (strcmp(hsync, "-hsync") == 0)
2362 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2363 else
2364 return -1;
2365
2366 if (strcmp(vsync, "+vsync") == 0)
2367 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2368 else if (strcmp(vsync, "-vsync") == 0)
2369 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2370 else
2371 return -1;
2372
2373 return 0;
2374}
2375
2376static int
2377check_for_modeline(struct drm_configured_output *output)
2378{
2379 drmModeModeInfo mode;
2380 char hsync[16];
2381 char vsync[16];
2382 char mode_name[16];
2383 float fclock;
2384
2385 mode.type = DRM_MODE_TYPE_USERDEF;
2386 mode.hskew = 0;
2387 mode.vscan = 0;
2388 mode.vrefresh = 0;
2389
2390 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2391 &fclock, &mode.hdisplay,
2392 &mode.hsync_start,
2393 &mode.hsync_end, &mode.htotal,
2394 &mode.vdisplay,
2395 &mode.vsync_start,
2396 &mode.vsync_end, &mode.vtotal,
2397 hsync, vsync) == 11) {
2398 if (set_sync_flags(&mode, hsync, vsync))
2399 return -1;
2400
2401 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2402 strcpy(mode.name, mode_name);
2403
2404 mode.clock = fclock * 1000;
2405 } else
2406 return -1;
2407
2408 output->crtc_mode = mode;
2409
2410 return 0;
2411}
2412
Scott Moreau8ab5d452012-07-30 19:51:08 -06002413static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002414drm_output_set_transform(struct drm_configured_output *output)
2415{
2416 if (!output_transform) {
2417 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2418 return;
2419 }
2420
2421 if (!strcmp(output_transform, "normal"))
2422 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2423 else if (!strcmp(output_transform, "90"))
2424 output->transform = WL_OUTPUT_TRANSFORM_90;
2425 else if (!strcmp(output_transform, "180"))
2426 output->transform = WL_OUTPUT_TRANSFORM_180;
2427 else if (!strcmp(output_transform, "270"))
2428 output->transform = WL_OUTPUT_TRANSFORM_270;
2429 else if (!strcmp(output_transform, "flipped"))
2430 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2431 else if (!strcmp(output_transform, "flipped-90"))
2432 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2433 else if (!strcmp(output_transform, "flipped-180"))
2434 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2435 else if (!strcmp(output_transform, "flipped-270"))
2436 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2437 else {
2438 weston_log("Invalid transform \"%s\" for output %s\n",
2439 output_transform, output_name);
2440 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2441 }
2442
2443 free(output_transform);
2444 output_transform = NULL;
2445}
2446
2447static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002448output_section_done(void *data)
2449{
2450 struct drm_configured_output *output;
2451
2452 output = malloc(sizeof *output);
2453
Scott Moreau1bad5db2012-08-18 01:04:05 -06002454 if (!output || !output_name || (output_name[0] == 'X') ||
2455 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002456 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002457 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002458 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002459 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002460 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002461 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002462 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002463 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002464 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002465
2466 output->config = OUTPUT_CONFIG_INVALID;
2467 output->name = output_name;
2468 output->mode = output_mode;
2469
Scott Moreau1bad5db2012-08-18 01:04:05 -06002470 if (output_mode) {
2471 if (strcmp(output_mode, "off") == 0)
2472 output->config = OUTPUT_CONFIG_OFF;
2473 else if (strcmp(output_mode, "preferred") == 0)
2474 output->config = OUTPUT_CONFIG_PREFERRED;
2475 else if (strcmp(output_mode, "current") == 0)
2476 output->config = OUTPUT_CONFIG_CURRENT;
2477 else if (sscanf(output_mode, "%dx%d",
2478 &output->width, &output->height) == 2)
2479 output->config = OUTPUT_CONFIG_MODE;
2480 else if (check_for_modeline(output) == 0)
2481 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002482
Scott Moreau1bad5db2012-08-18 01:04:05 -06002483 if (output->config == OUTPUT_CONFIG_INVALID)
2484 weston_log("Invalid mode \"%s\" for output %s\n",
2485 output_mode, output_name);
2486 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002487 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002488
2489 drm_output_set_transform(output);
2490
2491 wl_list_insert(&configured_output_list, &output->link);
2492
2493 if (output_transform)
2494 free(output_transform);
2495 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002496}
2497
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002498WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002499backend_init(struct wl_display *display, int argc, char *argv[],
2500 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002501{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002502 int connector = 0, tty = 0;
2503 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002504
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002505 const struct weston_option drm_options[] = {
2506 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2507 { WESTON_OPTION_STRING, "seat", 0, &seat },
2508 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002509 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002510 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002511
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002512 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002513
Scott Moreau8ab5d452012-07-30 19:51:08 -06002514 wl_list_init(&configured_output_list);
2515
2516 const struct config_key drm_config_keys[] = {
2517 { "name", CONFIG_KEY_STRING, &output_name },
2518 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002519 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002520 };
2521
2522 const struct config_section config_section[] = {
2523 { "output", drm_config_keys,
2524 ARRAY_LENGTH(drm_config_keys), output_section_done },
2525 };
2526
2527 parse_config_file(config_file, config_section,
2528 ARRAY_LENGTH(config_section), NULL);
2529
Daniel Stonec1be8e52012-06-01 11:14:02 -04002530 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2531 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002532}