blob: a2169dd161e301c611928ae175e23604c55ace0e [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
567/*
568 * This function must take care to damage any previously assigned surface
569 * if the sprite ends up binding to a different surface than in the
570 * previous frame.
571 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400572static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400574 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500575{
576 struct weston_compositor *ec = output_base->compositor;
577 struct drm_compositor *c =(struct drm_compositor *) ec;
578 struct drm_sprite *s;
579 int found = 0;
580 EGLint handle, stride;
581 struct gbm_bo *bo;
582 uint32_t fb_id = 0;
583 uint32_t handles[4], pitches[4], offsets[4];
584 int ret = 0;
585 pixman_region32_t dest_rect, src_rect;
586 pixman_box32_t *box;
587 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400588 wl_fixed_t sx1, sy1, sx2, sy2;
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400589 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500590
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500591 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400592 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500593
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300594 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400595 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300596
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400597 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400598 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599
Rob Clark702ffae2012-08-09 14:18:27 -0500600 if (wl_buffer_is_shm(es->buffer))
601 return NULL;
602
Jesse Barnes58ef3792012-02-23 09:45:49 -0500603 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400604 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605
Jesse Barnes58ef3792012-02-23 09:45:49 -0500606 wl_list_for_each(s, &c->sprite_list, link) {
607 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
608 continue;
609
610 if (!s->pending_fb_id) {
611 found = 1;
612 break;
613 }
614 }
615
616 /* No sprites available */
617 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400618 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500619
Rob Clark4339add2012-08-09 14:18:28 -0500620 width = es->geometry.width;
621 height = es->geometry.height;
622
623 /* If geometry is out of bounds, don't even bother trying because
624 * we know the AddFB2() call will fail:
625 */
626 if (c->min_width > width || width > c->max_width ||
627 c->min_height > height || height > c->max_height)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400628 return NULL;
Rob Clark4339add2012-08-09 14:18:28 -0500629
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400630 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
631 es->buffer, GBM_BO_USE_SCANOUT);
632 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400633 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400634
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635 format = gbm_bo_get_format(bo);
636 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400637 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638
639 gbm_bo_destroy(bo);
640
641 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400642 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643
644 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400645 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500646
647 handles[0] = handle;
648 pitches[0] = stride;
649 offsets[0] = 0;
650
Rob Clark4339add2012-08-09 14:18:28 -0500651 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 format, handles, pitches, offsets,
653 &fb_id, 0);
654 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200655 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500656 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400657 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 }
659
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 s->pending_fb_id = fb_id;
661 s->pending_surface = es;
662 es->buffer->busy_count++;
663
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400664 box = pixman_region32_extents(&es->transform.boundingbox);
665 s->plane.x = box->x1;
666 s->plane.y = box->y1;
667
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668 /*
669 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200670 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500671 * for us already).
672 */
673 pixman_region32_init(&dest_rect);
674 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
675 &output_base->region);
676 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
677 box = pixman_region32_extents(&dest_rect);
678 s->dest_x = box->x1;
679 s->dest_y = box->y1;
680 s->dest_w = box->x2 - box->x1;
681 s->dest_h = box->y2 - box->y1;
682 pixman_region32_fini(&dest_rect);
683
684 pixman_region32_init(&src_rect);
685 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
686 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500687 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400688
689 weston_surface_from_global_fixed(es,
690 wl_fixed_from_int(box->x1),
691 wl_fixed_from_int(box->y1),
692 &sx1, &sy1);
693 weston_surface_from_global_fixed(es,
694 wl_fixed_from_int(box->x2),
695 wl_fixed_from_int(box->y2),
696 &sx2, &sy2);
697
698 if (sx1 < 0)
699 sx1 = 0;
700 if (sy1 < 0)
701 sy1 = 0;
702 if (sx2 > wl_fixed_from_int(es->geometry.width))
703 sx2 = wl_fixed_from_int(es->geometry.width);
704 if (sy2 > wl_fixed_from_int(es->geometry.height))
705 sy2 = wl_fixed_from_int(es->geometry.height);
706
707 s->src_x = sx1 << 8;
708 s->src_y = sy1 << 8;
709 s->src_w = (sx2 - sx1) << 8;
710 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500711 pixman_region32_fini(&src_rect);
712
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400713 wl_signal_add(&es->buffer->resource.destroy_signal,
714 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400715
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400716 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500717}
718
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400719static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400720drm_output_prepare_cursor_surface(struct weston_output *output_base,
721 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500722{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400723 struct drm_compositor *c =
724 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400725 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400726
727 if (output->cursor_surface)
728 return NULL;
729 if (es->output_mask != (1u << output_base->id))
730 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500731 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400732 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400733 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
734 es->geometry.width > 64 || es->geometry.height > 64)
735 return NULL;
736
737 output->cursor_surface = es;
738
739 return &output->cursor_plane;
740}
741
742static void
743drm_output_set_cursor(struct drm_output *output)
744{
745 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400746 struct drm_compositor *c =
747 (struct drm_compositor *) output->base.compositor;
748 EGLint handle, stride;
749 struct gbm_bo *bo;
750 uint32_t buf[64 * 64];
751 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400752 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500753
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400754 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400755 if (es == NULL) {
756 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
757 return;
758 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500759
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400760 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
761 pixman_region32_fini(&output->cursor_plane.damage);
762 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400763 output->current_cursor ^= 1;
764 bo = output->cursor_bo[output->current_cursor];
765 memset(buf, 0, sizeof buf);
766 stride = wl_shm_buffer_get_stride(es->buffer);
767 s = wl_shm_buffer_get_data(es->buffer);
768 for (i = 0; i < es->geometry.height; i++)
769 memcpy(buf + i * 64, s + i * stride,
770 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500771
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400772 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300773 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400774
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400775 handle = gbm_bo_get_handle(bo).s32;
776 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500777 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300778 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500779 c->cursors_are_broken = 1;
780 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400781 }
782
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400783 x = es->geometry.x - output->base.x;
784 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400785 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500786 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400787 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500788 c->cursors_are_broken = 1;
789 }
790
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400791 output->cursor_plane.x = x;
792 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400793 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500794}
795
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796static void
797drm_assign_planes(struct weston_output *output)
798{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400799 struct drm_compositor *c =
800 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400801 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400803 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804
805 /*
806 * Find a surface for each sprite in the output using some heuristics:
807 * 1) size
808 * 2) frequency of update
809 * 3) opacity (though some hw might support alpha blending)
810 * 4) clipping (this can be fixed with color keys)
811 *
812 * The idea is to save on blitting since this should save power.
813 * If we can get a large video surface on the sprite for example,
814 * the main display surface may not need to update at all, and
815 * the client buffer can be used directly for the sprite surface
816 * as we do for flipping full screen surfaces.
817 */
818 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400819 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400820 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821 pixman_region32_init(&surface_overlap);
822 pixman_region32_intersect(&surface_overlap, &overlap,
823 &es->transform.boundingbox);
824
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400825 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400826 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400827 next_plane = primary;
828 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400829 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 if (next_plane == NULL)
831 next_plane = drm_output_prepare_scanout_surface(output, es);
832 if (next_plane == NULL)
833 next_plane = drm_output_prepare_overlay_surface(output, es);
834 if (next_plane == NULL)
835 next_plane = primary;
836 weston_surface_move_to_plane(es, next_plane);
837 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500838 pixman_region32_union(&overlap, &overlap,
839 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400840
Jesse Barnes58ef3792012-02-23 09:45:49 -0500841 pixman_region32_fini(&surface_overlap);
842 }
843 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500844}
845
Matt Roper361d2ad2011-08-29 13:52:23 -0700846static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500847drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700848{
849 struct drm_output *output = (struct drm_output *) output_base;
850 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200851 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700852 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700853
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200854 if (output->backlight)
855 backlight_destroy(output->backlight);
856
Matt Roper361d2ad2011-08-29 13:52:23 -0700857 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400858 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700859
860 /* Restore original CRTC state */
861 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200862 origcrtc->x, origcrtc->y,
863 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700864 drmModeFreeCrtc(origcrtc);
865
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200866 c->crtc_allocator &= ~(1 << output->crtc_id);
867 c->connector_allocator &= ~(1 << output->connector_id);
868
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400869 eglDestroySurface(c->base.egl_display, output->base.egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400870 gbm_surface_destroy(output->surface);
871
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400872 weston_plane_release(&output->fb_plane);
873 weston_plane_release(&output->cursor_plane);
874
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500875 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200876 wl_list_remove(&output->base.link);
877
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400878 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700879 free(output);
880}
881
Alex Wub7b8bda2012-04-17 17:20:48 +0800882static struct drm_mode *
883choose_mode (struct drm_output *output, struct weston_mode *target_mode)
884{
885 struct drm_mode *tmp_mode = NULL, *mode;
886
887 if (output->base.current->width == target_mode->width &&
888 output->base.current->height == target_mode->height &&
889 (output->base.current->refresh == target_mode->refresh ||
890 target_mode->refresh == 0))
891 return (struct drm_mode *)output->base.current;
892
893 wl_list_for_each(mode, &output->base.mode_list, base.link) {
894 if (mode->mode_info.hdisplay == target_mode->width &&
895 mode->mode_info.vdisplay == target_mode->height) {
896 if (mode->mode_info.vrefresh == target_mode->refresh ||
897 target_mode->refresh == 0) {
898 return mode;
899 } else if (!tmp_mode)
900 tmp_mode = mode;
901 }
902 }
903
904 return tmp_mode;
905}
906
907static int
908drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
909{
910 struct drm_output *output;
911 struct drm_mode *drm_mode;
912 int ret;
913 struct drm_compositor *ec;
914 struct gbm_surface *surface;
915 EGLSurface egl_surface;
916
917 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200918 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800919 return -1;
920 }
921
922 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200923 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800924 return -1;
925 }
926
927 ec = (struct drm_compositor *)output_base->compositor;
928 output = (struct drm_output *)output_base;
929 drm_mode = choose_mode (output, mode);
930
931 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200932 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800933 return -1;
934 } else if (&drm_mode->base == output->base.current) {
935 return 0;
936 } else if (drm_mode->base.width == output->base.current->width &&
937 drm_mode->base.height == output->base.current->height) {
938 /* only change refresh value */
939 ret = drmModeSetCrtc(ec->drm.fd,
940 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300941 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800942 &output->connector_id, 1, &drm_mode->mode_info);
943
944 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200945 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800946 drm_mode->base.width,
947 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400948 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800949 ret = -1;
950 } else {
951 output->base.current->flags = 0;
952 output->base.current = &drm_mode->base;
953 drm_mode->base.flags =
954 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
955 ret = 0;
956 }
957
958 return ret;
959 }
960
961 drm_mode->base.flags =
962 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
963
964 surface = gbm_surface_create(ec->gbm,
965 drm_mode->base.width,
966 drm_mode->base.height,
967 GBM_FORMAT_XRGB8888,
968 GBM_BO_USE_SCANOUT |
969 GBM_BO_USE_RENDERING);
970 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200971 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800972 return -1;
973 }
974
975 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400976 eglCreateWindowSurface(ec->base.egl_display,
977 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800978 surface, NULL);
979
980 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200981 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800982 goto err;
983 }
984
985 ret = drmModeSetCrtc(ec->drm.fd,
986 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300987 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800988 &output->connector_id, 1, &drm_mode->mode_info);
989 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200990 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800991 goto err;
992 }
993
994 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300995 if (output->current) {
996 if (output->current->is_client_buffer)
997 gbm_bo_destroy(output->current->bo);
998 else
999 gbm_surface_release_buffer(output->surface,
1000 output->current->bo);
1001 }
1002 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001003
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001004 if (output->next) {
1005 if (output->next->is_client_buffer)
1006 gbm_bo_destroy(output->next->bo);
1007 else
1008 gbm_surface_release_buffer(output->surface,
1009 output->next->bo);
1010 }
1011 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001012
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001013 eglDestroySurface(ec->base.egl_display, output->base.egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001014 gbm_surface_destroy(output->surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001015 output->base.egl_surface = egl_surface;
Alex Wub7b8bda2012-04-17 17:20:48 +08001016 output->surface = surface;
1017
1018 /*update output*/
1019 output->base.current = &drm_mode->base;
1020 output->base.dirty = 1;
1021 weston_output_move(&output->base, output->base.x, output->base.y);
1022 return 0;
1023
1024err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001025 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001026 gbm_surface_destroy(surface);
1027 return -1;
1028}
1029
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001030static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001031on_drm_input(int fd, uint32_t mask, void *data)
1032{
1033 drmEventContext evctx;
1034
1035 memset(&evctx, 0, sizeof evctx);
1036 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1037 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001038 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001039 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001040
1041 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001042}
1043
1044static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001045init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001046{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001047 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001048 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001049 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001050 static const EGLint config_attribs[] = {
1051 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1052 EGL_RED_SIZE, 1,
1053 EGL_GREEN_SIZE, 1,
1054 EGL_BLUE_SIZE, 1,
1055 EGL_ALPHA_SIZE, 0,
1056 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1057 EGL_NONE
1058 };
1059
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001060 sysnum = udev_device_get_sysnum(device);
1061 if (sysnum)
1062 ec->drm.id = atoi(sysnum);
1063 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001064 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001065 return -1;
1066 }
1067
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001068 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001069 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001070 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001071 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001072 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001073 udev_device_get_devnode(device));
1074 return -1;
1075 }
1076
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001077 weston_log("using %s\n", filename);
1078
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001079 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001080 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001081 ec->base.egl_display = eglGetDisplay(ec->gbm);
1082 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001083 weston_log("failed to create 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 (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001088 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001089 return -1;
1090 }
1091
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001092 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1093 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001094 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001095 return -1;
1096 }
1097
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001098 return 0;
1099}
1100
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001101static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001102drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1103{
1104 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001105 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001106
1107 mode = malloc(sizeof *mode);
1108 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001109 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001110
1111 mode->base.flags = 0;
1112 mode->base.width = info->hdisplay;
1113 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001114
1115 /* Calculate higher precision (mHz) refresh rate */
1116 refresh = (info->clock * 1000000LL / info->htotal +
1117 info->vtotal / 2) / info->vtotal;
1118
1119 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1120 refresh *= 2;
1121 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1122 refresh /= 2;
1123 if (info->vscan > 1)
1124 refresh /= info->vscan;
1125
1126 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001127 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001128
1129 if (info->type & DRM_MODE_TYPE_PREFERRED)
1130 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1131
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001132 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1133
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001134 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001135}
1136
1137static int
1138drm_subpixel_to_wayland(int drm_value)
1139{
1140 switch (drm_value) {
1141 default:
1142 case DRM_MODE_SUBPIXEL_UNKNOWN:
1143 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1144 case DRM_MODE_SUBPIXEL_NONE:
1145 return WL_OUTPUT_SUBPIXEL_NONE;
1146 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1147 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1148 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1149 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1150 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1151 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1152 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1153 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1154 }
1155}
1156
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001157static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001158sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001159{
1160 struct drm_sprite *sprite =
1161 container_of(listener, struct drm_sprite,
1162 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001163 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001164
1165 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001166 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1167 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001168}
1169
1170static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001171sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001172{
1173 struct drm_sprite *sprite =
1174 container_of(listener, struct drm_sprite,
1175 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001176 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001177
1178 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001179 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1180 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001181}
1182
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001183/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001184static uint32_t
1185drm_get_backlight(struct drm_output *output)
1186{
1187 long brightness, max_brightness, norm;
1188
1189 brightness = backlight_get_brightness(output->backlight);
1190 max_brightness = backlight_get_max_brightness(output->backlight);
1191
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001192 /* convert it on a scale of 0 to 255 */
1193 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001194
1195 return (uint32_t) norm;
1196}
1197
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001198/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001199static void
1200drm_set_backlight(struct weston_output *output_base, uint32_t value)
1201{
1202 struct drm_output *output = (struct drm_output *) output_base;
1203 long max_brightness, new_brightness;
1204
1205 if (!output->backlight)
1206 return;
1207
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001208 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001209 return;
1210
1211 max_brightness = backlight_get_max_brightness(output->backlight);
1212
1213 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001214 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001215
1216 backlight_set_brightness(output->backlight, new_brightness);
1217}
1218
1219static drmModePropertyPtr
1220drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1221{
1222 drmModePropertyPtr props;
1223 int i;
1224
1225 for (i = 0; i < connector->count_props; i++) {
1226 props = drmModeGetProperty(fd, connector->props[i]);
1227 if (!props)
1228 continue;
1229
1230 if (!strcmp(props->name, name))
1231 return props;
1232
1233 drmModeFreeProperty(props);
1234 }
1235
1236 return NULL;
1237}
1238
1239static void
1240drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1241{
1242 struct drm_output *output = (struct drm_output *) output_base;
1243 struct weston_compositor *ec = output_base->compositor;
1244 struct drm_compositor *c = (struct drm_compositor *) ec;
1245 drmModeConnectorPtr connector;
1246 drmModePropertyPtr prop;
1247
1248 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1249 if (!connector)
1250 return;
1251
1252 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1253 if (!prop) {
1254 drmModeFreeConnector(connector);
1255 return;
1256 }
1257
1258 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1259 prop->prop_id, level);
1260 drmModeFreeProperty(prop);
1261 drmModeFreeConnector(connector);
1262}
1263
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001264static const char *connector_type_names[] = {
1265 "None",
1266 "VGA",
1267 "DVI",
1268 "DVI",
1269 "DVI",
1270 "Composite",
1271 "TV",
1272 "LVDS",
1273 "CTV",
1274 "DIN",
1275 "DP",
1276 "HDMI",
1277 "HDMI",
1278 "TV",
1279 "eDP",
1280};
1281
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001282static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001283find_crtc_for_connector(struct drm_compositor *ec,
1284 drmModeRes *resources, drmModeConnector *connector)
1285{
1286 drmModeEncoder *encoder;
1287 uint32_t possible_crtcs;
1288 int i, j;
1289
1290 for (j = 0; j < connector->count_encoders; j++) {
1291 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1292 if (encoder == NULL) {
1293 weston_log("Failed to get encoder.\n");
1294 return -1;
1295 }
1296 possible_crtcs = encoder->possible_crtcs;
1297 drmModeFreeEncoder(encoder);
1298
1299 for (i = 0; i < resources->count_crtcs; i++) {
1300 if (possible_crtcs & (1 << i) &&
1301 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1302 return i;
1303 }
1304 }
1305
1306 return -1;
1307}
1308
1309static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001310create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001311 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001312 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001313 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001314{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001315 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001316 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1317 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001318 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001319 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001320 drmModeModeInfo crtc_mode;
1321 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001322 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001323 char name[32];
1324 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001325
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001326 i = find_crtc_for_connector(ec, resources, connector);
1327 if (i < 0) {
1328 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001329 return -1;
1330 }
1331
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001332 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001333 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001334 return -1;
1335
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001336 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001337 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1338 output->base.make = "unknown";
1339 output->base.model = "unknown";
1340 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001341
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001342 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1343 type_name = connector_type_names[connector->connector_type];
1344 else
1345 type_name = "UNKNOWN";
1346 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1347 output->name = strdup(name);
1348
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001349 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001350 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001351 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001352 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001353 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001354
Matt Roper361d2ad2011-08-29 13:52:23 -07001355 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1356
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001357 /* Get the current mode on the crtc that's currently driving
1358 * this connector. */
1359 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001360 memset(&crtc_mode, 0, sizeof crtc_mode);
1361 if (encoder != NULL) {
1362 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1363 drmModeFreeEncoder(encoder);
1364 if (crtc == NULL)
1365 goto err_free;
1366 if (crtc->mode_valid)
1367 crtc_mode = crtc->mode;
1368 drmModeFreeCrtc(crtc);
1369 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001370
David Herrmann0f0d54e2011-12-08 17:05:45 +01001371 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001372 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1373 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001374 goto err_free;
1375 }
1376
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001377 preferred = NULL;
1378 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001379 configured = NULL;
1380
1381 wl_list_for_each(temp, &configured_output_list, link) {
1382 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001383 if (temp->mode)
1384 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001385 temp->name, temp->mode);
1386 o = temp;
1387 break;
1388 }
1389 }
1390
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001391 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001392 weston_log("Disabling output %s\n", o->name);
1393
1394 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1395 0, 0, 0, 0, 0, NULL);
1396 goto err_free;
1397 }
1398
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001399 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001400 if (o && o->config == OUTPUT_CONFIG_MODE &&
1401 o->width == drm_mode->base.width &&
1402 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001403 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001404 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001405 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001406 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001407 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001408 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001409
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001410 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001411 configured = drm_output_add_mode(output, &o->crtc_mode);
1412 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001413 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001414 current = configured;
1415 }
1416
Wang Quanxianacb805a2012-07-30 18:09:46 -04001417 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001418 current = drm_output_add_mode(output, &crtc_mode);
1419 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001421 }
1422
Scott Moreau8ab5d452012-07-30 19:51:08 -06001423 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1424 configured = current;
1425
Wang Quanxianacb805a2012-07-30 18:09:46 -04001426 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001427 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001428 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001429 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001430 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001431 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001432 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001433 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001434
1435 if (output->base.current == NULL) {
1436 weston_log("no available modes for %s\n", output->name);
1437 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001438 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001439
Wang Quanxianacb805a2012-07-30 18:09:46 -04001440 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1441
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001442 output->surface = gbm_surface_create(ec->gbm,
1443 output->base.current->width,
1444 output->base.current->height,
1445 GBM_FORMAT_XRGB8888,
1446 GBM_BO_USE_SCANOUT |
1447 GBM_BO_USE_RENDERING);
1448 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001449 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001450 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001451 }
1452
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001453 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001454 eglCreateWindowSurface(ec->base.egl_display,
1455 ec->base.egl_config,
1456 output->surface,
1457 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001458 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001459 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001460 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001461 }
1462
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001463 output->cursor_bo[0] =
1464 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1465 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1466 output->cursor_bo[1] =
1467 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1468 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001469 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1470 weston_log("cursor buffers unavailable, using gl cursors\n");
1471 ec->cursors_are_broken = 1;
1472 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001473
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001474 output->backlight = backlight_init(drm_device,
1475 connector->connector_type);
1476 if (output->backlight) {
1477 output->base.set_backlight = drm_set_backlight;
1478 output->base.backlight_current = drm_get_backlight(output);
1479 }
1480
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001481 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001482 connector->mmWidth, connector->mmHeight,
1483 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001484
1485 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1486
Alex Wubd3354b2012-04-17 17:20:49 +08001487 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001488 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001489 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001490 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001491 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001492 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001493
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001494 weston_plane_init(&output->cursor_plane, 0, 0);
1495 weston_plane_init(&output->fb_plane, 0, 0);
1496
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001497 weston_log("Output %s, (connector %d, crtc %d)\n",
1498 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001499 wl_list_for_each(m, &output->base.mode_list, link)
1500 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1501 m->width, m->height, m->refresh / 1000.0,
1502 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1503 ", preferred" : "",
1504 m->flags & WL_OUTPUT_MODE_CURRENT ?
1505 ", current" : "",
1506 connector->count_modes == 0 ?
1507 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001508
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001509 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001510
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001511err_surface:
1512 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001513err_free:
1514 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1515 base.link) {
1516 wl_list_remove(&drm_mode->base.link);
1517 free(drm_mode);
1518 }
1519
1520 drmModeFreeCrtc(output->original_crtc);
1521 ec->crtc_allocator &= ~(1 << output->crtc_id);
1522 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001523 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001524 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001525
David Herrmann0f0d54e2011-12-08 17:05:45 +01001526 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001527}
1528
Jesse Barnes58ef3792012-02-23 09:45:49 -05001529static void
1530create_sprites(struct drm_compositor *ec)
1531{
1532 struct drm_sprite *sprite;
1533 drmModePlaneRes *plane_res;
1534 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001535 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001536
1537 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1538 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001539 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001540 strerror(errno));
1541 return;
1542 }
1543
1544 for (i = 0; i < plane_res->count_planes; i++) {
1545 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1546 if (!plane)
1547 continue;
1548
1549 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1550 plane->count_formats));
1551 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001552 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001553 __func__);
1554 free(plane);
1555 continue;
1556 }
1557
1558 memset(sprite, 0, sizeof *sprite);
1559
1560 sprite->possible_crtcs = plane->possible_crtcs;
1561 sprite->plane_id = plane->plane_id;
1562 sprite->surface = NULL;
1563 sprite->pending_surface = NULL;
1564 sprite->fb_id = 0;
1565 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001566 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1567 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001568 sprite_handle_pending_buffer_destroy;
1569 sprite->compositor = ec;
1570 sprite->count_formats = plane->count_formats;
1571 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001572 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001573 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001574 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001575
1576 wl_list_insert(&ec->sprite_list, &sprite->link);
1577 }
1578
1579 free(plane_res->planes);
1580 free(plane_res);
1581}
1582
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001583static void
1584destroy_sprites(struct drm_compositor *compositor)
1585{
1586 struct drm_sprite *sprite, *next;
1587 struct drm_output *output;
1588
1589 output = container_of(compositor->base.output_list.next,
1590 struct drm_output, base.link);
1591
1592 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1593 drmModeSetPlane(compositor->drm.fd,
1594 sprite->plane_id,
1595 output->crtc_id, 0, 0,
1596 0, 0, 0, 0, 0, 0, 0, 0);
1597 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001598 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001599 free(sprite);
1600 }
1601}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001602
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001603static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001604create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001605 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001606{
1607 drmModeConnector *connector;
1608 drmModeRes *resources;
1609 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001610 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001611
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001612 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001613 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001614 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001615 return -1;
1616 }
1617
Jesse Barnes58ef3792012-02-23 09:45:49 -05001618 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001619 if (!ec->crtcs) {
1620 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001621 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001622 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001623
Rob Clark4339add2012-08-09 14:18:28 -05001624 ec->min_width = resources->min_width;
1625 ec->max_width = resources->max_width;
1626 ec->min_height = resources->min_height;
1627 ec->max_height = resources->max_height;
1628
Jesse Barnes58ef3792012-02-23 09:45:49 -05001629 ec->num_crtcs = resources->count_crtcs;
1630 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1631
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001632 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001633 connector = drmModeGetConnector(ec->drm.fd,
1634 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001635 if (connector == NULL)
1636 continue;
1637
1638 if (connector->connection == DRM_MODE_CONNECTED &&
1639 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001640 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001641 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001642 connector, x, y,
1643 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001644 drmModeFreeConnector(connector);
1645 continue;
1646 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001647
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001648 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001649 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001650 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001651 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001652
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001653 drmModeFreeConnector(connector);
1654 }
1655
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001656 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001657 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001658 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001659 return -1;
1660 }
1661
1662 drmModeFreeResources(resources);
1663
1664 return 0;
1665}
1666
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001667static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001668update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001669{
1670 drmModeConnector *connector;
1671 drmModeRes *resources;
1672 struct drm_output *output, *next;
1673 int x = 0, y = 0;
1674 int x_offset = 0, y_offset = 0;
1675 uint32_t connected = 0, disconnects = 0;
1676 int i;
1677
1678 resources = drmModeGetResources(ec->drm.fd);
1679 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001680 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001681 return;
1682 }
1683
1684 /* collect new connects */
1685 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001686 int connector_id = resources->connectors[i];
1687
1688 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001689 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001690 continue;
1691
David Herrmann7551cff2011-12-08 17:05:43 +01001692 if (connector->connection != DRM_MODE_CONNECTED) {
1693 drmModeFreeConnector(connector);
1694 continue;
1695 }
1696
Benjamin Franzke117483d2011-08-30 11:38:26 +02001697 connected |= (1 << connector_id);
1698
1699 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001700 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001701 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001702 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001703
1704 /* XXX: not yet needed, we die with 0 outputs */
1705 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001706 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001707 else
1708 x = 0;
1709 y = 0;
1710 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001711 connector, x, y,
1712 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001713 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001714
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001715 }
1716 drmModeFreeConnector(connector);
1717 }
1718 drmModeFreeResources(resources);
1719
1720 disconnects = ec->connector_allocator & ~connected;
1721 if (disconnects) {
1722 wl_list_for_each_safe(output, next, &ec->base.output_list,
1723 base.link) {
1724 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001725 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001726 output->base.x - x_offset,
1727 output->base.y - y_offset);
1728 }
1729
1730 if (disconnects & (1 << output->connector_id)) {
1731 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001732 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001733 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001734 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001735 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001736 }
1737 }
1738 }
1739
1740 /* FIXME: handle zero outputs, without terminating */
1741 if (ec->connector_allocator == 0)
1742 wl_display_terminate(ec->base.wl_display);
1743}
1744
1745static int
David Herrmannd7488c22012-03-11 20:05:21 +01001746udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001747{
David Herrmannd7488c22012-03-11 20:05:21 +01001748 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001749 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001750
1751 sysnum = udev_device_get_sysnum(device);
1752 if (!sysnum || atoi(sysnum) != ec->drm.id)
1753 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001754
David Herrmann6ac52db2012-03-11 20:05:22 +01001755 val = udev_device_get_property_value(device, "HOTPLUG");
1756 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001757 return 0;
1758
David Herrmann6ac52db2012-03-11 20:05:22 +01001759 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001760}
1761
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001762static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001763udev_drm_event(int fd, uint32_t mask, void *data)
1764{
1765 struct drm_compositor *ec = data;
1766 struct udev_device *event;
1767
1768 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001769
David Herrmannd7488c22012-03-11 20:05:21 +01001770 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001771 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001772
1773 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001774
1775 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001776}
1777
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001778static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001779drm_restore(struct weston_compositor *ec)
1780{
1781 struct drm_compositor *d = (struct drm_compositor *) ec;
1782
1783 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1784 weston_log("failed to drop master: %m\n");
1785 tty_reset(d->tty);
1786}
1787
Pekka Paalanen33156972012-08-03 13:30:30 -04001788static const char default_seat[] = "seat0";
1789
1790static void
1791device_added(struct udev_device *udev_device, struct drm_seat *master)
1792{
1793 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001794 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001795 const char *devnode;
1796 const char *device_seat;
1797 int fd;
1798
1799 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1800 if (!device_seat)
1801 device_seat = default_seat;
1802
1803 if (strcmp(device_seat, master->seat_id))
1804 return;
1805
1806 c = master->base.compositor;
1807 devnode = udev_device_get_devnode(udev_device);
1808
1809 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001810 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001811 * read. mtdev_get() also expects this. */
1812 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1813 if (fd < 0) {
1814 weston_log("opening input device '%s' failed.\n", devnode);
1815 return;
1816 }
1817
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001818 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001819 if (!device) {
1820 close(fd);
1821 weston_log("not using input device '%s'.\n", devnode);
1822 return;
1823 }
1824
1825 wl_list_insert(master->devices_list.prev, &device->link);
1826}
1827
1828static void
1829evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1830{
1831 struct drm_seat *seat = (struct drm_seat *) seat_base;
1832 struct udev_enumerate *e;
1833 struct udev_list_entry *entry;
1834 struct udev_device *device;
1835 const char *path, *sysname;
1836
1837 e = udev_enumerate_new(udev);
1838 udev_enumerate_add_match_subsystem(e, "input");
1839 udev_enumerate_scan_devices(e);
1840 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1841 path = udev_list_entry_get_name(entry);
1842 device = udev_device_new_from_syspath(udev, path);
1843
1844 sysname = udev_device_get_sysname(device);
1845 if (strncmp("event", sysname, 5) != 0) {
1846 udev_device_unref(device);
1847 continue;
1848 }
1849
1850 device_added(device, seat);
1851
1852 udev_device_unref(device);
1853 }
1854 udev_enumerate_unref(e);
1855
1856 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1857
1858 if (wl_list_empty(&seat->devices_list)) {
1859 weston_log(
1860 "warning: no input devices on entering Weston. "
1861 "Possible causes:\n"
1862 "\t- no permissions to read /dev/input/event*\n"
1863 "\t- seats misconfigured "
1864 "(Weston backend option 'seat', "
1865 "udev device property ID_SEAT)\n");
1866 }
1867}
1868
1869static int
1870evdev_udev_handler(int fd, uint32_t mask, void *data)
1871{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001872 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001873 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001874 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001875 const char *action;
1876 const char *devnode;
1877
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001878 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001879 if (!udev_device)
1880 return 1;
1881
1882 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001883 if (!action)
1884 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001885
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001886 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1887 goto out;
1888
1889 if (!strcmp(action, "add")) {
1890 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001891 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001892 else if (!strcmp(action, "remove")) {
1893 devnode = udev_device_get_devnode(udev_device);
1894 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1895 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001896 weston_log("input device %s, %s removed\n",
1897 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001898 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001899 break;
1900 }
1901 }
1902
1903out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001904 udev_device_unref(udev_device);
1905
1906 return 0;
1907}
1908
1909static int
1910evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1911{
1912 struct drm_seat *master = (struct drm_seat *) seat_base;
1913 struct wl_event_loop *loop;
1914 struct weston_compositor *c = master->base.compositor;
1915 int fd;
1916
1917 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1918 if (!master->udev_monitor) {
1919 weston_log("udev: failed to create the udev monitor\n");
1920 return 0;
1921 }
1922
1923 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1924 "input", NULL);
1925
1926 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1927 weston_log("udev: failed to bind the udev monitor\n");
1928 udev_monitor_unref(master->udev_monitor);
1929 return 0;
1930 }
1931
1932 loop = wl_display_get_event_loop(c->wl_display);
1933 fd = udev_monitor_get_fd(master->udev_monitor);
1934 master->udev_monitor_source =
1935 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1936 evdev_udev_handler, master);
1937 if (!master->udev_monitor_source) {
1938 udev_monitor_unref(master->udev_monitor);
1939 return 0;
1940 }
1941
1942 return 1;
1943}
1944
1945static void
1946evdev_disable_udev_monitor(struct weston_seat *seat_base)
1947{
1948 struct drm_seat *seat = (struct drm_seat *) seat_base;
1949
1950 if (!seat->udev_monitor)
1951 return;
1952
1953 udev_monitor_unref(seat->udev_monitor);
1954 seat->udev_monitor = NULL;
1955 wl_event_source_remove(seat->udev_monitor_source);
1956 seat->udev_monitor_source = NULL;
1957}
1958
1959static void
1960drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1961{
1962 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001963 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001964
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001965 wl_list_for_each(device, &seat->devices_list, link)
1966 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001967}
1968
1969static void
1970evdev_input_create(struct weston_compositor *c, struct udev *udev,
1971 const char *seat_id)
1972{
1973 struct drm_seat *seat;
1974
1975 seat = malloc(sizeof *seat);
1976 if (seat == NULL)
1977 return;
1978
1979 memset(seat, 0, sizeof *seat);
1980 weston_seat_init(&seat->base, c);
1981 seat->base.led_update = drm_led_update;
1982
1983 wl_list_init(&seat->devices_list);
1984 seat->seat_id = strdup(seat_id);
1985 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1986 free(seat->seat_id);
1987 free(seat);
1988 return;
1989 }
1990
1991 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001992}
1993
1994static void
1995evdev_remove_devices(struct weston_seat *seat_base)
1996{
1997 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001998 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001999
2000 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002001 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002002
Pekka Paalanend8583512012-08-03 14:39:11 +03002003 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002004 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002005}
2006
2007static void
2008evdev_input_destroy(struct weston_seat *seat_base)
2009{
2010 struct drm_seat *seat = (struct drm_seat *) seat_base;
2011
2012 evdev_remove_devices(seat_base);
2013 evdev_disable_udev_monitor(&seat->base);
2014
2015 weston_seat_release(seat_base);
2016 free(seat->seat_id);
2017 free(seat);
2018}
2019
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002020static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002021drm_free_configured_output(struct drm_configured_output *output)
2022{
2023 free(output->name);
2024 free(output->mode);
2025 free(output);
2026}
2027
2028static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002029drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002030{
2031 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002032 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002033 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002034
Daniel Stone37816df2012-05-16 18:45:18 +01002035 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2036 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002037 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002038 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002039
2040 wl_event_source_remove(d->udev_drm_source);
2041 wl_event_source_remove(d->drm_source);
2042
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002043 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002044
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002045 gles2_renderer_destroy(ec);
2046
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002047 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002048 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002049 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002050 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002051 eglReleaseThread();
2052
Matt Roper361d2ad2011-08-29 13:52:23 -07002053 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002054 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002055 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002056 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002057 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002058
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002059 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002060}
2061
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002062static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002063drm_compositor_set_modes(struct drm_compositor *compositor)
2064{
2065 struct drm_output *output;
2066 struct drm_mode *drm_mode;
2067 int ret;
2068
2069 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2070 drm_mode = (struct drm_mode *) output->base.current;
2071 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002072 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002073 &output->connector_id, 1,
2074 &drm_mode->mode_info);
2075 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002076 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002077 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002078 drm_mode->base.width, drm_mode->base.height,
2079 output->base.x, output->base.y);
2080 }
2081 }
2082}
2083
2084static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002085vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002086{
2087 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002088 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002089 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002090 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002091
2092 switch (event) {
2093 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002094 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002095 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002096 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002097 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002098 wl_display_terminate(compositor->wl_display);
2099 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002100 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002101 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002102 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002103 wl_list_for_each(seat, &compositor->seat_list, link) {
2104 evdev_add_devices(ec->udev, seat);
2105 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002106 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002107 break;
2108 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002109 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002110 wl_list_for_each(seat, &compositor->seat_list, link) {
2111 evdev_disable_udev_monitor(seat);
2112 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002113 }
2114
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002115 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002116 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002117 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002118
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002119 /* If we have a repaint scheduled (either from a
2120 * pending pageflip or the idle handler), make sure we
2121 * cancel that so we don't try to pageflip when we're
2122 * vt switched away. The SLEEPING state will prevent
2123 * further attemps at repainting. When we switch
2124 * back, we schedule a repaint, which will process
2125 * pending frame callbacks. */
2126
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002127 wl_list_for_each(output, &ec->base.output_list, base.link) {
2128 output->base.repaint_needed = 0;
2129 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002130 }
2131
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002132 output = container_of(ec->base.output_list.next,
2133 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002134
2135 wl_list_for_each(sprite, &ec->sprite_list, link)
2136 drmModeSetPlane(ec->drm.fd,
2137 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002138 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002139 0, 0, 0, 0, 0, 0, 0, 0);
2140
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002141 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002142 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002143
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002144 break;
2145 };
2146}
2147
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002148static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002149switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002150{
2151 struct drm_compositor *ec = data;
2152
Daniel Stone325fc2d2012-05-30 16:31:58 +01002153 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002154}
2155
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002156static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002157drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002158 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002159 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002160{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002161 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002162 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002163 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002164 struct udev_device *device, *drm_device;
2165 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002166 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002167 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002168 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002169
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002170 weston_log("initializing drm backend\n");
2171
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002172 ec = malloc(sizeof *ec);
2173 if (ec == NULL)
2174 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002175 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002176
2177 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002178 config_file) < 0) {
2179 weston_log("weston_compositor_init failed\n");
2180 goto err_base;
2181 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002182
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002183 ec->udev = udev_new();
2184 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002185 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002186 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002187 }
2188
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002189 ec->base.wl_display = display;
2190 ec->tty = tty_create(&ec->base, vt_func, tty);
2191 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002192 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002193 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002194 }
2195
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002196 e = udev_enumerate_new(ec->udev);
2197 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002198 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002199
Benjamin Franzke117483d2011-08-30 11:38:26 +02002200 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002201 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002202 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002203 path = udev_list_entry_get_name(entry);
2204 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002205 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002206 udev_device_get_property_value(device, "ID_SEAT");
2207 if (!device_seat)
2208 device_seat = default_seat;
2209 if (strcmp(device_seat, seat) == 0) {
2210 drm_device = device;
2211 break;
2212 }
2213 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002214 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002215
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002216 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002217 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002218 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002219 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002220
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002221 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002222 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002223 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002224 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002225
2226 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002227 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002228
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002229 ec->base.focus = 1;
2230
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002231 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002232
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002233 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002234 weston_compositor_add_key_binding(&ec->base, key,
2235 MODIFIER_CTRL | MODIFIER_ALT,
2236 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002237
Jesse Barnes58ef3792012-02-23 09:45:49 -05002238 wl_list_init(&ec->sprite_list);
2239 create_sprites(ec);
2240
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002241 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002242 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002243 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002244 }
2245
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002246 if (gles2_renderer_init(&ec->base) < 0)
2247 goto err_egl;
2248
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002249 path = NULL;
2250
Tiago Vignattice03ec32011-12-19 01:14:03 +02002251 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002252
2253 loop = wl_display_get_event_loop(ec->base.wl_display);
2254 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002255 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002256 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002257
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002258 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2259 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002260 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002261 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002262 }
2263 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2264 "drm", NULL);
2265 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002266 wl_event_loop_add_fd(loop,
2267 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002268 WL_EVENT_READABLE, udev_drm_event, ec);
2269
2270 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002271 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002272 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002273 }
2274
Daniel Stonea96b93c2012-06-22 14:04:37 +01002275 udev_device_unref(drm_device);
2276 udev_enumerate_unref(e);
2277
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002278 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002279
2280err_udev_monitor:
2281 wl_event_source_remove(ec->udev_drm_source);
2282 udev_monitor_unref(ec->udev_monitor);
2283err_drm_source:
2284 wl_event_source_remove(ec->drm_source);
2285 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2286 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002287err_egl:
2288 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2289 EGL_NO_CONTEXT);
2290 eglTerminate(ec->base.egl_display);
2291 eglReleaseThread();
2292 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002293err_sprite:
2294 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002295err_udev_dev:
2296 udev_device_unref(drm_device);
2297err_udev_enum:
2298 udev_enumerate_unref(e);
2299 tty_destroy(ec->tty);
2300err_udev:
2301 udev_unref(ec->udev);
2302err_compositor:
2303 weston_compositor_shutdown(&ec->base);
2304err_base:
2305 free(ec);
2306 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002307}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002308
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002309static int
2310set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2311{
2312 mode->flags = 0;
2313
2314 if (strcmp(hsync, "+hsync") == 0)
2315 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2316 else if (strcmp(hsync, "-hsync") == 0)
2317 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2318 else
2319 return -1;
2320
2321 if (strcmp(vsync, "+vsync") == 0)
2322 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2323 else if (strcmp(vsync, "-vsync") == 0)
2324 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2325 else
2326 return -1;
2327
2328 return 0;
2329}
2330
2331static int
2332check_for_modeline(struct drm_configured_output *output)
2333{
2334 drmModeModeInfo mode;
2335 char hsync[16];
2336 char vsync[16];
2337 char mode_name[16];
2338 float fclock;
2339
2340 mode.type = DRM_MODE_TYPE_USERDEF;
2341 mode.hskew = 0;
2342 mode.vscan = 0;
2343 mode.vrefresh = 0;
2344
2345 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2346 &fclock, &mode.hdisplay,
2347 &mode.hsync_start,
2348 &mode.hsync_end, &mode.htotal,
2349 &mode.vdisplay,
2350 &mode.vsync_start,
2351 &mode.vsync_end, &mode.vtotal,
2352 hsync, vsync) == 11) {
2353 if (set_sync_flags(&mode, hsync, vsync))
2354 return -1;
2355
2356 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2357 strcpy(mode.name, mode_name);
2358
2359 mode.clock = fclock * 1000;
2360 } else
2361 return -1;
2362
2363 output->crtc_mode = mode;
2364
2365 return 0;
2366}
2367
Scott Moreau8ab5d452012-07-30 19:51:08 -06002368static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002369drm_output_set_transform(struct drm_configured_output *output)
2370{
2371 if (!output_transform) {
2372 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2373 return;
2374 }
2375
2376 if (!strcmp(output_transform, "normal"))
2377 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2378 else if (!strcmp(output_transform, "90"))
2379 output->transform = WL_OUTPUT_TRANSFORM_90;
2380 else if (!strcmp(output_transform, "180"))
2381 output->transform = WL_OUTPUT_TRANSFORM_180;
2382 else if (!strcmp(output_transform, "270"))
2383 output->transform = WL_OUTPUT_TRANSFORM_270;
2384 else if (!strcmp(output_transform, "flipped"))
2385 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2386 else if (!strcmp(output_transform, "flipped-90"))
2387 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2388 else if (!strcmp(output_transform, "flipped-180"))
2389 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2390 else if (!strcmp(output_transform, "flipped-270"))
2391 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2392 else {
2393 weston_log("Invalid transform \"%s\" for output %s\n",
2394 output_transform, output_name);
2395 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2396 }
2397
2398 free(output_transform);
2399 output_transform = NULL;
2400}
2401
2402static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002403output_section_done(void *data)
2404{
2405 struct drm_configured_output *output;
2406
2407 output = malloc(sizeof *output);
2408
Scott Moreau1bad5db2012-08-18 01:04:05 -06002409 if (!output || !output_name || (output_name[0] == 'X') ||
2410 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002411 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002412 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002413 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002414 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002415 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002416 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002417 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002418 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002419 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002420
2421 output->config = OUTPUT_CONFIG_INVALID;
2422 output->name = output_name;
2423 output->mode = output_mode;
2424
Scott Moreau1bad5db2012-08-18 01:04:05 -06002425 if (output_mode) {
2426 if (strcmp(output_mode, "off") == 0)
2427 output->config = OUTPUT_CONFIG_OFF;
2428 else if (strcmp(output_mode, "preferred") == 0)
2429 output->config = OUTPUT_CONFIG_PREFERRED;
2430 else if (strcmp(output_mode, "current") == 0)
2431 output->config = OUTPUT_CONFIG_CURRENT;
2432 else if (sscanf(output_mode, "%dx%d",
2433 &output->width, &output->height) == 2)
2434 output->config = OUTPUT_CONFIG_MODE;
2435 else if (check_for_modeline(output) == 0)
2436 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002437
Scott Moreau1bad5db2012-08-18 01:04:05 -06002438 if (output->config == OUTPUT_CONFIG_INVALID)
2439 weston_log("Invalid mode \"%s\" for output %s\n",
2440 output_mode, output_name);
2441 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002442 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002443
2444 drm_output_set_transform(output);
2445
2446 wl_list_insert(&configured_output_list, &output->link);
2447
2448 if (output_transform)
2449 free(output_transform);
2450 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002451}
2452
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002453WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002454backend_init(struct wl_display *display, int argc, char *argv[],
2455 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002456{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002457 int connector = 0, tty = 0;
2458 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002459
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002460 const struct weston_option drm_options[] = {
2461 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2462 { WESTON_OPTION_STRING, "seat", 0, &seat },
2463 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002464 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002465 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002466
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002467 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002468
Scott Moreau8ab5d452012-07-30 19:51:08 -06002469 wl_list_init(&configured_output_list);
2470
2471 const struct config_key drm_config_keys[] = {
2472 { "name", CONFIG_KEY_STRING, &output_name },
2473 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002474 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002475 };
2476
2477 const struct config_section config_section[] = {
2478 { "output", drm_config_keys,
2479 ARRAY_LENGTH(drm_config_keys), output_section_done },
2480 };
2481
2482 parse_config_file(config_file, config_section,
2483 ARRAY_LENGTH(config_section), NULL);
2484
Daniel Stonec1be8e52012-06-01 11:14:02 -04002485 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2486 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002487}