blob: 1730cb2bee759409550752e752df87715c79342d [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;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400796 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400798 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799
800 /*
801 * Find a surface for each sprite in the output using some heuristics:
802 * 1) size
803 * 2) frequency of update
804 * 3) opacity (though some hw might support alpha blending)
805 * 4) clipping (this can be fixed with color keys)
806 *
807 * The idea is to save on blitting since this should save power.
808 * If we can get a large video surface on the sprite for example,
809 * the main display surface may not need to update at all, and
810 * the client buffer can be used directly for the sprite surface
811 * as we do for flipping full screen surfaces.
812 */
813 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400814 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400815 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816 pixman_region32_init(&surface_overlap);
817 pixman_region32_intersect(&surface_overlap, &overlap,
818 &es->transform.boundingbox);
819
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400820 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400821 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400822 next_plane = primary;
823 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400824 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400825 if (next_plane == NULL)
826 next_plane = drm_output_prepare_scanout_surface(output, es);
827 if (next_plane == NULL)
828 next_plane = drm_output_prepare_overlay_surface(output, es);
829 if (next_plane == NULL)
830 next_plane = primary;
831 weston_surface_move_to_plane(es, next_plane);
832 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833 pixman_region32_union(&overlap, &overlap,
834 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400835
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836 pixman_region32_fini(&surface_overlap);
837 }
838 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839}
840
Matt Roper361d2ad2011-08-29 13:52:23 -0700841static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500842drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700843{
844 struct drm_output *output = (struct drm_output *) output_base;
845 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200846 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700847 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700848
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200849 if (output->backlight)
850 backlight_destroy(output->backlight);
851
Matt Roper361d2ad2011-08-29 13:52:23 -0700852 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400853 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700854
855 /* Restore original CRTC state */
856 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200857 origcrtc->x, origcrtc->y,
858 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700859 drmModeFreeCrtc(origcrtc);
860
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200861 c->crtc_allocator &= ~(1 << output->crtc_id);
862 c->connector_allocator &= ~(1 << output->connector_id);
863
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400864 eglDestroySurface(c->base.egl_display, output->base.egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400865 gbm_surface_destroy(output->surface);
866
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400867 weston_plane_release(&output->fb_plane);
868 weston_plane_release(&output->cursor_plane);
869
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500870 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200871 wl_list_remove(&output->base.link);
872
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400873 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700874 free(output);
875}
876
Alex Wub7b8bda2012-04-17 17:20:48 +0800877static struct drm_mode *
878choose_mode (struct drm_output *output, struct weston_mode *target_mode)
879{
880 struct drm_mode *tmp_mode = NULL, *mode;
881
882 if (output->base.current->width == target_mode->width &&
883 output->base.current->height == target_mode->height &&
884 (output->base.current->refresh == target_mode->refresh ||
885 target_mode->refresh == 0))
886 return (struct drm_mode *)output->base.current;
887
888 wl_list_for_each(mode, &output->base.mode_list, base.link) {
889 if (mode->mode_info.hdisplay == target_mode->width &&
890 mode->mode_info.vdisplay == target_mode->height) {
891 if (mode->mode_info.vrefresh == target_mode->refresh ||
892 target_mode->refresh == 0) {
893 return mode;
894 } else if (!tmp_mode)
895 tmp_mode = mode;
896 }
897 }
898
899 return tmp_mode;
900}
901
902static int
903drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
904{
905 struct drm_output *output;
906 struct drm_mode *drm_mode;
907 int ret;
908 struct drm_compositor *ec;
909 struct gbm_surface *surface;
910 EGLSurface egl_surface;
911
912 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200913 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800914 return -1;
915 }
916
917 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200918 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800919 return -1;
920 }
921
922 ec = (struct drm_compositor *)output_base->compositor;
923 output = (struct drm_output *)output_base;
924 drm_mode = choose_mode (output, mode);
925
926 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200927 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800928 return -1;
929 } else if (&drm_mode->base == output->base.current) {
930 return 0;
931 } else if (drm_mode->base.width == output->base.current->width &&
932 drm_mode->base.height == output->base.current->height) {
933 /* only change refresh value */
934 ret = drmModeSetCrtc(ec->drm.fd,
935 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300936 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800937 &output->connector_id, 1, &drm_mode->mode_info);
938
939 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200940 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800941 drm_mode->base.width,
942 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400943 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800944 ret = -1;
945 } else {
946 output->base.current->flags = 0;
947 output->base.current = &drm_mode->base;
948 drm_mode->base.flags =
949 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
950 ret = 0;
951 }
952
953 return ret;
954 }
955
956 drm_mode->base.flags =
957 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
958
959 surface = gbm_surface_create(ec->gbm,
960 drm_mode->base.width,
961 drm_mode->base.height,
962 GBM_FORMAT_XRGB8888,
963 GBM_BO_USE_SCANOUT |
964 GBM_BO_USE_RENDERING);
965 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200966 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800967 return -1;
968 }
969
970 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400971 eglCreateWindowSurface(ec->base.egl_display,
972 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 surface, NULL);
974
975 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200976 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800977 goto err;
978 }
979
980 ret = drmModeSetCrtc(ec->drm.fd,
981 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300982 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800983 &output->connector_id, 1, &drm_mode->mode_info);
984 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200985 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800986 goto err;
987 }
988
989 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300990 if (output->current) {
991 if (output->current->is_client_buffer)
992 gbm_bo_destroy(output->current->bo);
993 else
994 gbm_surface_release_buffer(output->surface,
995 output->current->bo);
996 }
997 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800998
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300999 if (output->next) {
1000 if (output->next->is_client_buffer)
1001 gbm_bo_destroy(output->next->bo);
1002 else
1003 gbm_surface_release_buffer(output->surface,
1004 output->next->bo);
1005 }
1006 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001007
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001008 eglDestroySurface(ec->base.egl_display, output->base.egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001009 gbm_surface_destroy(output->surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001010 output->base.egl_surface = egl_surface;
Alex Wub7b8bda2012-04-17 17:20:48 +08001011 output->surface = surface;
1012
1013 /*update output*/
1014 output->base.current = &drm_mode->base;
1015 output->base.dirty = 1;
1016 weston_output_move(&output->base, output->base.x, output->base.y);
1017 return 0;
1018
1019err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001020 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001021 gbm_surface_destroy(surface);
1022 return -1;
1023}
1024
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001025static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001026on_drm_input(int fd, uint32_t mask, void *data)
1027{
1028 drmEventContext evctx;
1029
1030 memset(&evctx, 0, sizeof evctx);
1031 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1032 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001033 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001034 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001035
1036 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001037}
1038
1039static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001040init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001041{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001042 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001043 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001044 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001045 static const EGLint config_attribs[] = {
1046 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1047 EGL_RED_SIZE, 1,
1048 EGL_GREEN_SIZE, 1,
1049 EGL_BLUE_SIZE, 1,
1050 EGL_ALPHA_SIZE, 0,
1051 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1052 EGL_NONE
1053 };
1054
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001055 sysnum = udev_device_get_sysnum(device);
1056 if (sysnum)
1057 ec->drm.id = atoi(sysnum);
1058 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001059 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001060 return -1;
1061 }
1062
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001063 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001064 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001065 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001066 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001067 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001068 udev_device_get_devnode(device));
1069 return -1;
1070 }
1071
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001072 weston_log("using %s\n", filename);
1073
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001074 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001075 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001076 ec->base.egl_display = eglGetDisplay(ec->gbm);
1077 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001078 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001079 return -1;
1080 }
1081
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001082 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001083 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001084 return -1;
1085 }
1086
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001087 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1088 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001089 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001090 return -1;
1091 }
1092
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001093 return 0;
1094}
1095
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001096static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001097drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1098{
1099 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001100 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001101
1102 mode = malloc(sizeof *mode);
1103 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001104 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001105
1106 mode->base.flags = 0;
1107 mode->base.width = info->hdisplay;
1108 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001109
1110 /* Calculate higher precision (mHz) refresh rate */
1111 refresh = (info->clock * 1000000LL / info->htotal +
1112 info->vtotal / 2) / info->vtotal;
1113
1114 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1115 refresh *= 2;
1116 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1117 refresh /= 2;
1118 if (info->vscan > 1)
1119 refresh /= info->vscan;
1120
1121 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001122 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001123
1124 if (info->type & DRM_MODE_TYPE_PREFERRED)
1125 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1126
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001127 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1128
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001129 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001130}
1131
1132static int
1133drm_subpixel_to_wayland(int drm_value)
1134{
1135 switch (drm_value) {
1136 default:
1137 case DRM_MODE_SUBPIXEL_UNKNOWN:
1138 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1139 case DRM_MODE_SUBPIXEL_NONE:
1140 return WL_OUTPUT_SUBPIXEL_NONE;
1141 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1142 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1143 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1144 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1145 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1146 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1147 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1148 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1149 }
1150}
1151
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001152static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001153sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001154{
1155 struct drm_sprite *sprite =
1156 container_of(listener, struct drm_sprite,
1157 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001158 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001159
1160 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001161 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1162 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001163}
1164
1165static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001166sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001167{
1168 struct drm_sprite *sprite =
1169 container_of(listener, struct drm_sprite,
1170 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001171 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001172
1173 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001174 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1175 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001176}
1177
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001178/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001179static uint32_t
1180drm_get_backlight(struct drm_output *output)
1181{
1182 long brightness, max_brightness, norm;
1183
1184 brightness = backlight_get_brightness(output->backlight);
1185 max_brightness = backlight_get_max_brightness(output->backlight);
1186
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001187 /* convert it on a scale of 0 to 255 */
1188 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001189
1190 return (uint32_t) norm;
1191}
1192
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001193/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001194static void
1195drm_set_backlight(struct weston_output *output_base, uint32_t value)
1196{
1197 struct drm_output *output = (struct drm_output *) output_base;
1198 long max_brightness, new_brightness;
1199
1200 if (!output->backlight)
1201 return;
1202
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001203 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001204 return;
1205
1206 max_brightness = backlight_get_max_brightness(output->backlight);
1207
1208 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001209 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001210
1211 backlight_set_brightness(output->backlight, new_brightness);
1212}
1213
1214static drmModePropertyPtr
1215drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1216{
1217 drmModePropertyPtr props;
1218 int i;
1219
1220 for (i = 0; i < connector->count_props; i++) {
1221 props = drmModeGetProperty(fd, connector->props[i]);
1222 if (!props)
1223 continue;
1224
1225 if (!strcmp(props->name, name))
1226 return props;
1227
1228 drmModeFreeProperty(props);
1229 }
1230
1231 return NULL;
1232}
1233
1234static void
1235drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1236{
1237 struct drm_output *output = (struct drm_output *) output_base;
1238 struct weston_compositor *ec = output_base->compositor;
1239 struct drm_compositor *c = (struct drm_compositor *) ec;
1240 drmModeConnectorPtr connector;
1241 drmModePropertyPtr prop;
1242
1243 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1244 if (!connector)
1245 return;
1246
1247 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1248 if (!prop) {
1249 drmModeFreeConnector(connector);
1250 return;
1251 }
1252
1253 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1254 prop->prop_id, level);
1255 drmModeFreeProperty(prop);
1256 drmModeFreeConnector(connector);
1257}
1258
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001259static const char *connector_type_names[] = {
1260 "None",
1261 "VGA",
1262 "DVI",
1263 "DVI",
1264 "DVI",
1265 "Composite",
1266 "TV",
1267 "LVDS",
1268 "CTV",
1269 "DIN",
1270 "DP",
1271 "HDMI",
1272 "HDMI",
1273 "TV",
1274 "eDP",
1275};
1276
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001277static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001278find_crtc_for_connector(struct drm_compositor *ec,
1279 drmModeRes *resources, drmModeConnector *connector)
1280{
1281 drmModeEncoder *encoder;
1282 uint32_t possible_crtcs;
1283 int i, j;
1284
1285 for (j = 0; j < connector->count_encoders; j++) {
1286 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1287 if (encoder == NULL) {
1288 weston_log("Failed to get encoder.\n");
1289 return -1;
1290 }
1291 possible_crtcs = encoder->possible_crtcs;
1292 drmModeFreeEncoder(encoder);
1293
1294 for (i = 0; i < resources->count_crtcs; i++) {
1295 if (possible_crtcs & (1 << i) &&
1296 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1297 return i;
1298 }
1299 }
1300
1301 return -1;
1302}
1303
1304static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001305create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001306 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001307 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001308 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001309{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001310 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001311 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1312 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001313 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001314 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001315 drmModeModeInfo crtc_mode;
1316 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001317 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001318 char name[32];
1319 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001320
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001321 i = find_crtc_for_connector(ec, resources, connector);
1322 if (i < 0) {
1323 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001324 return -1;
1325 }
1326
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001327 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001328 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001329 return -1;
1330
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001331 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001332 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1333 output->base.make = "unknown";
1334 output->base.model = "unknown";
1335 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001336
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001337 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1338 type_name = connector_type_names[connector->connector_type];
1339 else
1340 type_name = "UNKNOWN";
1341 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1342 output->name = strdup(name);
1343
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001344 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001345 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001346 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001347 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001348 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001349
Matt Roper361d2ad2011-08-29 13:52:23 -07001350 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1351
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001352 /* Get the current mode on the crtc that's currently driving
1353 * this connector. */
1354 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001355 memset(&crtc_mode, 0, sizeof crtc_mode);
1356 if (encoder != NULL) {
1357 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1358 drmModeFreeEncoder(encoder);
1359 if (crtc == NULL)
1360 goto err_free;
1361 if (crtc->mode_valid)
1362 crtc_mode = crtc->mode;
1363 drmModeFreeCrtc(crtc);
1364 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001365
David Herrmann0f0d54e2011-12-08 17:05:45 +01001366 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001367 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1368 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001369 goto err_free;
1370 }
1371
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001372 preferred = NULL;
1373 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001374 configured = NULL;
1375
1376 wl_list_for_each(temp, &configured_output_list, link) {
1377 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001378 if (temp->mode)
1379 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001380 temp->name, temp->mode);
1381 o = temp;
1382 break;
1383 }
1384 }
1385
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001386 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001387 weston_log("Disabling output %s\n", o->name);
1388
1389 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1390 0, 0, 0, 0, 0, NULL);
1391 goto err_free;
1392 }
1393
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001394 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001395 if (o && o->config == OUTPUT_CONFIG_MODE &&
1396 o->width == drm_mode->base.width &&
1397 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001398 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001399 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001400 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001401 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001402 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001403 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001404
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001405 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001406 configured = drm_output_add_mode(output, &o->crtc_mode);
1407 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001408 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001409 current = configured;
1410 }
1411
Wang Quanxianacb805a2012-07-30 18:09:46 -04001412 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001413 current = drm_output_add_mode(output, &crtc_mode);
1414 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001415 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001416 }
1417
Scott Moreau8ab5d452012-07-30 19:51:08 -06001418 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1419 configured = current;
1420
Wang Quanxianacb805a2012-07-30 18:09:46 -04001421 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001422 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001423 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001424 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001425 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001426 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001427 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001428 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001429
1430 if (output->base.current == NULL) {
1431 weston_log("no available modes for %s\n", output->name);
1432 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001433 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001434
Wang Quanxianacb805a2012-07-30 18:09:46 -04001435 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1436
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001437 output->surface = gbm_surface_create(ec->gbm,
1438 output->base.current->width,
1439 output->base.current->height,
1440 GBM_FORMAT_XRGB8888,
1441 GBM_BO_USE_SCANOUT |
1442 GBM_BO_USE_RENDERING);
1443 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001444 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001445 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001446 }
1447
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001448 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001449 eglCreateWindowSurface(ec->base.egl_display,
1450 ec->base.egl_config,
1451 output->surface,
1452 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001453 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001454 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001455 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001456 }
1457
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001458 output->cursor_bo[0] =
1459 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1460 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1461 output->cursor_bo[1] =
1462 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1463 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001464 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1465 weston_log("cursor buffers unavailable, using gl cursors\n");
1466 ec->cursors_are_broken = 1;
1467 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001468
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001469 output->backlight = backlight_init(drm_device,
1470 connector->connector_type);
1471 if (output->backlight) {
1472 output->base.set_backlight = drm_set_backlight;
1473 output->base.backlight_current = drm_get_backlight(output);
1474 }
1475
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001476 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001477 connector->mmWidth, connector->mmHeight,
1478 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001479
1480 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1481
Alex Wubd3354b2012-04-17 17:20:49 +08001482 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001483 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001484 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001485 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001486 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001487 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001488
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001489 weston_plane_init(&output->cursor_plane, 0, 0);
1490 weston_plane_init(&output->fb_plane, 0, 0);
1491
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001492 weston_log("Output %s, (connector %d, crtc %d)\n",
1493 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001494 wl_list_for_each(m, &output->base.mode_list, link)
1495 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1496 m->width, m->height, m->refresh / 1000.0,
1497 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1498 ", preferred" : "",
1499 m->flags & WL_OUTPUT_MODE_CURRENT ?
1500 ", current" : "",
1501 connector->count_modes == 0 ?
1502 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001503
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001504 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001505
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001506err_surface:
1507 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001508err_free:
1509 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1510 base.link) {
1511 wl_list_remove(&drm_mode->base.link);
1512 free(drm_mode);
1513 }
1514
1515 drmModeFreeCrtc(output->original_crtc);
1516 ec->crtc_allocator &= ~(1 << output->crtc_id);
1517 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001518 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001519 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001520
David Herrmann0f0d54e2011-12-08 17:05:45 +01001521 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001522}
1523
Jesse Barnes58ef3792012-02-23 09:45:49 -05001524static void
1525create_sprites(struct drm_compositor *ec)
1526{
1527 struct drm_sprite *sprite;
1528 drmModePlaneRes *plane_res;
1529 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001530 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001531
1532 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1533 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001534 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001535 strerror(errno));
1536 return;
1537 }
1538
1539 for (i = 0; i < plane_res->count_planes; i++) {
1540 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1541 if (!plane)
1542 continue;
1543
1544 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1545 plane->count_formats));
1546 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001547 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001548 __func__);
1549 free(plane);
1550 continue;
1551 }
1552
1553 memset(sprite, 0, sizeof *sprite);
1554
1555 sprite->possible_crtcs = plane->possible_crtcs;
1556 sprite->plane_id = plane->plane_id;
1557 sprite->surface = NULL;
1558 sprite->pending_surface = NULL;
1559 sprite->fb_id = 0;
1560 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001561 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1562 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001563 sprite_handle_pending_buffer_destroy;
1564 sprite->compositor = ec;
1565 sprite->count_formats = plane->count_formats;
1566 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001567 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001568 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001569 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001570
1571 wl_list_insert(&ec->sprite_list, &sprite->link);
1572 }
1573
1574 free(plane_res->planes);
1575 free(plane_res);
1576}
1577
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001578static void
1579destroy_sprites(struct drm_compositor *compositor)
1580{
1581 struct drm_sprite *sprite, *next;
1582 struct drm_output *output;
1583
1584 output = container_of(compositor->base.output_list.next,
1585 struct drm_output, base.link);
1586
1587 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1588 drmModeSetPlane(compositor->drm.fd,
1589 sprite->plane_id,
1590 output->crtc_id, 0, 0,
1591 0, 0, 0, 0, 0, 0, 0, 0);
1592 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001593 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001594 free(sprite);
1595 }
1596}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001597
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001598static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001599create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001600 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001601{
1602 drmModeConnector *connector;
1603 drmModeRes *resources;
1604 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001605 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001606
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001607 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001608 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001609 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001610 return -1;
1611 }
1612
Jesse Barnes58ef3792012-02-23 09:45:49 -05001613 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001614 if (!ec->crtcs) {
1615 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001616 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001617 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001618
Rob Clark4339add2012-08-09 14:18:28 -05001619 ec->min_width = resources->min_width;
1620 ec->max_width = resources->max_width;
1621 ec->min_height = resources->min_height;
1622 ec->max_height = resources->max_height;
1623
Jesse Barnes58ef3792012-02-23 09:45:49 -05001624 ec->num_crtcs = resources->count_crtcs;
1625 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1626
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001627 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001628 connector = drmModeGetConnector(ec->drm.fd,
1629 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001630 if (connector == NULL)
1631 continue;
1632
1633 if (connector->connection == DRM_MODE_CONNECTED &&
1634 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001635 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001636 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001637 connector, x, y,
1638 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001639 drmModeFreeConnector(connector);
1640 continue;
1641 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001642
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001643 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001644 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001645 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001646 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001647
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001648 drmModeFreeConnector(connector);
1649 }
1650
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001651 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001652 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001653 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001654 return -1;
1655 }
1656
1657 drmModeFreeResources(resources);
1658
1659 return 0;
1660}
1661
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001662static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001663update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001664{
1665 drmModeConnector *connector;
1666 drmModeRes *resources;
1667 struct drm_output *output, *next;
1668 int x = 0, y = 0;
1669 int x_offset = 0, y_offset = 0;
1670 uint32_t connected = 0, disconnects = 0;
1671 int i;
1672
1673 resources = drmModeGetResources(ec->drm.fd);
1674 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001675 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001676 return;
1677 }
1678
1679 /* collect new connects */
1680 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001681 int connector_id = resources->connectors[i];
1682
1683 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001684 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001685 continue;
1686
David Herrmann7551cff2011-12-08 17:05:43 +01001687 if (connector->connection != DRM_MODE_CONNECTED) {
1688 drmModeFreeConnector(connector);
1689 continue;
1690 }
1691
Benjamin Franzke117483d2011-08-30 11:38:26 +02001692 connected |= (1 << connector_id);
1693
1694 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001695 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001696 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001697 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001698
1699 /* XXX: not yet needed, we die with 0 outputs */
1700 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001701 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001702 else
1703 x = 0;
1704 y = 0;
1705 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001706 connector, x, y,
1707 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001708 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001709
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001710 }
1711 drmModeFreeConnector(connector);
1712 }
1713 drmModeFreeResources(resources);
1714
1715 disconnects = ec->connector_allocator & ~connected;
1716 if (disconnects) {
1717 wl_list_for_each_safe(output, next, &ec->base.output_list,
1718 base.link) {
1719 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001720 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001721 output->base.x - x_offset,
1722 output->base.y - y_offset);
1723 }
1724
1725 if (disconnects & (1 << output->connector_id)) {
1726 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001727 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001728 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001729 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001730 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001731 }
1732 }
1733 }
1734
1735 /* FIXME: handle zero outputs, without terminating */
1736 if (ec->connector_allocator == 0)
1737 wl_display_terminate(ec->base.wl_display);
1738}
1739
1740static int
David Herrmannd7488c22012-03-11 20:05:21 +01001741udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001742{
David Herrmannd7488c22012-03-11 20:05:21 +01001743 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001744 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001745
1746 sysnum = udev_device_get_sysnum(device);
1747 if (!sysnum || atoi(sysnum) != ec->drm.id)
1748 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001749
David Herrmann6ac52db2012-03-11 20:05:22 +01001750 val = udev_device_get_property_value(device, "HOTPLUG");
1751 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001752 return 0;
1753
David Herrmann6ac52db2012-03-11 20:05:22 +01001754 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001755}
1756
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001757static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001758udev_drm_event(int fd, uint32_t mask, void *data)
1759{
1760 struct drm_compositor *ec = data;
1761 struct udev_device *event;
1762
1763 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001764
David Herrmannd7488c22012-03-11 20:05:21 +01001765 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001766 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001767
1768 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001769
1770 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001771}
1772
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001773static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001774drm_restore(struct weston_compositor *ec)
1775{
1776 struct drm_compositor *d = (struct drm_compositor *) ec;
1777
1778 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1779 weston_log("failed to drop master: %m\n");
1780 tty_reset(d->tty);
1781}
1782
Pekka Paalanen33156972012-08-03 13:30:30 -04001783static const char default_seat[] = "seat0";
1784
1785static void
1786device_added(struct udev_device *udev_device, struct drm_seat *master)
1787{
1788 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001789 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001790 const char *devnode;
1791 const char *device_seat;
1792 int fd;
1793
1794 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1795 if (!device_seat)
1796 device_seat = default_seat;
1797
1798 if (strcmp(device_seat, master->seat_id))
1799 return;
1800
1801 c = master->base.compositor;
1802 devnode = udev_device_get_devnode(udev_device);
1803
1804 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001805 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001806 * read. mtdev_get() also expects this. */
1807 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1808 if (fd < 0) {
1809 weston_log("opening input device '%s' failed.\n", devnode);
1810 return;
1811 }
1812
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001813 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001814 if (!device) {
1815 close(fd);
1816 weston_log("not using input device '%s'.\n", devnode);
1817 return;
1818 }
1819
1820 wl_list_insert(master->devices_list.prev, &device->link);
1821}
1822
1823static void
1824evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1825{
1826 struct drm_seat *seat = (struct drm_seat *) seat_base;
1827 struct udev_enumerate *e;
1828 struct udev_list_entry *entry;
1829 struct udev_device *device;
1830 const char *path, *sysname;
1831
1832 e = udev_enumerate_new(udev);
1833 udev_enumerate_add_match_subsystem(e, "input");
1834 udev_enumerate_scan_devices(e);
1835 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1836 path = udev_list_entry_get_name(entry);
1837 device = udev_device_new_from_syspath(udev, path);
1838
1839 sysname = udev_device_get_sysname(device);
1840 if (strncmp("event", sysname, 5) != 0) {
1841 udev_device_unref(device);
1842 continue;
1843 }
1844
1845 device_added(device, seat);
1846
1847 udev_device_unref(device);
1848 }
1849 udev_enumerate_unref(e);
1850
1851 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1852
1853 if (wl_list_empty(&seat->devices_list)) {
1854 weston_log(
1855 "warning: no input devices on entering Weston. "
1856 "Possible causes:\n"
1857 "\t- no permissions to read /dev/input/event*\n"
1858 "\t- seats misconfigured "
1859 "(Weston backend option 'seat', "
1860 "udev device property ID_SEAT)\n");
1861 }
1862}
1863
1864static int
1865evdev_udev_handler(int fd, uint32_t mask, void *data)
1866{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001867 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001868 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001869 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001870 const char *action;
1871 const char *devnode;
1872
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001873 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001874 if (!udev_device)
1875 return 1;
1876
1877 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001878 if (!action)
1879 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001880
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001881 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1882 goto out;
1883
1884 if (!strcmp(action, "add")) {
1885 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001886 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001887 else if (!strcmp(action, "remove")) {
1888 devnode = udev_device_get_devnode(udev_device);
1889 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1890 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001891 weston_log("input device %s, %s removed\n",
1892 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001893 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001894 break;
1895 }
1896 }
1897
1898out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001899 udev_device_unref(udev_device);
1900
1901 return 0;
1902}
1903
1904static int
1905evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1906{
1907 struct drm_seat *master = (struct drm_seat *) seat_base;
1908 struct wl_event_loop *loop;
1909 struct weston_compositor *c = master->base.compositor;
1910 int fd;
1911
1912 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1913 if (!master->udev_monitor) {
1914 weston_log("udev: failed to create the udev monitor\n");
1915 return 0;
1916 }
1917
1918 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1919 "input", NULL);
1920
1921 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1922 weston_log("udev: failed to bind the udev monitor\n");
1923 udev_monitor_unref(master->udev_monitor);
1924 return 0;
1925 }
1926
1927 loop = wl_display_get_event_loop(c->wl_display);
1928 fd = udev_monitor_get_fd(master->udev_monitor);
1929 master->udev_monitor_source =
1930 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1931 evdev_udev_handler, master);
1932 if (!master->udev_monitor_source) {
1933 udev_monitor_unref(master->udev_monitor);
1934 return 0;
1935 }
1936
1937 return 1;
1938}
1939
1940static void
1941evdev_disable_udev_monitor(struct weston_seat *seat_base)
1942{
1943 struct drm_seat *seat = (struct drm_seat *) seat_base;
1944
1945 if (!seat->udev_monitor)
1946 return;
1947
1948 udev_monitor_unref(seat->udev_monitor);
1949 seat->udev_monitor = NULL;
1950 wl_event_source_remove(seat->udev_monitor_source);
1951 seat->udev_monitor_source = NULL;
1952}
1953
1954static void
1955drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1956{
1957 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001958 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001959
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001960 wl_list_for_each(device, &seat->devices_list, link)
1961 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001962}
1963
1964static void
1965evdev_input_create(struct weston_compositor *c, struct udev *udev,
1966 const char *seat_id)
1967{
1968 struct drm_seat *seat;
1969
1970 seat = malloc(sizeof *seat);
1971 if (seat == NULL)
1972 return;
1973
1974 memset(seat, 0, sizeof *seat);
1975 weston_seat_init(&seat->base, c);
1976 seat->base.led_update = drm_led_update;
1977
1978 wl_list_init(&seat->devices_list);
1979 seat->seat_id = strdup(seat_id);
1980 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1981 free(seat->seat_id);
1982 free(seat);
1983 return;
1984 }
1985
1986 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001987}
1988
1989static void
1990evdev_remove_devices(struct weston_seat *seat_base)
1991{
1992 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001993 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001994
1995 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001996 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001997
Pekka Paalanend8583512012-08-03 14:39:11 +03001998 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001999 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002000}
2001
2002static void
2003evdev_input_destroy(struct weston_seat *seat_base)
2004{
2005 struct drm_seat *seat = (struct drm_seat *) seat_base;
2006
2007 evdev_remove_devices(seat_base);
2008 evdev_disable_udev_monitor(&seat->base);
2009
2010 weston_seat_release(seat_base);
2011 free(seat->seat_id);
2012 free(seat);
2013}
2014
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002015static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002016drm_free_configured_output(struct drm_configured_output *output)
2017{
2018 free(output->name);
2019 free(output->mode);
2020 free(output);
2021}
2022
2023static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002024drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002025{
2026 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002027 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002028 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002029
Daniel Stone37816df2012-05-16 18:45:18 +01002030 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2031 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002032 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002033 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002034
2035 wl_event_source_remove(d->udev_drm_source);
2036 wl_event_source_remove(d->drm_source);
2037
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002038 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002039
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002040 gles2_renderer_destroy(ec);
2041
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002042 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002043 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002044 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002045 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002046 eglReleaseThread();
2047
Matt Roper361d2ad2011-08-29 13:52:23 -07002048 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002049 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002050 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002051 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002052 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002053
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002054 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002055}
2056
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002057static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002058drm_compositor_set_modes(struct drm_compositor *compositor)
2059{
2060 struct drm_output *output;
2061 struct drm_mode *drm_mode;
2062 int ret;
2063
2064 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2065 drm_mode = (struct drm_mode *) output->base.current;
2066 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002067 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002068 &output->connector_id, 1,
2069 &drm_mode->mode_info);
2070 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002071 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002072 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002073 drm_mode->base.width, drm_mode->base.height,
2074 output->base.x, output->base.y);
2075 }
2076 }
2077}
2078
2079static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002080vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002081{
2082 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002083 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002084 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002085 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002086
2087 switch (event) {
2088 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002089 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002090 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002091 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002092 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002093 wl_display_terminate(compositor->wl_display);
2094 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002095 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002096 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002097 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002098 wl_list_for_each(seat, &compositor->seat_list, link) {
2099 evdev_add_devices(ec->udev, seat);
2100 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002101 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002102 break;
2103 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002104 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002105 wl_list_for_each(seat, &compositor->seat_list, link) {
2106 evdev_disable_udev_monitor(seat);
2107 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002108 }
2109
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002110 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002111 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002112 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002113
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002114 /* If we have a repaint scheduled (either from a
2115 * pending pageflip or the idle handler), make sure we
2116 * cancel that so we don't try to pageflip when we're
2117 * vt switched away. The SLEEPING state will prevent
2118 * further attemps at repainting. When we switch
2119 * back, we schedule a repaint, which will process
2120 * pending frame callbacks. */
2121
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002122 wl_list_for_each(output, &ec->base.output_list, base.link) {
2123 output->base.repaint_needed = 0;
2124 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002125 }
2126
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002127 output = container_of(ec->base.output_list.next,
2128 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002129
2130 wl_list_for_each(sprite, &ec->sprite_list, link)
2131 drmModeSetPlane(ec->drm.fd,
2132 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002133 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002134 0, 0, 0, 0, 0, 0, 0, 0);
2135
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002136 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002137 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002138
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002139 break;
2140 };
2141}
2142
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002143static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002144switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002145{
2146 struct drm_compositor *ec = data;
2147
Daniel Stone325fc2d2012-05-30 16:31:58 +01002148 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002149}
2150
David Herrmann0af066f2012-10-29 19:21:16 +01002151/*
2152 * Find primary GPU
2153 * Some systems may have multiple DRM devices attached to a single seat. This
2154 * function loops over all devices and tries to find a PCI device with the
2155 * boot_vga sysfs attribute set to 1.
2156 * If no such device is found, the first DRM device reported by udev is used.
2157 */
2158static struct udev_device*
2159find_primary_gpu(struct drm_compositor *ec, const char *seat)
2160{
2161 struct udev_enumerate *e;
2162 struct udev_list_entry *entry;
2163 const char *path, *device_seat, *id;
2164 struct udev_device *device, *drm_device, *pci;
2165
2166 e = udev_enumerate_new(ec->udev);
2167 udev_enumerate_add_match_subsystem(e, "drm");
2168 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2169
2170 udev_enumerate_scan_devices(e);
2171 drm_device = NULL;
2172 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2173 path = udev_list_entry_get_name(entry);
2174 device = udev_device_new_from_syspath(ec->udev, path);
2175 if (!device)
2176 continue;
2177 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2178 if (!device_seat)
2179 device_seat = default_seat;
2180 if (strcmp(device_seat, seat)) {
2181 udev_device_unref(device);
2182 continue;
2183 }
2184
2185 pci = udev_device_get_parent_with_subsystem_devtype(device,
2186 "pci", NULL);
2187 if (pci) {
2188 id = udev_device_get_sysattr_value(pci, "boot_vga");
2189 if (id && !strcmp(id, "1")) {
2190 if (drm_device)
2191 udev_device_unref(drm_device);
2192 drm_device = device;
2193 break;
2194 }
2195 }
2196
2197 if (!drm_device)
2198 drm_device = device;
2199 else
2200 udev_device_unref(device);
2201 }
2202
2203 udev_enumerate_unref(e);
2204 return drm_device;
2205}
2206
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002207static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002208drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002209 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002210 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002212 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002213 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002214 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002215 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002216 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002217 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002218
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002219 weston_log("initializing drm backend\n");
2220
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002221 ec = malloc(sizeof *ec);
2222 if (ec == NULL)
2223 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002224 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002225
2226 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002227 config_file) < 0) {
2228 weston_log("weston_compositor_init failed\n");
2229 goto err_base;
2230 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002231
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002232 ec->udev = udev_new();
2233 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002234 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002235 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236 }
2237
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002238 ec->base.wl_display = display;
2239 ec->tty = tty_create(&ec->base, vt_func, tty);
2240 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002241 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002242 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002243 }
2244
David Herrmann0af066f2012-10-29 19:21:16 +01002245 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002246 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002247 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002248 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002249 }
David Herrmann0af066f2012-10-29 19:21:16 +01002250 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002251
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002252 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002253 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002254 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002255 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002256
2257 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002258 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002259
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002260 ec->base.focus = 1;
2261
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002262 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002263
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002264 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002265 weston_compositor_add_key_binding(&ec->base, key,
2266 MODIFIER_CTRL | MODIFIER_ALT,
2267 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002268
Jesse Barnes58ef3792012-02-23 09:45:49 -05002269 wl_list_init(&ec->sprite_list);
2270 create_sprites(ec);
2271
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002272 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002273 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002274 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002275 }
2276
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002277 if (gles2_renderer_init(&ec->base) < 0)
2278 goto err_egl;
2279
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002280 path = NULL;
2281
Tiago Vignattice03ec32011-12-19 01:14:03 +02002282 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002283
2284 loop = wl_display_get_event_loop(ec->base.wl_display);
2285 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002286 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002287 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002288
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002289 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2290 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002291 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002292 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002293 }
2294 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2295 "drm", NULL);
2296 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002297 wl_event_loop_add_fd(loop,
2298 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002299 WL_EVENT_READABLE, udev_drm_event, ec);
2300
2301 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002302 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002303 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002304 }
2305
Daniel Stonea96b93c2012-06-22 14:04:37 +01002306 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002307
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002308 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002309
2310err_udev_monitor:
2311 wl_event_source_remove(ec->udev_drm_source);
2312 udev_monitor_unref(ec->udev_monitor);
2313err_drm_source:
2314 wl_event_source_remove(ec->drm_source);
2315 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2316 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002317err_egl:
2318 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2319 EGL_NO_CONTEXT);
2320 eglTerminate(ec->base.egl_display);
2321 eglReleaseThread();
2322 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002323err_sprite:
2324 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002325err_udev_dev:
2326 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002327err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002328 tty_destroy(ec->tty);
2329err_udev:
2330 udev_unref(ec->udev);
2331err_compositor:
2332 weston_compositor_shutdown(&ec->base);
2333err_base:
2334 free(ec);
2335 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002336}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002337
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002338static int
2339set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2340{
2341 mode->flags = 0;
2342
2343 if (strcmp(hsync, "+hsync") == 0)
2344 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2345 else if (strcmp(hsync, "-hsync") == 0)
2346 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2347 else
2348 return -1;
2349
2350 if (strcmp(vsync, "+vsync") == 0)
2351 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2352 else if (strcmp(vsync, "-vsync") == 0)
2353 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2354 else
2355 return -1;
2356
2357 return 0;
2358}
2359
2360static int
2361check_for_modeline(struct drm_configured_output *output)
2362{
2363 drmModeModeInfo mode;
2364 char hsync[16];
2365 char vsync[16];
2366 char mode_name[16];
2367 float fclock;
2368
2369 mode.type = DRM_MODE_TYPE_USERDEF;
2370 mode.hskew = 0;
2371 mode.vscan = 0;
2372 mode.vrefresh = 0;
2373
2374 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2375 &fclock, &mode.hdisplay,
2376 &mode.hsync_start,
2377 &mode.hsync_end, &mode.htotal,
2378 &mode.vdisplay,
2379 &mode.vsync_start,
2380 &mode.vsync_end, &mode.vtotal,
2381 hsync, vsync) == 11) {
2382 if (set_sync_flags(&mode, hsync, vsync))
2383 return -1;
2384
2385 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2386 strcpy(mode.name, mode_name);
2387
2388 mode.clock = fclock * 1000;
2389 } else
2390 return -1;
2391
2392 output->crtc_mode = mode;
2393
2394 return 0;
2395}
2396
Scott Moreau8ab5d452012-07-30 19:51:08 -06002397static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002398drm_output_set_transform(struct drm_configured_output *output)
2399{
2400 if (!output_transform) {
2401 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2402 return;
2403 }
2404
2405 if (!strcmp(output_transform, "normal"))
2406 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2407 else if (!strcmp(output_transform, "90"))
2408 output->transform = WL_OUTPUT_TRANSFORM_90;
2409 else if (!strcmp(output_transform, "180"))
2410 output->transform = WL_OUTPUT_TRANSFORM_180;
2411 else if (!strcmp(output_transform, "270"))
2412 output->transform = WL_OUTPUT_TRANSFORM_270;
2413 else if (!strcmp(output_transform, "flipped"))
2414 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2415 else if (!strcmp(output_transform, "flipped-90"))
2416 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2417 else if (!strcmp(output_transform, "flipped-180"))
2418 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2419 else if (!strcmp(output_transform, "flipped-270"))
2420 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2421 else {
2422 weston_log("Invalid transform \"%s\" for output %s\n",
2423 output_transform, output_name);
2424 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2425 }
2426
2427 free(output_transform);
2428 output_transform = NULL;
2429}
2430
2431static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002432output_section_done(void *data)
2433{
2434 struct drm_configured_output *output;
2435
2436 output = malloc(sizeof *output);
2437
Scott Moreau1bad5db2012-08-18 01:04:05 -06002438 if (!output || !output_name || (output_name[0] == 'X') ||
2439 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002440 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002441 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002442 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002443 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002444 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002445 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002446 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002447 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002448 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002449
2450 output->config = OUTPUT_CONFIG_INVALID;
2451 output->name = output_name;
2452 output->mode = output_mode;
2453
Scott Moreau1bad5db2012-08-18 01:04:05 -06002454 if (output_mode) {
2455 if (strcmp(output_mode, "off") == 0)
2456 output->config = OUTPUT_CONFIG_OFF;
2457 else if (strcmp(output_mode, "preferred") == 0)
2458 output->config = OUTPUT_CONFIG_PREFERRED;
2459 else if (strcmp(output_mode, "current") == 0)
2460 output->config = OUTPUT_CONFIG_CURRENT;
2461 else if (sscanf(output_mode, "%dx%d",
2462 &output->width, &output->height) == 2)
2463 output->config = OUTPUT_CONFIG_MODE;
2464 else if (check_for_modeline(output) == 0)
2465 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002466
Scott Moreau1bad5db2012-08-18 01:04:05 -06002467 if (output->config == OUTPUT_CONFIG_INVALID)
2468 weston_log("Invalid mode \"%s\" for output %s\n",
2469 output_mode, output_name);
2470 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002471 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002472
2473 drm_output_set_transform(output);
2474
2475 wl_list_insert(&configured_output_list, &output->link);
2476
2477 if (output_transform)
2478 free(output_transform);
2479 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002480}
2481
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002482WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002483backend_init(struct wl_display *display, int argc, char *argv[],
2484 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002485{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002486 int connector = 0, tty = 0;
2487 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002488
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002489 const struct weston_option drm_options[] = {
2490 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2491 { WESTON_OPTION_STRING, "seat", 0, &seat },
2492 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002493 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002494 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002495
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002496 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002497
Scott Moreau8ab5d452012-07-30 19:51:08 -06002498 wl_list_init(&configured_output_list);
2499
2500 const struct config_key drm_config_keys[] = {
2501 { "name", CONFIG_KEY_STRING, &output_name },
2502 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002503 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002504 };
2505
2506 const struct config_section config_section[] = {
2507 { "output", drm_config_keys,
2508 ARRAY_LENGTH(drm_config_keys), output_section_done },
2509 };
2510
2511 parse_config_file(config_file, config_section,
2512 ARRAY_LENGTH(config_section), NULL);
2513
Daniel Stonec1be8e52012-06-01 11:14:02 -04002514 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2515 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002516}