blob: 8ff7f3bd27f75dc35c27baa6a472df54dd3d4a7e [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;
49static struct wl_list configured_output_list;
50
51enum output_config {
52 OUTPUT_CONFIG_INVALID = 0,
53 OUTPUT_CONFIG_OFF,
54 OUTPUT_CONFIG_PREFERRED,
55 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060056 OUTPUT_CONFIG_MODE,
57 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060058};
59
60struct drm_configured_output {
61 char *name;
62 char *mode;
63 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060064 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065 enum output_config config;
66 struct wl_list link;
67};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040068
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050070 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
72 struct udev *udev;
73 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010075 struct udev_monitor *udev_monitor;
76 struct wl_event_source *udev_drm_source;
77
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010079 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 int fd;
81 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020082 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050083 uint32_t *crtcs;
84 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050085 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010086 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050087 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020088
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040089 struct gbm_surface *dummy_surface;
90 EGLSurface dummy_egl_surface;
91
Rob Clark4339add2012-08-09 14:18:28 -050092 /* we need these parameters in order to not fail drmModeAddFB2()
93 * due to out of bounds dimensions, and then mistakenly set
94 * sprites_are_broken:
95 */
96 uint32_t min_width, max_width;
97 uint32_t min_height, max_height;
98
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200102 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400103};
104
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400105struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500106 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400107 drmModeModeInfo mode_info;
108};
109
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300110struct drm_output;
111
112struct drm_fb {
113 struct gbm_bo *bo;
114 struct drm_output *output;
115 uint32_t fb_id;
116 int is_client_buffer;
117 struct wl_buffer *buffer;
118 struct wl_listener buffer_destroy_listener;
119};
120
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400121struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500122 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400123
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400124 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500126 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400127 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700128 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200129
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300130 int vblank_pending;
131 int page_flip_pending;
132
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400133 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400134 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400135 struct weston_plane cursor_plane;
136 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400137 struct weston_surface *cursor_surface;
138 int current_cursor;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400139 EGLSurface egl_surface;
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
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300295 /* Need to verify output->region contained in surface opaque
296 * region. Or maybe just that format doesn't have alpha.
297 * For now, scanout only if format is XRGB8888. */
298 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
299 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400300 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300301 }
302
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300303 output->next = drm_fb_get_from_bo(bo, output);
304 if (!output->next) {
305 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400306 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300307 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500308
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300309 output->next->is_client_buffer = 1;
310 output->next->buffer = es->buffer;
311 output->next->buffer->busy_count++;
312 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
313
314 wl_signal_add(&output->next->buffer->resource.destroy_signal,
315 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500316
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400317 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500318}
319
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500320static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400321drm_output_render(struct drm_output *output, pixman_region32_t *damage)
322{
323 struct drm_compositor *compositor =
324 (struct drm_compositor *) output->base.compositor;
325 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300326 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400327
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400328 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
329 output->egl_surface,
330 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200331 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400332 return;
333 }
334
335 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400336 if (surface->plane == &compositor->base.primary_plane)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400337 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400338
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400339 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600340
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400341 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300342 bo = gbm_surface_lock_front_buffer(output->surface);
343 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200344 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400345 return;
346 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300347
348 output->next = drm_fb_get_from_bo(bo, output);
349 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200350 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300351 gbm_surface_release_buffer(output->surface, bo);
352 return;
353 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400354}
355
356static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500357drm_output_repaint(struct weston_output *output_base,
358 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100359{
360 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500361 struct drm_compositor *compositor =
362 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500363 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400364 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500365 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100366
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400368 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300369 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400370 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100371
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400372 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300373 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400374 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300375 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400376 &output->connector_id, 1,
377 &mode->mode_info);
378 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200379 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400380 return;
381 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200382 }
383
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500384 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300385 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500386 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200387 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500388 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500389 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100390
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300391 output->page_flip_pending = 1;
392
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400393 drm_output_set_cursor(output);
394
Jesse Barnes58ef3792012-02-23 09:45:49 -0500395 /*
396 * Now, update all the sprite surfaces
397 */
398 wl_list_for_each(s, &compositor->sprite_list, link) {
399 uint32_t flags = 0;
400 drmVBlank vbl = {
401 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
402 .request.sequence = 1,
403 };
404
405 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
406 continue;
407
408 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
409 output->crtc_id, s->pending_fb_id, flags,
410 s->dest_x, s->dest_y,
411 s->dest_w, s->dest_h,
412 s->src_x, s->src_y,
413 s->src_w, s->src_h);
414 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200415 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500416 ret, strerror(errno));
417
Rob Clark5ca1a472012-08-08 20:27:37 -0500418 if (output->pipe > 0)
419 vbl.request.type |= DRM_VBLANK_SECONDARY;
420
Jesse Barnes58ef3792012-02-23 09:45:49 -0500421 /*
422 * Queue a vblank signal so we know when the surface
423 * becomes active on the display or has been replaced.
424 */
425 vbl.request.signal = (unsigned long)s;
426 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
427 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200428 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500429 ret, strerror(errno));
430 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300431
432 s->output = output;
433 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500434 }
435
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400436 drm_disable_unused_sprites(&output->base);
437
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500438 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400439}
440
441static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500442vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
443 void *data)
444{
445 struct drm_sprite *s = (struct drm_sprite *)data;
446 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300447 struct drm_output *output = s->output;
448 uint32_t msecs;
449
450 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500451
452 if (s->surface) {
453 weston_buffer_post_release(s->surface->buffer);
454 wl_list_remove(&s->destroy_listener.link);
455 s->surface = NULL;
456 drmModeRmFB(c->drm.fd, s->fb_id);
457 s->fb_id = 0;
458 }
459
460 if (s->pending_surface) {
461 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400462 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
463 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500464 s->surface = s->pending_surface;
465 s->pending_surface = NULL;
466 s->fb_id = s->pending_fb_id;
467 s->pending_fb_id = 0;
468 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300469
470 if (!output->page_flip_pending) {
471 msecs = sec * 1000 + usec / 1000;
472 weston_output_finish_frame(&output->base, msecs);
473 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500474}
475
476static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400477page_flip_handler(int fd, unsigned int frame,
478 unsigned int sec, unsigned int usec, void *data)
479{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200480 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400481 uint32_t msecs;
482
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300483 output->page_flip_pending = 0;
484
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300485 if (output->current) {
486 if (output->current->is_client_buffer)
487 gbm_bo_destroy(output->current->bo);
488 else
489 gbm_surface_release_buffer(output->surface,
490 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200491 }
492
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300493 output->current = output->next;
494 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400495
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300496 if (!output->vblank_pending) {
497 msecs = sec * 1000 + usec / 1000;
498 weston_output_finish_frame(&output->base, msecs);
499 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200500}
501
502static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500503drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
504{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400505 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500506
507 for (i = 0; i < s->count_formats; i++)
508 if (s->formats[i] == format)
509 return 1;
510
511 return 0;
512}
513
514static int
515drm_surface_transform_supported(struct weston_surface *es)
516{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400517 struct weston_matrix *matrix = &es->transform.matrix;
518 int i;
519
520 if (!es->transform.enabled)
521 return 1;
522
523 for (i = 0; i < 16; i++) {
524 switch (i) {
525 case 10:
526 case 15:
527 if (matrix->d[i] != 1.0)
528 return 0;
529 break;
530 case 0:
531 case 5:
532 case 12:
533 case 13:
534 break;
535 default:
536 if (matrix->d[i] != 0.0)
537 return 0;
538 break;
539 }
540 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500541
542 return 1;
543}
544
Jesse Barnes58ef3792012-02-23 09:45:49 -0500545static void
546drm_disable_unused_sprites(struct weston_output *output_base)
547{
548 struct weston_compositor *ec = output_base->compositor;
549 struct drm_compositor *c =(struct drm_compositor *) ec;
550 struct drm_output *output = (struct drm_output *) output_base;
551 struct drm_sprite *s;
Rob Clark4339add2012-08-09 14:18:28 -0500552 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500553 int ret;
554
555 wl_list_for_each(s, &c->sprite_list, link) {
556 if (s->pending_fb_id)
557 continue;
558
559 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
560 output->crtc_id, 0, 0,
561 0, 0, 0, 0, 0, 0, 0, 0);
562 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200563 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500564 ret, strerror(errno));
565 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300566
567 if (s->surface) {
568 s->surface = NULL;
569 wl_list_remove(&s->destroy_listener.link);
570 }
571
572 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573 s->fb_id = 0;
574 s->pending_fb_id = 0;
575 }
576}
577
578/*
579 * This function must take care to damage any previously assigned surface
580 * if the sprite ends up binding to a different surface than in the
581 * previous frame.
582 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400583static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500584drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400585 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586{
587 struct weston_compositor *ec = output_base->compositor;
588 struct drm_compositor *c =(struct drm_compositor *) ec;
589 struct drm_sprite *s;
590 int found = 0;
591 EGLint handle, stride;
592 struct gbm_bo *bo;
593 uint32_t fb_id = 0;
594 uint32_t handles[4], pitches[4], offsets[4];
595 int ret = 0;
596 pixman_region32_t dest_rect, src_rect;
597 pixman_box32_t *box;
598 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400599 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500601 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400602 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500603
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300604 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400605 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300606
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400607 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400608 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609
Rob Clark702ffae2012-08-09 14:18:27 -0500610 if (wl_buffer_is_shm(es->buffer))
611 return NULL;
612
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400614 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615
Jesse Barnes58ef3792012-02-23 09:45:49 -0500616 wl_list_for_each(s, &c->sprite_list, link) {
617 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
618 continue;
619
620 if (!s->pending_fb_id) {
621 found = 1;
622 break;
623 }
624 }
625
626 /* No sprites available */
627 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400628 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629
Rob Clark4339add2012-08-09 14:18:28 -0500630 width = es->geometry.width;
631 height = es->geometry.height;
632
633 /* If geometry is out of bounds, don't even bother trying because
634 * we know the AddFB2() call will fail:
635 */
636 if (c->min_width > width || width > c->max_width ||
637 c->min_height > height || height > c->max_height)
638 return -1;
639
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400640 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
641 es->buffer, GBM_BO_USE_SCANOUT);
642 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400643 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400644
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 format = gbm_bo_get_format(bo);
646 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400647 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500648
649 gbm_bo_destroy(bo);
650
651 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400652 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653
654 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400655 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500656
657 handles[0] = handle;
658 pitches[0] = stride;
659 offsets[0] = 0;
660
Rob Clark4339add2012-08-09 14:18:28 -0500661 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500662 format, handles, pitches, offsets,
663 &fb_id, 0);
664 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200665 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500666 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400667 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500668 }
669
Jesse Barnes58ef3792012-02-23 09:45:49 -0500670 s->pending_fb_id = fb_id;
671 s->pending_surface = es;
672 es->buffer->busy_count++;
673
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400674 box = pixman_region32_extents(&es->transform.boundingbox);
675 s->plane.x = box->x1;
676 s->plane.y = box->y1;
677
Jesse Barnes58ef3792012-02-23 09:45:49 -0500678 /*
679 * Calculate the source & dest rects properly based on actual
680 * postion (note the caller has called weston_surface_update_transform()
681 * for us already).
682 */
683 pixman_region32_init(&dest_rect);
684 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
685 &output_base->region);
686 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
687 box = pixman_region32_extents(&dest_rect);
688 s->dest_x = box->x1;
689 s->dest_y = box->y1;
690 s->dest_w = box->x2 - box->x1;
691 s->dest_h = box->y2 - box->y1;
692 pixman_region32_fini(&dest_rect);
693
694 pixman_region32_init(&src_rect);
695 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
696 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400698
699 weston_surface_from_global_fixed(es,
700 wl_fixed_from_int(box->x1),
701 wl_fixed_from_int(box->y1),
702 &sx1, &sy1);
703 weston_surface_from_global_fixed(es,
704 wl_fixed_from_int(box->x2),
705 wl_fixed_from_int(box->y2),
706 &sx2, &sy2);
707
708 if (sx1 < 0)
709 sx1 = 0;
710 if (sy1 < 0)
711 sy1 = 0;
712 if (sx2 > wl_fixed_from_int(es->geometry.width))
713 sx2 = wl_fixed_from_int(es->geometry.width);
714 if (sy2 > wl_fixed_from_int(es->geometry.height))
715 sy2 = wl_fixed_from_int(es->geometry.height);
716
717 s->src_x = sx1 << 8;
718 s->src_y = sy1 << 8;
719 s->src_w = (sx2 - sx1) << 8;
720 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500721 pixman_region32_fini(&src_rect);
722
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400723 wl_signal_add(&es->buffer->resource.destroy_signal,
724 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400725
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400726 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500727}
728
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400729static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400730drm_output_prepare_cursor_surface(struct weston_output *output_base,
731 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500732{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400733 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400734
735 if (output->cursor_surface)
736 return NULL;
737 if (es->output_mask != (1u << output_base->id))
738 return NULL;
739 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
740 es->geometry.width > 64 || es->geometry.height > 64)
741 return NULL;
742
743 output->cursor_surface = es;
744
745 return &output->cursor_plane;
746}
747
748static void
749drm_output_set_cursor(struct drm_output *output)
750{
751 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400752 struct drm_compositor *c =
753 (struct drm_compositor *) output->base.compositor;
754 EGLint handle, stride;
755 struct gbm_bo *bo;
756 uint32_t buf[64 * 64];
757 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400758 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500759
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400760 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400761 if (es == NULL) {
762 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
763 return;
764 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500765
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400766 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
767 pixman_region32_fini(&output->cursor_plane.damage);
768 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400769 output->current_cursor ^= 1;
770 bo = output->cursor_bo[output->current_cursor];
771 memset(buf, 0, sizeof buf);
772 stride = wl_shm_buffer_get_stride(es->buffer);
773 s = wl_shm_buffer_get_data(es->buffer);
774 for (i = 0; i < es->geometry.height; i++)
775 memcpy(buf + i * 64, s + i * stride,
776 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500777
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400778 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300779 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400780
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400781 handle = gbm_bo_get_handle(bo).s32;
782 if (drmModeSetCursor(c->drm.fd,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400783 output->crtc_id, handle, 64, 64))
Pekka Paalanenae29da22012-08-06 14:57:05 +0300784 weston_log("failed to set cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400785 }
786
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400787 x = es->geometry.x - output->base.x;
788 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400789 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
790 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y))
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400791 weston_log("failed to move cursor: %m\n");
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400792 output->cursor_plane.x = x;
793 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400794 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500795}
796
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797static void
798drm_assign_planes(struct weston_output *output)
799{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400800 struct drm_compositor *c =
801 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400802 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500803 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400804 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500805
806 /*
807 * Find a surface for each sprite in the output using some heuristics:
808 * 1) size
809 * 2) frequency of update
810 * 3) opacity (though some hw might support alpha blending)
811 * 4) clipping (this can be fixed with color keys)
812 *
813 * The idea is to save on blitting since this should save power.
814 * If we can get a large video surface on the sprite for example,
815 * the main display surface may not need to update at all, and
816 * the client buffer can be used directly for the sprite surface
817 * as we do for flipping full screen surfaces.
818 */
819 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400820 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400821 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500822 pixman_region32_init(&surface_overlap);
823 pixman_region32_intersect(&surface_overlap, &overlap,
824 &es->transform.boundingbox);
825
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400826 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400827 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400828 next_plane = primary;
829 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400830 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400831 if (next_plane == NULL)
832 next_plane = drm_output_prepare_scanout_surface(output, es);
833 if (next_plane == NULL)
834 next_plane = drm_output_prepare_overlay_surface(output, es);
835 if (next_plane == NULL)
836 next_plane = primary;
837 weston_surface_move_to_plane(es, next_plane);
838 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839 pixman_region32_union(&overlap, &overlap,
840 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400841
Jesse Barnes58ef3792012-02-23 09:45:49 -0500842 pixman_region32_fini(&surface_overlap);
843 }
844 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845}
846
Matt Roper361d2ad2011-08-29 13:52:23 -0700847static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500848drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700849{
850 struct drm_output *output = (struct drm_output *) output_base;
851 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200852 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700853 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700854
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200855 if (output->backlight)
856 backlight_destroy(output->backlight);
857
Matt Roper361d2ad2011-08-29 13:52:23 -0700858 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400859 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700860
861 /* Restore original CRTC state */
862 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200863 origcrtc->x, origcrtc->y,
864 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700865 drmModeFreeCrtc(origcrtc);
866
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200867 c->crtc_allocator &= ~(1 << output->crtc_id);
868 c->connector_allocator &= ~(1 << output->connector_id);
869
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400870 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400871 gbm_surface_destroy(output->surface);
872
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400873 weston_plane_release(&output->fb_plane);
874 weston_plane_release(&output->cursor_plane);
875
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500876 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200877 wl_list_remove(&output->base.link);
878
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400879 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700880 free(output);
881}
882
Alex Wub7b8bda2012-04-17 17:20:48 +0800883static struct drm_mode *
884choose_mode (struct drm_output *output, struct weston_mode *target_mode)
885{
886 struct drm_mode *tmp_mode = NULL, *mode;
887
888 if (output->base.current->width == target_mode->width &&
889 output->base.current->height == target_mode->height &&
890 (output->base.current->refresh == target_mode->refresh ||
891 target_mode->refresh == 0))
892 return (struct drm_mode *)output->base.current;
893
894 wl_list_for_each(mode, &output->base.mode_list, base.link) {
895 if (mode->mode_info.hdisplay == target_mode->width &&
896 mode->mode_info.vdisplay == target_mode->height) {
897 if (mode->mode_info.vrefresh == target_mode->refresh ||
898 target_mode->refresh == 0) {
899 return mode;
900 } else if (!tmp_mode)
901 tmp_mode = mode;
902 }
903 }
904
905 return tmp_mode;
906}
907
908static int
909drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
910{
911 struct drm_output *output;
912 struct drm_mode *drm_mode;
913 int ret;
914 struct drm_compositor *ec;
915 struct gbm_surface *surface;
916 EGLSurface egl_surface;
917
918 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200919 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800920 return -1;
921 }
922
923 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200924 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800925 return -1;
926 }
927
928 ec = (struct drm_compositor *)output_base->compositor;
929 output = (struct drm_output *)output_base;
930 drm_mode = choose_mode (output, mode);
931
932 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200933 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800934 return -1;
935 } else if (&drm_mode->base == output->base.current) {
936 return 0;
937 } else if (drm_mode->base.width == output->base.current->width &&
938 drm_mode->base.height == output->base.current->height) {
939 /* only change refresh value */
940 ret = drmModeSetCrtc(ec->drm.fd,
941 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300942 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800943 &output->connector_id, 1, &drm_mode->mode_info);
944
945 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200946 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800947 drm_mode->base.width,
948 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400949 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800950 ret = -1;
951 } else {
952 output->base.current->flags = 0;
953 output->base.current = &drm_mode->base;
954 drm_mode->base.flags =
955 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
956 ret = 0;
957 }
958
959 return ret;
960 }
961
962 drm_mode->base.flags =
963 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
964
965 surface = gbm_surface_create(ec->gbm,
966 drm_mode->base.width,
967 drm_mode->base.height,
968 GBM_FORMAT_XRGB8888,
969 GBM_BO_USE_SCANOUT |
970 GBM_BO_USE_RENDERING);
971 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200972 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 return -1;
974 }
975
976 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400977 eglCreateWindowSurface(ec->base.egl_display,
978 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800979 surface, NULL);
980
981 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200982 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800983 goto err;
984 }
985
986 ret = drmModeSetCrtc(ec->drm.fd,
987 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300988 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800989 &output->connector_id, 1, &drm_mode->mode_info);
990 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200991 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800992 goto err;
993 }
994
995 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300996 if (output->current) {
997 if (output->current->is_client_buffer)
998 gbm_bo_destroy(output->current->bo);
999 else
1000 gbm_surface_release_buffer(output->surface,
1001 output->current->bo);
1002 }
1003 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001004
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001005 if (output->next) {
1006 if (output->next->is_client_buffer)
1007 gbm_bo_destroy(output->next->bo);
1008 else
1009 gbm_surface_release_buffer(output->surface,
1010 output->next->bo);
1011 }
1012 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001013
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001014 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001015 gbm_surface_destroy(output->surface);
1016 output->egl_surface = egl_surface;
1017 output->surface = surface;
1018
1019 /*update output*/
1020 output->base.current = &drm_mode->base;
1021 output->base.dirty = 1;
1022 weston_output_move(&output->base, output->base.x, output->base.y);
1023 return 0;
1024
1025err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001026 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001027 gbm_surface_destroy(surface);
1028 return -1;
1029}
1030
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001031static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001032on_drm_input(int fd, uint32_t mask, void *data)
1033{
1034 drmEventContext evctx;
1035
1036 memset(&evctx, 0, sizeof evctx);
1037 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1038 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001039 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001040 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001041
1042 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001043}
1044
1045static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001046init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001047{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001048 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001049 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001050 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001051 static const EGLint context_attribs[] = {
1052 EGL_CONTEXT_CLIENT_VERSION, 2,
1053 EGL_NONE
1054 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001055
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001056 static const EGLint config_attribs[] = {
1057 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1058 EGL_RED_SIZE, 1,
1059 EGL_GREEN_SIZE, 1,
1060 EGL_BLUE_SIZE, 1,
1061 EGL_ALPHA_SIZE, 0,
1062 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1063 EGL_NONE
1064 };
1065
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001066 sysnum = udev_device_get_sysnum(device);
1067 if (sysnum)
1068 ec->drm.id = atoi(sysnum);
1069 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001070 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001071 return -1;
1072 }
1073
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001074 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001075 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001076 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001077 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001078 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001079 udev_device_get_devnode(device));
1080 return -1;
1081 }
1082
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001083 weston_log("using %s\n", filename);
1084
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001085 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001086 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001087 ec->base.egl_display = eglGetDisplay(ec->gbm);
1088 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001089 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001090 return -1;
1091 }
1092
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001093 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001094 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001095 return -1;
1096 }
1097
Darxus55973f22010-11-22 21:24:39 -05001098 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001099 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001100 return -1;
1101 }
1102
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001103 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1104 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001105 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001106 return -1;
1107 }
1108
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001109 ec->base.egl_context =
1110 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1111 EGL_NO_CONTEXT, context_attribs);
1112 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001113 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001114 return -1;
1115 }
1116
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001117 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1118 GBM_FORMAT_XRGB8888,
1119 GBM_BO_USE_RENDERING);
1120 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001121 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001122 return -1;
1123 }
1124
1125 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001126 eglCreateWindowSurface(ec->base.egl_display,
1127 ec->base.egl_config,
1128 ec->dummy_surface,
1129 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001130 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001131 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001132 return -1;
1133 }
1134
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001135 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1136 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001137 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001138 return -1;
1139 }
1140
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001141 return 0;
1142}
1143
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001144static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001145drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1146{
1147 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001148 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001149
1150 mode = malloc(sizeof *mode);
1151 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001152 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001153
1154 mode->base.flags = 0;
1155 mode->base.width = info->hdisplay;
1156 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001157
1158 /* Calculate higher precision (mHz) refresh rate */
1159 refresh = (info->clock * 1000000LL / info->htotal +
1160 info->vtotal / 2) / info->vtotal;
1161
1162 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1163 refresh *= 2;
1164 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1165 refresh /= 2;
1166 if (info->vscan > 1)
1167 refresh /= info->vscan;
1168
1169 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001170 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001171
1172 if (info->type & DRM_MODE_TYPE_PREFERRED)
1173 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1174
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001175 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1176
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001177 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001178}
1179
1180static int
1181drm_subpixel_to_wayland(int drm_value)
1182{
1183 switch (drm_value) {
1184 default:
1185 case DRM_MODE_SUBPIXEL_UNKNOWN:
1186 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1187 case DRM_MODE_SUBPIXEL_NONE:
1188 return WL_OUTPUT_SUBPIXEL_NONE;
1189 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1190 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1191 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1192 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1193 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1194 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1195 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1196 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1197 }
1198}
1199
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001200static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001201sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001202{
1203 struct drm_sprite *sprite =
1204 container_of(listener, struct drm_sprite,
1205 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001206 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001207
1208 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001209 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1210 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001211}
1212
1213static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001214sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001215{
1216 struct drm_sprite *sprite =
1217 container_of(listener, struct drm_sprite,
1218 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001219 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001220
1221 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001222 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1223 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001224}
1225
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001226/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001227static uint32_t
1228drm_get_backlight(struct drm_output *output)
1229{
1230 long brightness, max_brightness, norm;
1231
1232 brightness = backlight_get_brightness(output->backlight);
1233 max_brightness = backlight_get_max_brightness(output->backlight);
1234
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001235 /* convert it on a scale of 0 to 255 */
1236 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001237
1238 return (uint32_t) norm;
1239}
1240
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001241/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001242static void
1243drm_set_backlight(struct weston_output *output_base, uint32_t value)
1244{
1245 struct drm_output *output = (struct drm_output *) output_base;
1246 long max_brightness, new_brightness;
1247
1248 if (!output->backlight)
1249 return;
1250
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001251 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001252 return;
1253
1254 max_brightness = backlight_get_max_brightness(output->backlight);
1255
1256 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001257 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001258
1259 backlight_set_brightness(output->backlight, new_brightness);
1260}
1261
1262static drmModePropertyPtr
1263drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1264{
1265 drmModePropertyPtr props;
1266 int i;
1267
1268 for (i = 0; i < connector->count_props; i++) {
1269 props = drmModeGetProperty(fd, connector->props[i]);
1270 if (!props)
1271 continue;
1272
1273 if (!strcmp(props->name, name))
1274 return props;
1275
1276 drmModeFreeProperty(props);
1277 }
1278
1279 return NULL;
1280}
1281
1282static void
1283drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1284{
1285 struct drm_output *output = (struct drm_output *) output_base;
1286 struct weston_compositor *ec = output_base->compositor;
1287 struct drm_compositor *c = (struct drm_compositor *) ec;
1288 drmModeConnectorPtr connector;
1289 drmModePropertyPtr prop;
1290
1291 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1292 if (!connector)
1293 return;
1294
1295 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1296 if (!prop) {
1297 drmModeFreeConnector(connector);
1298 return;
1299 }
1300
1301 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1302 prop->prop_id, level);
1303 drmModeFreeProperty(prop);
1304 drmModeFreeConnector(connector);
1305}
1306
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001307static const char *connector_type_names[] = {
1308 "None",
1309 "VGA",
1310 "DVI",
1311 "DVI",
1312 "DVI",
1313 "Composite",
1314 "TV",
1315 "LVDS",
1316 "CTV",
1317 "DIN",
1318 "DP",
1319 "HDMI",
1320 "HDMI",
1321 "TV",
1322 "eDP",
1323};
1324
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001325static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001326find_crtc_for_connector(struct drm_compositor *ec,
1327 drmModeRes *resources, drmModeConnector *connector)
1328{
1329 drmModeEncoder *encoder;
1330 uint32_t possible_crtcs;
1331 int i, j;
1332
1333 for (j = 0; j < connector->count_encoders; j++) {
1334 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1335 if (encoder == NULL) {
1336 weston_log("Failed to get encoder.\n");
1337 return -1;
1338 }
1339 possible_crtcs = encoder->possible_crtcs;
1340 drmModeFreeEncoder(encoder);
1341
1342 for (i = 0; i < resources->count_crtcs; i++) {
1343 if (possible_crtcs & (1 << i) &&
1344 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1345 return i;
1346 }
1347 }
1348
1349 return -1;
1350}
1351
1352static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001353create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001354 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001355 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001356 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001357{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001358 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001359 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1360 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001361 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001362 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001363 drmModeModeInfo crtc_mode;
1364 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001365 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001366 char name[32];
1367 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001368
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001369 i = find_crtc_for_connector(ec, resources, connector);
1370 if (i < 0) {
1371 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001372 return -1;
1373 }
1374
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001375 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001376 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001377 return -1;
1378
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001379 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001380 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1381 output->base.make = "unknown";
1382 output->base.model = "unknown";
1383 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001384
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001385 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1386 type_name = connector_type_names[connector->connector_type];
1387 else
1388 type_name = "UNKNOWN";
1389 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1390 output->name = strdup(name);
1391
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001392 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001393 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001394 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001395 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001396 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001397
Matt Roper361d2ad2011-08-29 13:52:23 -07001398 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1399
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001400 /* Get the current mode on the crtc that's currently driving
1401 * this connector. */
1402 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001403 memset(&crtc_mode, 0, sizeof crtc_mode);
1404 if (encoder != NULL) {
1405 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1406 drmModeFreeEncoder(encoder);
1407 if (crtc == NULL)
1408 goto err_free;
1409 if (crtc->mode_valid)
1410 crtc_mode = crtc->mode;
1411 drmModeFreeCrtc(crtc);
1412 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001413
David Herrmann0f0d54e2011-12-08 17:05:45 +01001414 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001415 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1416 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001417 goto err_free;
1418 }
1419
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 preferred = NULL;
1421 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001422 configured = NULL;
1423
1424 wl_list_for_each(temp, &configured_output_list, link) {
1425 if (strcmp(temp->name, output->name) == 0) {
1426 weston_log("%s mode \"%s\" in config\n",
1427 temp->name, temp->mode);
1428 o = temp;
1429 break;
1430 }
1431 }
1432
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001433 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001434 weston_log("Disabling output %s\n", o->name);
1435
1436 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1437 0, 0, 0, 0, 0, NULL);
1438 goto err_free;
1439 }
1440
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001441 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001442 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001443 o->height == drm_mode->base.height &&
1444 o->config == OUTPUT_CONFIG_MODE)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001445 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001446 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001447 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001448 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001449 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001450 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001451
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001452 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001453 configured = drm_output_add_mode(output, &o->crtc_mode);
1454 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001455 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001456 current = configured;
1457 }
1458
Wang Quanxianacb805a2012-07-30 18:09:46 -04001459 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001460 current = drm_output_add_mode(output, &crtc_mode);
1461 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001462 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001463 }
1464
Scott Moreau8ab5d452012-07-30 19:51:08 -06001465 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1466 configured = current;
1467
Wang Quanxianacb805a2012-07-30 18:09:46 -04001468 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001469 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001470 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001471 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001472 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001473 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001474 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001475 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001476
1477 if (output->base.current == NULL) {
1478 weston_log("no available modes for %s\n", output->name);
1479 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001480 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001481
Wang Quanxianacb805a2012-07-30 18:09:46 -04001482 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1483
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001484 output->surface = gbm_surface_create(ec->gbm,
1485 output->base.current->width,
1486 output->base.current->height,
1487 GBM_FORMAT_XRGB8888,
1488 GBM_BO_USE_SCANOUT |
1489 GBM_BO_USE_RENDERING);
1490 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001491 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001492 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001493 }
1494
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001495 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001496 eglCreateWindowSurface(ec->base.egl_display,
1497 ec->base.egl_config,
1498 output->surface,
1499 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001500 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001501 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001502 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001503 }
1504
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001505 output->cursor_bo[0] =
1506 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1507 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1508 output->cursor_bo[1] =
1509 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1510 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1511
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001512 output->backlight = backlight_init(drm_device,
1513 connector->connector_type);
1514 if (output->backlight) {
1515 output->base.set_backlight = drm_set_backlight;
1516 output->base.backlight_current = drm_get_backlight(output);
1517 }
1518
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001519 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001520 connector->mmWidth, connector->mmHeight,
1521 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001522
1523 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1524
Alex Wubd3354b2012-04-17 17:20:49 +08001525 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001526 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001527 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001528 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001529 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001530 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001531
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001532 weston_plane_init(&output->cursor_plane, 0, 0);
1533 weston_plane_init(&output->fb_plane, 0, 0);
1534
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001535 weston_log("Output %s, (connector %d, crtc %d)\n",
1536 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001537 wl_list_for_each(m, &output->base.mode_list, link)
1538 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1539 m->width, m->height, m->refresh / 1000.0,
1540 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1541 ", preferred" : "",
1542 m->flags & WL_OUTPUT_MODE_CURRENT ?
1543 ", current" : "",
1544 connector->count_modes == 0 ?
1545 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001546
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001547 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001548
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001549err_surface:
1550 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001551err_free:
1552 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1553 base.link) {
1554 wl_list_remove(&drm_mode->base.link);
1555 free(drm_mode);
1556 }
1557
1558 drmModeFreeCrtc(output->original_crtc);
1559 ec->crtc_allocator &= ~(1 << output->crtc_id);
1560 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001561 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001562 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001563
David Herrmann0f0d54e2011-12-08 17:05:45 +01001564 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001565}
1566
Jesse Barnes58ef3792012-02-23 09:45:49 -05001567static void
1568create_sprites(struct drm_compositor *ec)
1569{
1570 struct drm_sprite *sprite;
1571 drmModePlaneRes *plane_res;
1572 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001573 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001574
1575 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1576 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001577 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001578 strerror(errno));
1579 return;
1580 }
1581
1582 for (i = 0; i < plane_res->count_planes; i++) {
1583 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1584 if (!plane)
1585 continue;
1586
1587 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1588 plane->count_formats));
1589 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001590 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001591 __func__);
1592 free(plane);
1593 continue;
1594 }
1595
1596 memset(sprite, 0, sizeof *sprite);
1597
1598 sprite->possible_crtcs = plane->possible_crtcs;
1599 sprite->plane_id = plane->plane_id;
1600 sprite->surface = NULL;
1601 sprite->pending_surface = NULL;
1602 sprite->fb_id = 0;
1603 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001604 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1605 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001606 sprite_handle_pending_buffer_destroy;
1607 sprite->compositor = ec;
1608 sprite->count_formats = plane->count_formats;
1609 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001610 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001611 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001612 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001613
1614 wl_list_insert(&ec->sprite_list, &sprite->link);
1615 }
1616
1617 free(plane_res->planes);
1618 free(plane_res);
1619}
1620
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001621static void
1622destroy_sprites(struct drm_compositor *compositor)
1623{
1624 struct drm_sprite *sprite, *next;
1625 struct drm_output *output;
1626
1627 output = container_of(compositor->base.output_list.next,
1628 struct drm_output, base.link);
1629
1630 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1631 drmModeSetPlane(compositor->drm.fd,
1632 sprite->plane_id,
1633 output->crtc_id, 0, 0,
1634 0, 0, 0, 0, 0, 0, 0, 0);
1635 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001636 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001637 free(sprite);
1638 }
1639}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001640
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001641static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001642create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001643 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001644{
1645 drmModeConnector *connector;
1646 drmModeRes *resources;
1647 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001648 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001649
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001650 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001651 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001652 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001653 return -1;
1654 }
1655
Jesse Barnes58ef3792012-02-23 09:45:49 -05001656 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001657 if (!ec->crtcs) {
1658 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001659 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001660 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001661
Rob Clark4339add2012-08-09 14:18:28 -05001662 ec->min_width = resources->min_width;
1663 ec->max_width = resources->max_width;
1664 ec->min_height = resources->min_height;
1665 ec->max_height = resources->max_height;
1666
Jesse Barnes58ef3792012-02-23 09:45:49 -05001667 ec->num_crtcs = resources->count_crtcs;
1668 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1669
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001670 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001671 connector = drmModeGetConnector(ec->drm.fd,
1672 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001673 if (connector == NULL)
1674 continue;
1675
1676 if (connector->connection == DRM_MODE_CONNECTED &&
1677 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001678 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001679 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001680 connector, x, y,
1681 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001682 drmModeFreeConnector(connector);
1683 continue;
1684 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001685
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001686 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001687 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001688 link)->current->width;
1689 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001690
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001691 drmModeFreeConnector(connector);
1692 }
1693
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001694 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001695 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001696 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001697 return -1;
1698 }
1699
1700 drmModeFreeResources(resources);
1701
1702 return 0;
1703}
1704
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001705static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001706update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001707{
1708 drmModeConnector *connector;
1709 drmModeRes *resources;
1710 struct drm_output *output, *next;
1711 int x = 0, y = 0;
1712 int x_offset = 0, y_offset = 0;
1713 uint32_t connected = 0, disconnects = 0;
1714 int i;
1715
1716 resources = drmModeGetResources(ec->drm.fd);
1717 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001718 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001719 return;
1720 }
1721
1722 /* collect new connects */
1723 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001724 int connector_id = resources->connectors[i];
1725
1726 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001727 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001728 continue;
1729
David Herrmann7551cff2011-12-08 17:05:43 +01001730 if (connector->connection != DRM_MODE_CONNECTED) {
1731 drmModeFreeConnector(connector);
1732 continue;
1733 }
1734
Benjamin Franzke117483d2011-08-30 11:38:26 +02001735 connected |= (1 << connector_id);
1736
1737 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001738 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001739 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001740 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001741
1742 /* XXX: not yet needed, we die with 0 outputs */
1743 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001744 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001745 else
1746 x = 0;
1747 y = 0;
1748 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001749 connector, x, y,
1750 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001751 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001752
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001753 }
1754 drmModeFreeConnector(connector);
1755 }
1756 drmModeFreeResources(resources);
1757
1758 disconnects = ec->connector_allocator & ~connected;
1759 if (disconnects) {
1760 wl_list_for_each_safe(output, next, &ec->base.output_list,
1761 base.link) {
1762 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001763 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001764 output->base.x - x_offset,
1765 output->base.y - y_offset);
1766 }
1767
1768 if (disconnects & (1 << output->connector_id)) {
1769 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001770 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001771 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001772 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001773 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001774 }
1775 }
1776 }
1777
1778 /* FIXME: handle zero outputs, without terminating */
1779 if (ec->connector_allocator == 0)
1780 wl_display_terminate(ec->base.wl_display);
1781}
1782
1783static int
David Herrmannd7488c22012-03-11 20:05:21 +01001784udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001785{
David Herrmannd7488c22012-03-11 20:05:21 +01001786 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001787 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001788
1789 sysnum = udev_device_get_sysnum(device);
1790 if (!sysnum || atoi(sysnum) != ec->drm.id)
1791 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001792
David Herrmann6ac52db2012-03-11 20:05:22 +01001793 val = udev_device_get_property_value(device, "HOTPLUG");
1794 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001795 return 0;
1796
David Herrmann6ac52db2012-03-11 20:05:22 +01001797 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001798}
1799
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001800static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001801udev_drm_event(int fd, uint32_t mask, void *data)
1802{
1803 struct drm_compositor *ec = data;
1804 struct udev_device *event;
1805
1806 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001807
David Herrmannd7488c22012-03-11 20:05:21 +01001808 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001809 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001810
1811 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001812
1813 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001814}
1815
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001816static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001817drm_restore(struct weston_compositor *ec)
1818{
1819 struct drm_compositor *d = (struct drm_compositor *) ec;
1820
1821 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1822 weston_log("failed to drop master: %m\n");
1823 tty_reset(d->tty);
1824}
1825
Pekka Paalanen33156972012-08-03 13:30:30 -04001826static const char default_seat[] = "seat0";
1827
1828static void
1829device_added(struct udev_device *udev_device, struct drm_seat *master)
1830{
1831 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001832 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001833 const char *devnode;
1834 const char *device_seat;
1835 int fd;
1836
1837 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1838 if (!device_seat)
1839 device_seat = default_seat;
1840
1841 if (strcmp(device_seat, master->seat_id))
1842 return;
1843
1844 c = master->base.compositor;
1845 devnode = udev_device_get_devnode(udev_device);
1846
1847 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001848 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001849 * read. mtdev_get() also expects this. */
1850 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1851 if (fd < 0) {
1852 weston_log("opening input device '%s' failed.\n", devnode);
1853 return;
1854 }
1855
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001856 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001857 if (!device) {
1858 close(fd);
1859 weston_log("not using input device '%s'.\n", devnode);
1860 return;
1861 }
1862
1863 wl_list_insert(master->devices_list.prev, &device->link);
1864}
1865
1866static void
1867evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1868{
1869 struct drm_seat *seat = (struct drm_seat *) seat_base;
1870 struct udev_enumerate *e;
1871 struct udev_list_entry *entry;
1872 struct udev_device *device;
1873 const char *path, *sysname;
1874
1875 e = udev_enumerate_new(udev);
1876 udev_enumerate_add_match_subsystem(e, "input");
1877 udev_enumerate_scan_devices(e);
1878 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1879 path = udev_list_entry_get_name(entry);
1880 device = udev_device_new_from_syspath(udev, path);
1881
1882 sysname = udev_device_get_sysname(device);
1883 if (strncmp("event", sysname, 5) != 0) {
1884 udev_device_unref(device);
1885 continue;
1886 }
1887
1888 device_added(device, seat);
1889
1890 udev_device_unref(device);
1891 }
1892 udev_enumerate_unref(e);
1893
1894 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1895
1896 if (wl_list_empty(&seat->devices_list)) {
1897 weston_log(
1898 "warning: no input devices on entering Weston. "
1899 "Possible causes:\n"
1900 "\t- no permissions to read /dev/input/event*\n"
1901 "\t- seats misconfigured "
1902 "(Weston backend option 'seat', "
1903 "udev device property ID_SEAT)\n");
1904 }
1905}
1906
1907static int
1908evdev_udev_handler(int fd, uint32_t mask, void *data)
1909{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001910 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001911 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001912 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001913 const char *action;
1914 const char *devnode;
1915
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001916 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001917 if (!udev_device)
1918 return 1;
1919
1920 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001921 if (!action)
1922 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001923
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001924 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1925 goto out;
1926
1927 if (!strcmp(action, "add")) {
1928 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001929 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001930 else if (!strcmp(action, "remove")) {
1931 devnode = udev_device_get_devnode(udev_device);
1932 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1933 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001934 weston_log("input device %s, %s removed\n",
1935 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001936 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001937 break;
1938 }
1939 }
1940
1941out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001942 udev_device_unref(udev_device);
1943
1944 return 0;
1945}
1946
1947static int
1948evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1949{
1950 struct drm_seat *master = (struct drm_seat *) seat_base;
1951 struct wl_event_loop *loop;
1952 struct weston_compositor *c = master->base.compositor;
1953 int fd;
1954
1955 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1956 if (!master->udev_monitor) {
1957 weston_log("udev: failed to create the udev monitor\n");
1958 return 0;
1959 }
1960
1961 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1962 "input", NULL);
1963
1964 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1965 weston_log("udev: failed to bind the udev monitor\n");
1966 udev_monitor_unref(master->udev_monitor);
1967 return 0;
1968 }
1969
1970 loop = wl_display_get_event_loop(c->wl_display);
1971 fd = udev_monitor_get_fd(master->udev_monitor);
1972 master->udev_monitor_source =
1973 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1974 evdev_udev_handler, master);
1975 if (!master->udev_monitor_source) {
1976 udev_monitor_unref(master->udev_monitor);
1977 return 0;
1978 }
1979
1980 return 1;
1981}
1982
1983static void
1984evdev_disable_udev_monitor(struct weston_seat *seat_base)
1985{
1986 struct drm_seat *seat = (struct drm_seat *) seat_base;
1987
1988 if (!seat->udev_monitor)
1989 return;
1990
1991 udev_monitor_unref(seat->udev_monitor);
1992 seat->udev_monitor = NULL;
1993 wl_event_source_remove(seat->udev_monitor_source);
1994 seat->udev_monitor_source = NULL;
1995}
1996
1997static void
1998drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1999{
2000 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002001 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002002
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002003 wl_list_for_each(device, &seat->devices_list, link)
2004 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002005}
2006
2007static void
2008evdev_input_create(struct weston_compositor *c, struct udev *udev,
2009 const char *seat_id)
2010{
2011 struct drm_seat *seat;
2012
2013 seat = malloc(sizeof *seat);
2014 if (seat == NULL)
2015 return;
2016
2017 memset(seat, 0, sizeof *seat);
2018 weston_seat_init(&seat->base, c);
2019 seat->base.led_update = drm_led_update;
2020
2021 wl_list_init(&seat->devices_list);
2022 seat->seat_id = strdup(seat_id);
2023 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2024 free(seat->seat_id);
2025 free(seat);
2026 return;
2027 }
2028
2029 evdev_add_devices(udev, &seat->base);
2030
2031 c->seat = &seat->base;
2032}
2033
2034static void
2035evdev_remove_devices(struct weston_seat *seat_base)
2036{
2037 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002038 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002039
2040 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002041 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002042
Pekka Paalanend8583512012-08-03 14:39:11 +03002043 if (seat->base.seat.keyboard)
2044 notify_keyboard_focus_out(&seat->base.seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002045}
2046
2047static void
2048evdev_input_destroy(struct weston_seat *seat_base)
2049{
2050 struct drm_seat *seat = (struct drm_seat *) seat_base;
2051
2052 evdev_remove_devices(seat_base);
2053 evdev_disable_udev_monitor(&seat->base);
2054
2055 weston_seat_release(seat_base);
2056 free(seat->seat_id);
2057 free(seat);
2058}
2059
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002060static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002061drm_free_configured_output(struct drm_configured_output *output)
2062{
2063 free(output->name);
2064 free(output->mode);
2065 free(output);
2066}
2067
2068static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002069drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002070{
2071 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002072 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002073 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002074
Daniel Stone37816df2012-05-16 18:45:18 +01002075 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2076 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002077 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002078 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002079
2080 wl_event_source_remove(d->udev_drm_source);
2081 wl_event_source_remove(d->drm_source);
2082
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002083 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002084
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002085 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002086 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002087 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002088 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002089 eglReleaseThread();
2090
Matt Roper361d2ad2011-08-29 13:52:23 -07002091 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002092 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002093 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002094 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002095 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002096
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002097 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002098}
2099
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002100static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002101drm_compositor_set_modes(struct drm_compositor *compositor)
2102{
2103 struct drm_output *output;
2104 struct drm_mode *drm_mode;
2105 int ret;
2106
2107 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2108 drm_mode = (struct drm_mode *) output->base.current;
2109 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002110 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002111 &output->connector_id, 1,
2112 &drm_mode->mode_info);
2113 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002114 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002115 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002116 drm_mode->base.width, drm_mode->base.height,
2117 output->base.x, output->base.y);
2118 }
2119 }
2120}
2121
2122static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002123vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002124{
2125 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002126 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002127 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002128 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002129
2130 switch (event) {
2131 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002132 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002133 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002134 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002135 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002136 wl_display_terminate(compositor->wl_display);
2137 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002138 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002139 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002140 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002141 wl_list_for_each(seat, &compositor->seat_list, link) {
2142 evdev_add_devices(ec->udev, seat);
2143 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002144 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002145 break;
2146 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002147 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002148 wl_list_for_each(seat, &compositor->seat_list, link) {
2149 evdev_disable_udev_monitor(seat);
2150 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002151 }
2152
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002153 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002154 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002155 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002156
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002157 /* If we have a repaint scheduled (either from a
2158 * pending pageflip or the idle handler), make sure we
2159 * cancel that so we don't try to pageflip when we're
2160 * vt switched away. The SLEEPING state will prevent
2161 * further attemps at repainting. When we switch
2162 * back, we schedule a repaint, which will process
2163 * pending frame callbacks. */
2164
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002165 wl_list_for_each(output, &ec->base.output_list, base.link) {
2166 output->base.repaint_needed = 0;
2167 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002168 }
2169
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002170 output = container_of(ec->base.output_list.next,
2171 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002172
2173 wl_list_for_each(sprite, &ec->sprite_list, link)
2174 drmModeSetPlane(ec->drm.fd,
2175 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002176 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002177 0, 0, 0, 0, 0, 0, 0, 0);
2178
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002179 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002180 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002181
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002182 break;
2183 };
2184}
2185
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002186static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002187switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002188{
2189 struct drm_compositor *ec = data;
2190
Daniel Stone325fc2d2012-05-30 16:31:58 +01002191 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002192}
2193
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002194static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002195drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002196 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002197 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002198{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002199 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002200 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002201 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002202 struct udev_device *device, *drm_device;
2203 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002205 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002206 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002207
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002208 weston_log("initializing drm backend\n");
2209
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002210 ec = malloc(sizeof *ec);
2211 if (ec == NULL)
2212 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002213 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002214
2215 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002216 config_file) < 0) {
2217 weston_log("weston_compositor_init failed\n");
2218 goto err_base;
2219 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002220
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002221 ec->udev = udev_new();
2222 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002223 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002224 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002225 }
2226
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002227 ec->base.wl_display = display;
2228 ec->tty = tty_create(&ec->base, vt_func, tty);
2229 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002230 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002231 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002232 }
2233
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002234 e = udev_enumerate_new(ec->udev);
2235 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002236 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002237
Benjamin Franzke117483d2011-08-30 11:38:26 +02002238 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002239 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002240 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002241 path = udev_list_entry_get_name(entry);
2242 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002243 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002244 udev_device_get_property_value(device, "ID_SEAT");
2245 if (!device_seat)
2246 device_seat = default_seat;
2247 if (strcmp(device_seat, seat) == 0) {
2248 drm_device = device;
2249 break;
2250 }
2251 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002252 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002253
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002254 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002255 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002256 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002257 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002258
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002259 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002260 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002261 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002262 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002263
2264 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002265 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002266
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002267 ec->base.focus = 1;
2268
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002269 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002270
Daniel Stone725c2c32012-06-22 14:04:36 +01002271 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002272 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002273
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002274 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002275 weston_compositor_add_key_binding(&ec->base, key,
2276 MODIFIER_CTRL | MODIFIER_ALT,
2277 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002278
Jesse Barnes58ef3792012-02-23 09:45:49 -05002279 wl_list_init(&ec->sprite_list);
2280 create_sprites(ec);
2281
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002282 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002283 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002284 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002285 }
2286
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002287 path = NULL;
2288
Tiago Vignattice03ec32011-12-19 01:14:03 +02002289 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002290
2291 loop = wl_display_get_event_loop(ec->base.wl_display);
2292 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002293 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002294 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002295
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002296 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2297 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002298 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002299 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002300 }
2301 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2302 "drm", NULL);
2303 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002304 wl_event_loop_add_fd(loop,
2305 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002306 WL_EVENT_READABLE, udev_drm_event, ec);
2307
2308 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002309 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002310 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002311 }
2312
Daniel Stonea96b93c2012-06-22 14:04:37 +01002313 udev_device_unref(drm_device);
2314 udev_enumerate_unref(e);
2315
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002316 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002317
2318err_udev_monitor:
2319 wl_event_source_remove(ec->udev_drm_source);
2320 udev_monitor_unref(ec->udev_monitor);
2321err_drm_source:
2322 wl_event_source_remove(ec->drm_source);
2323 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2324 evdev_input_destroy(weston_seat);
2325err_sprite:
2326 destroy_sprites(ec);
2327err_egl:
2328 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2329 EGL_NO_CONTEXT);
2330 eglTerminate(ec->base.egl_display);
2331 eglReleaseThread();
2332 gbm_device_destroy(ec->gbm);
2333err_udev_dev:
2334 udev_device_unref(drm_device);
2335err_udev_enum:
2336 udev_enumerate_unref(e);
2337 tty_destroy(ec->tty);
2338err_udev:
2339 udev_unref(ec->udev);
2340err_compositor:
2341 weston_compositor_shutdown(&ec->base);
2342err_base:
2343 free(ec);
2344 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002345}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002346
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002347static int
2348set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2349{
2350 mode->flags = 0;
2351
2352 if (strcmp(hsync, "+hsync") == 0)
2353 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2354 else if (strcmp(hsync, "-hsync") == 0)
2355 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2356 else
2357 return -1;
2358
2359 if (strcmp(vsync, "+vsync") == 0)
2360 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2361 else if (strcmp(vsync, "-vsync") == 0)
2362 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2363 else
2364 return -1;
2365
2366 return 0;
2367}
2368
2369static int
2370check_for_modeline(struct drm_configured_output *output)
2371{
2372 drmModeModeInfo mode;
2373 char hsync[16];
2374 char vsync[16];
2375 char mode_name[16];
2376 float fclock;
2377
2378 mode.type = DRM_MODE_TYPE_USERDEF;
2379 mode.hskew = 0;
2380 mode.vscan = 0;
2381 mode.vrefresh = 0;
2382
2383 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2384 &fclock, &mode.hdisplay,
2385 &mode.hsync_start,
2386 &mode.hsync_end, &mode.htotal,
2387 &mode.vdisplay,
2388 &mode.vsync_start,
2389 &mode.vsync_end, &mode.vtotal,
2390 hsync, vsync) == 11) {
2391 if (set_sync_flags(&mode, hsync, vsync))
2392 return -1;
2393
2394 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2395 strcpy(mode.name, mode_name);
2396
2397 mode.clock = fclock * 1000;
2398 } else
2399 return -1;
2400
2401 output->crtc_mode = mode;
2402
2403 return 0;
2404}
2405
Scott Moreau8ab5d452012-07-30 19:51:08 -06002406static void
2407output_section_done(void *data)
2408{
2409 struct drm_configured_output *output;
2410
2411 output = malloc(sizeof *output);
2412
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002413 if (!output || !output_name || !output_mode) {
2414 free(output_name);
2415 output_name = NULL;
2416 free(output_mode);
2417 output_mode = 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
2425 if (strcmp(output_mode, "off") == 0)
2426 output->config = OUTPUT_CONFIG_OFF;
2427 else if (strcmp(output_mode, "preferred") == 0)
2428 output->config = OUTPUT_CONFIG_PREFERRED;
2429 else if (strcmp(output_mode, "current") == 0)
2430 output->config = OUTPUT_CONFIG_CURRENT;
2431 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2432 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002433 else if (check_for_modeline(output) == 0)
2434 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002435
2436 if (output->config != OUTPUT_CONFIG_INVALID)
2437 wl_list_insert(&configured_output_list, &output->link);
2438 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002439 weston_log("Invalid mode \"%s\" for output %s\n",
2440 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002441 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002442 }
2443}
2444
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002445WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002446backend_init(struct wl_display *display, int argc, char *argv[],
2447 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002448{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002449 int connector = 0, tty = 0;
2450 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002451
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002452 const struct weston_option drm_options[] = {
2453 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2454 { WESTON_OPTION_STRING, "seat", 0, &seat },
2455 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002456 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002457 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002458
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002459 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002460
Scott Moreau8ab5d452012-07-30 19:51:08 -06002461 wl_list_init(&configured_output_list);
2462
2463 const struct config_key drm_config_keys[] = {
2464 { "name", CONFIG_KEY_STRING, &output_name },
2465 { "mode", CONFIG_KEY_STRING, &output_mode },
2466 };
2467
2468 const struct config_section config_section[] = {
2469 { "output", drm_config_keys,
2470 ARRAY_LENGTH(drm_config_keys), output_section_done },
2471 };
2472
2473 parse_config_file(config_file, config_section,
2474 ARRAY_LENGTH(config_section), NULL);
2475
Daniel Stonec1be8e52012-06-01 11:14:02 -04002476 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2477 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002478}