blob: e3cf134a7285be87478158d4dc37fe3de6317ad6 [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
Jesse Barnes58ef3792012-02-23 09:45:49 -050092 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050093 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -050094
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020095 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040096};
97
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040098struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050099 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400100 drmModeModeInfo mode_info;
101};
102
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300103struct drm_output;
104
105struct drm_fb {
106 struct gbm_bo *bo;
107 struct drm_output *output;
108 uint32_t fb_id;
109 int is_client_buffer;
110 struct wl_buffer *buffer;
111 struct wl_listener buffer_destroy_listener;
112};
113
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400114struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500115 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400116
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400117 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400118 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500119 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400120 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700121 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200122
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300123 int vblank_pending;
124 int page_flip_pending;
125
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400126 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400127 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400128 struct weston_plane cursor_plane;
129 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400130 struct weston_surface *cursor_surface;
131 int current_cursor;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400132 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300133 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200134 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400135};
136
Jesse Barnes58ef3792012-02-23 09:45:49 -0500137/*
138 * An output has a primary display plane plus zero or more sprites for
139 * blending display contents.
140 */
141struct drm_sprite {
142 struct wl_list link;
143
144 uint32_t fb_id;
145 uint32_t pending_fb_id;
146 struct weston_surface *surface;
147 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400148 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500149
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300150 struct drm_output *output;
151
Jesse Barnes58ef3792012-02-23 09:45:49 -0500152 struct drm_compositor *compositor;
153
154 struct wl_listener destroy_listener;
155 struct wl_listener pending_destroy_listener;
156
157 uint32_t possible_crtcs;
158 uint32_t plane_id;
159 uint32_t count_formats;
160
161 int32_t src_x, src_y;
162 uint32_t src_w, src_h;
163 uint32_t dest_x, dest_y;
164 uint32_t dest_w, dest_h;
165
166 uint32_t formats[];
167};
168
Pekka Paalanen33156972012-08-03 13:30:30 -0400169struct drm_seat {
170 struct weston_seat base;
171 struct wl_list devices_list;
172 struct udev_monitor *udev_monitor;
173 struct wl_event_source *udev_monitor_source;
174 char *seat_id;
175};
176
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400177static void
178drm_output_set_cursor(struct drm_output *output);
179static void
180drm_disable_unused_sprites(struct weston_output *output_base);
181
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
184{
185 struct weston_compositor *ec = output_base->compositor;
186 struct drm_compositor *c =(struct drm_compositor *) ec;
187 struct drm_output *output = (struct drm_output *) output_base;
188 int crtc;
189
190 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
191 if (c->crtcs[crtc] != output->crtc_id)
192 continue;
193
194 if (supported & (1 << crtc))
195 return -1;
196 }
197
198 return 0;
199}
200
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300201static void
202drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
203{
204 struct drm_fb *fb = data;
205 struct gbm_device *gbm = gbm_bo_get_device(bo);
206
207 if (fb->fb_id)
208 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
209
210 if (fb->buffer) {
211 weston_buffer_post_release(fb->buffer);
212 wl_list_remove(&fb->buffer_destroy_listener.link);
213 }
214
215 free(data);
216}
217
218static struct drm_fb *
219drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
220{
221 struct drm_fb *fb = gbm_bo_get_user_data(bo);
222 struct drm_compositor *compositor =
223 (struct drm_compositor *) output->base.compositor;
224 uint32_t width, height, stride, handle;
225 int ret;
226
227 if (fb)
228 return fb;
229
230 fb = malloc(sizeof *fb);
231
232 fb->bo = bo;
233 fb->output = output;
234 fb->is_client_buffer = 0;
235 fb->buffer = NULL;
236
237 width = gbm_bo_get_width(bo);
238 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400239 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300240 handle = gbm_bo_get_handle(bo).u32;
241
242 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
243 stride, handle, &fb->fb_id);
244 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200245 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300246 free(fb);
247 return NULL;
248 }
249
250 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
251
252 return fb;
253}
254
255static void
256fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
257{
258 struct drm_fb *fb = container_of(listener, struct drm_fb,
259 buffer_destroy_listener);
260
261 fb->buffer = NULL;
262
263 if (fb == fb->output->next ||
264 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400265 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300266}
267
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400268static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400269drm_output_prepare_scanout_surface(struct weston_output *_output,
270 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500271{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400272 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500273 struct drm_compositor *c =
274 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300275 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500276
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500277 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200278 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200279 es->geometry.width != output->base.current->width ||
280 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200281 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400282 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400283 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500284
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400285 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
286 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500287
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300288 /* Need to verify output->region contained in surface opaque
289 * region. Or maybe just that format doesn't have alpha.
290 * For now, scanout only if format is XRGB8888. */
291 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
292 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400293 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300294 }
295
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300296 output->next = drm_fb_get_from_bo(bo, output);
297 if (!output->next) {
298 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400299 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300300 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500301
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300302 output->next->is_client_buffer = 1;
303 output->next->buffer = es->buffer;
304 output->next->buffer->busy_count++;
305 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
306
307 wl_signal_add(&output->next->buffer->resource.destroy_signal,
308 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500309
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400310 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500311}
312
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500313static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400314drm_output_render(struct drm_output *output, pixman_region32_t *damage)
315{
316 struct drm_compositor *compositor =
317 (struct drm_compositor *) output->base.compositor;
318 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300319 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400320
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400321 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
322 output->egl_surface,
323 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200324 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400325 return;
326 }
327
328 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400329 if (surface->plane == &compositor->base.primary_plane)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400330 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400331
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400332 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600333
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400334 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300335 bo = gbm_surface_lock_front_buffer(output->surface);
336 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200337 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400338 return;
339 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300340
341 output->next = drm_fb_get_from_bo(bo, output);
342 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200343 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300344 gbm_surface_release_buffer(output->surface, bo);
345 return;
346 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400347}
348
349static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500350drm_output_repaint(struct weston_output *output_base,
351 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100352{
353 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500354 struct drm_compositor *compositor =
355 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500356 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400357 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500358 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100359
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300360 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400361 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400363 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100364
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400365 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400367 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400369 &output->connector_id, 1,
370 &mode->mode_info);
371 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200372 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400373 return;
374 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200375 }
376
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500377 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500379 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200380 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500381 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500382 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100383
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300384 output->page_flip_pending = 1;
385
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400386 drm_output_set_cursor(output);
387
Jesse Barnes58ef3792012-02-23 09:45:49 -0500388 /*
389 * Now, update all the sprite surfaces
390 */
391 wl_list_for_each(s, &compositor->sprite_list, link) {
392 uint32_t flags = 0;
393 drmVBlank vbl = {
394 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
395 .request.sequence = 1,
396 };
397
398 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
399 continue;
400
401 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
402 output->crtc_id, s->pending_fb_id, flags,
403 s->dest_x, s->dest_y,
404 s->dest_w, s->dest_h,
405 s->src_x, s->src_y,
406 s->src_w, s->src_h);
407 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200408 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500409 ret, strerror(errno));
410
Rob Clark5ca1a472012-08-08 20:27:37 -0500411 if (output->pipe > 0)
412 vbl.request.type |= DRM_VBLANK_SECONDARY;
413
Jesse Barnes58ef3792012-02-23 09:45:49 -0500414 /*
415 * Queue a vblank signal so we know when the surface
416 * becomes active on the display or has been replaced.
417 */
418 vbl.request.signal = (unsigned long)s;
419 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
420 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200421 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500422 ret, strerror(errno));
423 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300424
425 s->output = output;
426 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500427 }
428
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400429 drm_disable_unused_sprites(&output->base);
430
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500431 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400432}
433
434static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500435vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
436 void *data)
437{
438 struct drm_sprite *s = (struct drm_sprite *)data;
439 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300440 struct drm_output *output = s->output;
441 uint32_t msecs;
442
443 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500444
445 if (s->surface) {
446 weston_buffer_post_release(s->surface->buffer);
447 wl_list_remove(&s->destroy_listener.link);
448 s->surface = NULL;
449 drmModeRmFB(c->drm.fd, s->fb_id);
450 s->fb_id = 0;
451 }
452
453 if (s->pending_surface) {
454 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400455 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
456 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500457 s->surface = s->pending_surface;
458 s->pending_surface = NULL;
459 s->fb_id = s->pending_fb_id;
460 s->pending_fb_id = 0;
461 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300462
463 if (!output->page_flip_pending) {
464 msecs = sec * 1000 + usec / 1000;
465 weston_output_finish_frame(&output->base, msecs);
466 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500467}
468
469static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400470page_flip_handler(int fd, unsigned int frame,
471 unsigned int sec, unsigned int usec, void *data)
472{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200473 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400474 uint32_t msecs;
475
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300476 output->page_flip_pending = 0;
477
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300478 if (output->current) {
479 if (output->current->is_client_buffer)
480 gbm_bo_destroy(output->current->bo);
481 else
482 gbm_surface_release_buffer(output->surface,
483 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200484 }
485
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300486 output->current = output->next;
487 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300489 if (!output->vblank_pending) {
490 msecs = sec * 1000 + usec / 1000;
491 weston_output_finish_frame(&output->base, msecs);
492 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200493}
494
495static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500496drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
497{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400498 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500499
500 for (i = 0; i < s->count_formats; i++)
501 if (s->formats[i] == format)
502 return 1;
503
504 return 0;
505}
506
507static int
508drm_surface_transform_supported(struct weston_surface *es)
509{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400510 struct weston_matrix *matrix = &es->transform.matrix;
511 int i;
512
513 if (!es->transform.enabled)
514 return 1;
515
516 for (i = 0; i < 16; i++) {
517 switch (i) {
518 case 10:
519 case 15:
520 if (matrix->d[i] != 1.0)
521 return 0;
522 break;
523 case 0:
524 case 5:
525 case 12:
526 case 13:
527 break;
528 default:
529 if (matrix->d[i] != 0.0)
530 return 0;
531 break;
532 }
533 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500534
535 return 1;
536}
537
Jesse Barnes58ef3792012-02-23 09:45:49 -0500538static void
539drm_disable_unused_sprites(struct weston_output *output_base)
540{
541 struct weston_compositor *ec = output_base->compositor;
542 struct drm_compositor *c =(struct drm_compositor *) ec;
543 struct drm_output *output = (struct drm_output *) output_base;
544 struct drm_sprite *s;
545 int ret;
546
547 wl_list_for_each(s, &c->sprite_list, link) {
548 if (s->pending_fb_id)
549 continue;
550
551 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
552 output->crtc_id, 0, 0,
553 0, 0, 0, 0, 0, 0, 0, 0);
554 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200555 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500556 ret, strerror(errno));
557 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300558
559 if (s->surface) {
560 s->surface = NULL;
561 wl_list_remove(&s->destroy_listener.link);
562 }
563
564 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500565 s->fb_id = 0;
566 s->pending_fb_id = 0;
567 }
568}
569
570/*
571 * This function must take care to damage any previously assigned surface
572 * if the sprite ends up binding to a different surface than in the
573 * previous frame.
574 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400575static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500576drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400577 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578{
579 struct weston_compositor *ec = output_base->compositor;
580 struct drm_compositor *c =(struct drm_compositor *) ec;
581 struct drm_sprite *s;
582 int found = 0;
583 EGLint handle, stride;
584 struct gbm_bo *bo;
585 uint32_t fb_id = 0;
586 uint32_t handles[4], pitches[4], offsets[4];
587 int ret = 0;
588 pixman_region32_t dest_rect, src_rect;
589 pixman_box32_t *box;
590 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400591 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500592
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500593 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400594 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500595
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300596 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400597 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300598
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400599 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400600 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601
602 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400603 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 wl_list_for_each(s, &c->sprite_list, link) {
606 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
607 continue;
608
609 if (!s->pending_fb_id) {
610 found = 1;
611 break;
612 }
613 }
614
615 /* No sprites available */
616 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400617 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400619 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
620 es->buffer, GBM_BO_USE_SCANOUT);
621 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400622 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400623
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 format = gbm_bo_get_format(bo);
625 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400626 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627
628 gbm_bo_destroy(bo);
629
630 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400631 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632
633 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400634 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635
636 handles[0] = handle;
637 pitches[0] = stride;
638 offsets[0] = 0;
639
640 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
641 format, handles, pitches, offsets,
642 &fb_id, 0);
643 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200644 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500645 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400646 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 }
648
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649 s->pending_fb_id = fb_id;
650 s->pending_surface = es;
651 es->buffer->busy_count++;
652
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400653 box = pixman_region32_extents(&es->transform.boundingbox);
654 s->plane.x = box->x1;
655 s->plane.y = box->y1;
656
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 /*
658 * Calculate the source & dest rects properly based on actual
659 * postion (note the caller has called weston_surface_update_transform()
660 * for us already).
661 */
662 pixman_region32_init(&dest_rect);
663 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
664 &output_base->region);
665 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
666 box = pixman_region32_extents(&dest_rect);
667 s->dest_x = box->x1;
668 s->dest_y = box->y1;
669 s->dest_w = box->x2 - box->x1;
670 s->dest_h = box->y2 - box->y1;
671 pixman_region32_fini(&dest_rect);
672
673 pixman_region32_init(&src_rect);
674 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
675 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500676 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400677
678 weston_surface_from_global_fixed(es,
679 wl_fixed_from_int(box->x1),
680 wl_fixed_from_int(box->y1),
681 &sx1, &sy1);
682 weston_surface_from_global_fixed(es,
683 wl_fixed_from_int(box->x2),
684 wl_fixed_from_int(box->y2),
685 &sx2, &sy2);
686
687 if (sx1 < 0)
688 sx1 = 0;
689 if (sy1 < 0)
690 sy1 = 0;
691 if (sx2 > wl_fixed_from_int(es->geometry.width))
692 sx2 = wl_fixed_from_int(es->geometry.width);
693 if (sy2 > wl_fixed_from_int(es->geometry.height))
694 sy2 = wl_fixed_from_int(es->geometry.height);
695
696 s->src_x = sx1 << 8;
697 s->src_y = sy1 << 8;
698 s->src_w = (sx2 - sx1) << 8;
699 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500700 pixman_region32_fini(&src_rect);
701
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400702 wl_signal_add(&es->buffer->resource.destroy_signal,
703 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400704
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400705 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706}
707
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400708static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400709drm_output_prepare_cursor_surface(struct weston_output *output_base,
710 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500711{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400712 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400713
714 if (output->cursor_surface)
715 return NULL;
716 if (es->output_mask != (1u << output_base->id))
717 return NULL;
718 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
719 es->geometry.width > 64 || es->geometry.height > 64)
720 return NULL;
721
722 output->cursor_surface = es;
723
724 return &output->cursor_plane;
725}
726
727static void
728drm_output_set_cursor(struct drm_output *output)
729{
730 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400731 struct drm_compositor *c =
732 (struct drm_compositor *) output->base.compositor;
733 EGLint handle, stride;
734 struct gbm_bo *bo;
735 uint32_t buf[64 * 64];
736 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400737 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500738
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400739 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400740 if (es == NULL) {
741 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
742 return;
743 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500744
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400745 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
746 pixman_region32_fini(&output->cursor_plane.damage);
747 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400748 output->current_cursor ^= 1;
749 bo = output->cursor_bo[output->current_cursor];
750 memset(buf, 0, sizeof buf);
751 stride = wl_shm_buffer_get_stride(es->buffer);
752 s = wl_shm_buffer_get_data(es->buffer);
753 for (i = 0; i < es->geometry.height; i++)
754 memcpy(buf + i * 64, s + i * stride,
755 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500756
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400757 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300758 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400759
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400760 handle = gbm_bo_get_handle(bo).s32;
761 if (drmModeSetCursor(c->drm.fd,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400762 output->crtc_id, handle, 64, 64))
Pekka Paalanenae29da22012-08-06 14:57:05 +0300763 weston_log("failed to set cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400764 }
765
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400766 x = es->geometry.x - output->base.x;
767 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400768 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
769 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y))
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400770 weston_log("failed to move cursor: %m\n");
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400771 output->cursor_plane.x = x;
772 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400773 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500774}
775
Jesse Barnes58ef3792012-02-23 09:45:49 -0500776static void
777drm_assign_planes(struct weston_output *output)
778{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400779 struct drm_compositor *c =
780 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400781 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500782 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400783 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500784
785 /*
786 * Find a surface for each sprite in the output using some heuristics:
787 * 1) size
788 * 2) frequency of update
789 * 3) opacity (though some hw might support alpha blending)
790 * 4) clipping (this can be fixed with color keys)
791 *
792 * The idea is to save on blitting since this should save power.
793 * If we can get a large video surface on the sprite for example,
794 * the main display surface may not need to update at all, and
795 * the client buffer can be used directly for the sprite surface
796 * as we do for flipping full screen surfaces.
797 */
798 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400799 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400800 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 pixman_region32_init(&surface_overlap);
802 pixman_region32_intersect(&surface_overlap, &overlap,
803 &es->transform.boundingbox);
804
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400805 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400806 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400807 next_plane = primary;
808 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400809 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 if (next_plane == NULL)
811 next_plane = drm_output_prepare_scanout_surface(output, es);
812 if (next_plane == NULL)
813 next_plane = drm_output_prepare_overlay_surface(output, es);
814 if (next_plane == NULL)
815 next_plane = primary;
816 weston_surface_move_to_plane(es, next_plane);
817 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818 pixman_region32_union(&overlap, &overlap,
819 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400820
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821 pixman_region32_fini(&surface_overlap);
822 }
823 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824}
825
Matt Roper361d2ad2011-08-29 13:52:23 -0700826static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500827drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700828{
829 struct drm_output *output = (struct drm_output *) output_base;
830 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200831 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700832 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700833
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200834 if (output->backlight)
835 backlight_destroy(output->backlight);
836
Matt Roper361d2ad2011-08-29 13:52:23 -0700837 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400838 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700839
840 /* Restore original CRTC state */
841 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200842 origcrtc->x, origcrtc->y,
843 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700844 drmModeFreeCrtc(origcrtc);
845
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200846 c->crtc_allocator &= ~(1 << output->crtc_id);
847 c->connector_allocator &= ~(1 << output->connector_id);
848
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400849 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400850 gbm_surface_destroy(output->surface);
851
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400852 weston_plane_release(&output->fb_plane);
853 weston_plane_release(&output->cursor_plane);
854
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500855 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200856 wl_list_remove(&output->base.link);
857
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400858 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700859 free(output);
860}
861
Alex Wub7b8bda2012-04-17 17:20:48 +0800862static struct drm_mode *
863choose_mode (struct drm_output *output, struct weston_mode *target_mode)
864{
865 struct drm_mode *tmp_mode = NULL, *mode;
866
867 if (output->base.current->width == target_mode->width &&
868 output->base.current->height == target_mode->height &&
869 (output->base.current->refresh == target_mode->refresh ||
870 target_mode->refresh == 0))
871 return (struct drm_mode *)output->base.current;
872
873 wl_list_for_each(mode, &output->base.mode_list, base.link) {
874 if (mode->mode_info.hdisplay == target_mode->width &&
875 mode->mode_info.vdisplay == target_mode->height) {
876 if (mode->mode_info.vrefresh == target_mode->refresh ||
877 target_mode->refresh == 0) {
878 return mode;
879 } else if (!tmp_mode)
880 tmp_mode = mode;
881 }
882 }
883
884 return tmp_mode;
885}
886
887static int
888drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
889{
890 struct drm_output *output;
891 struct drm_mode *drm_mode;
892 int ret;
893 struct drm_compositor *ec;
894 struct gbm_surface *surface;
895 EGLSurface egl_surface;
896
897 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200898 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800899 return -1;
900 }
901
902 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200903 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800904 return -1;
905 }
906
907 ec = (struct drm_compositor *)output_base->compositor;
908 output = (struct drm_output *)output_base;
909 drm_mode = choose_mode (output, mode);
910
911 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200912 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800913 return -1;
914 } else if (&drm_mode->base == output->base.current) {
915 return 0;
916 } else if (drm_mode->base.width == output->base.current->width &&
917 drm_mode->base.height == output->base.current->height) {
918 /* only change refresh value */
919 ret = drmModeSetCrtc(ec->drm.fd,
920 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300921 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800922 &output->connector_id, 1, &drm_mode->mode_info);
923
924 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200925 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800926 drm_mode->base.width,
927 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400928 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800929 ret = -1;
930 } else {
931 output->base.current->flags = 0;
932 output->base.current = &drm_mode->base;
933 drm_mode->base.flags =
934 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
935 ret = 0;
936 }
937
938 return ret;
939 }
940
941 drm_mode->base.flags =
942 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
943
944 surface = gbm_surface_create(ec->gbm,
945 drm_mode->base.width,
946 drm_mode->base.height,
947 GBM_FORMAT_XRGB8888,
948 GBM_BO_USE_SCANOUT |
949 GBM_BO_USE_RENDERING);
950 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200951 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800952 return -1;
953 }
954
955 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400956 eglCreateWindowSurface(ec->base.egl_display,
957 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800958 surface, NULL);
959
960 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200961 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800962 goto err;
963 }
964
965 ret = drmModeSetCrtc(ec->drm.fd,
966 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300967 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800968 &output->connector_id, 1, &drm_mode->mode_info);
969 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200970 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800971 goto err;
972 }
973
974 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300975 if (output->current) {
976 if (output->current->is_client_buffer)
977 gbm_bo_destroy(output->current->bo);
978 else
979 gbm_surface_release_buffer(output->surface,
980 output->current->bo);
981 }
982 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800983
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300984 if (output->next) {
985 if (output->next->is_client_buffer)
986 gbm_bo_destroy(output->next->bo);
987 else
988 gbm_surface_release_buffer(output->surface,
989 output->next->bo);
990 }
991 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800992
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400993 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800994 gbm_surface_destroy(output->surface);
995 output->egl_surface = egl_surface;
996 output->surface = surface;
997
998 /*update output*/
999 output->base.current = &drm_mode->base;
1000 output->base.dirty = 1;
1001 weston_output_move(&output->base, output->base.x, output->base.y);
1002 return 0;
1003
1004err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001005 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001006 gbm_surface_destroy(surface);
1007 return -1;
1008}
1009
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001010static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001011on_drm_input(int fd, uint32_t mask, void *data)
1012{
1013 drmEventContext evctx;
1014
1015 memset(&evctx, 0, sizeof evctx);
1016 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1017 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001018 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001019 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001020
1021 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001022}
1023
1024static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001025init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001026{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001027 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001028 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001029 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001030 static const EGLint context_attribs[] = {
1031 EGL_CONTEXT_CLIENT_VERSION, 2,
1032 EGL_NONE
1033 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001034
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001035 static const EGLint config_attribs[] = {
1036 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1037 EGL_RED_SIZE, 1,
1038 EGL_GREEN_SIZE, 1,
1039 EGL_BLUE_SIZE, 1,
1040 EGL_ALPHA_SIZE, 0,
1041 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1042 EGL_NONE
1043 };
1044
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001045 sysnum = udev_device_get_sysnum(device);
1046 if (sysnum)
1047 ec->drm.id = atoi(sysnum);
1048 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001049 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001050 return -1;
1051 }
1052
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001053 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001054 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001055 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001056 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001057 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001058 udev_device_get_devnode(device));
1059 return -1;
1060 }
1061
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001062 weston_log("using %s\n", filename);
1063
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001064 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001065 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001066 ec->base.egl_display = eglGetDisplay(ec->gbm);
1067 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001068 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001069 return -1;
1070 }
1071
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001072 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001073 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001074 return -1;
1075 }
1076
Darxus55973f22010-11-22 21:24:39 -05001077 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001078 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001079 return -1;
1080 }
1081
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001082 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1083 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001084 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001085 return -1;
1086 }
1087
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001088 ec->base.egl_context =
1089 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1090 EGL_NO_CONTEXT, context_attribs);
1091 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001092 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001093 return -1;
1094 }
1095
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001096 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1097 GBM_FORMAT_XRGB8888,
1098 GBM_BO_USE_RENDERING);
1099 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001100 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001101 return -1;
1102 }
1103
1104 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001105 eglCreateWindowSurface(ec->base.egl_display,
1106 ec->base.egl_config,
1107 ec->dummy_surface,
1108 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001109 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001110 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001111 return -1;
1112 }
1113
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001114 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1115 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001116 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001117 return -1;
1118 }
1119
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001120 return 0;
1121}
1122
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001123static int
1124drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1125{
1126 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001127 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001128
1129 mode = malloc(sizeof *mode);
1130 if (mode == NULL)
1131 return -1;
1132
1133 mode->base.flags = 0;
1134 mode->base.width = info->hdisplay;
1135 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001136
1137 /* Calculate higher precision (mHz) refresh rate */
1138 refresh = (info->clock * 1000000LL / info->htotal +
1139 info->vtotal / 2) / info->vtotal;
1140
1141 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1142 refresh *= 2;
1143 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1144 refresh /= 2;
1145 if (info->vscan > 1)
1146 refresh /= info->vscan;
1147
1148 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001149 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001150
1151 if (info->type & DRM_MODE_TYPE_PREFERRED)
1152 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1153
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001154 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1155
1156 return 0;
1157}
1158
1159static int
1160drm_subpixel_to_wayland(int drm_value)
1161{
1162 switch (drm_value) {
1163 default:
1164 case DRM_MODE_SUBPIXEL_UNKNOWN:
1165 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1166 case DRM_MODE_SUBPIXEL_NONE:
1167 return WL_OUTPUT_SUBPIXEL_NONE;
1168 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1169 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1170 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1171 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1172 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1173 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1174 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1175 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1176 }
1177}
1178
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001179static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001180sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001181{
1182 struct drm_sprite *sprite =
1183 container_of(listener, struct drm_sprite,
1184 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001185 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001186
1187 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001188 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1189 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001190}
1191
1192static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001193sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001194{
1195 struct drm_sprite *sprite =
1196 container_of(listener, struct drm_sprite,
1197 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001198 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001199
1200 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001201 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1202 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001203}
1204
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001205/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001206static uint32_t
1207drm_get_backlight(struct drm_output *output)
1208{
1209 long brightness, max_brightness, norm;
1210
1211 brightness = backlight_get_brightness(output->backlight);
1212 max_brightness = backlight_get_max_brightness(output->backlight);
1213
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001214 /* convert it on a scale of 0 to 255 */
1215 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001216
1217 return (uint32_t) norm;
1218}
1219
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001220/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001221static void
1222drm_set_backlight(struct weston_output *output_base, uint32_t value)
1223{
1224 struct drm_output *output = (struct drm_output *) output_base;
1225 long max_brightness, new_brightness;
1226
1227 if (!output->backlight)
1228 return;
1229
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001230 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001231 return;
1232
1233 max_brightness = backlight_get_max_brightness(output->backlight);
1234
1235 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001236 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001237
1238 backlight_set_brightness(output->backlight, new_brightness);
1239}
1240
1241static drmModePropertyPtr
1242drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1243{
1244 drmModePropertyPtr props;
1245 int i;
1246
1247 for (i = 0; i < connector->count_props; i++) {
1248 props = drmModeGetProperty(fd, connector->props[i]);
1249 if (!props)
1250 continue;
1251
1252 if (!strcmp(props->name, name))
1253 return props;
1254
1255 drmModeFreeProperty(props);
1256 }
1257
1258 return NULL;
1259}
1260
1261static void
1262drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1263{
1264 struct drm_output *output = (struct drm_output *) output_base;
1265 struct weston_compositor *ec = output_base->compositor;
1266 struct drm_compositor *c = (struct drm_compositor *) ec;
1267 drmModeConnectorPtr connector;
1268 drmModePropertyPtr prop;
1269
1270 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1271 if (!connector)
1272 return;
1273
1274 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1275 if (!prop) {
1276 drmModeFreeConnector(connector);
1277 return;
1278 }
1279
1280 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1281 prop->prop_id, level);
1282 drmModeFreeProperty(prop);
1283 drmModeFreeConnector(connector);
1284}
1285
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001286static const char *connector_type_names[] = {
1287 "None",
1288 "VGA",
1289 "DVI",
1290 "DVI",
1291 "DVI",
1292 "Composite",
1293 "TV",
1294 "LVDS",
1295 "CTV",
1296 "DIN",
1297 "DP",
1298 "HDMI",
1299 "HDMI",
1300 "TV",
1301 "eDP",
1302};
1303
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001304static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001305find_crtc_for_connector(struct drm_compositor *ec,
1306 drmModeRes *resources, drmModeConnector *connector)
1307{
1308 drmModeEncoder *encoder;
1309 uint32_t possible_crtcs;
1310 int i, j;
1311
1312 for (j = 0; j < connector->count_encoders; j++) {
1313 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1314 if (encoder == NULL) {
1315 weston_log("Failed to get encoder.\n");
1316 return -1;
1317 }
1318 possible_crtcs = encoder->possible_crtcs;
1319 drmModeFreeEncoder(encoder);
1320
1321 for (i = 0; i < resources->count_crtcs; i++) {
1322 if (possible_crtcs & (1 << i) &&
1323 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1324 return i;
1325 }
1326 }
1327
1328 return -1;
1329}
1330
1331static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001332create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001333 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001334 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001335 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001336{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001337 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001338 struct drm_mode *drm_mode, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001339 struct weston_mode *m, *preferred, *current, *configured;
1340 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001341 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001342 drmModeModeInfo crtc_mode;
1343 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001344 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001345 char name[32];
1346 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001347
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001348 i = find_crtc_for_connector(ec, resources, connector);
1349 if (i < 0) {
1350 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001351 return -1;
1352 }
1353
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001354 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001355 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001356 return -1;
1357
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001358 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001359 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1360 output->base.make = "unknown";
1361 output->base.model = "unknown";
1362 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001363
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001364 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1365 type_name = connector_type_names[connector->connector_type];
1366 else
1367 type_name = "UNKNOWN";
1368 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1369 output->name = strdup(name);
1370
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001371 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001372 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001373 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001374 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001375 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001376
Matt Roper361d2ad2011-08-29 13:52:23 -07001377 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1378
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001379 /* Get the current mode on the crtc that's currently driving
1380 * this connector. */
1381 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001382 memset(&crtc_mode, 0, sizeof crtc_mode);
1383 if (encoder != NULL) {
1384 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1385 drmModeFreeEncoder(encoder);
1386 if (crtc == NULL)
1387 goto err_free;
1388 if (crtc->mode_valid)
1389 crtc_mode = crtc->mode;
1390 drmModeFreeCrtc(crtc);
1391 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001392
David Herrmann0f0d54e2011-12-08 17:05:45 +01001393 for (i = 0; i < connector->count_modes; i++) {
1394 ret = drm_output_add_mode(output, &connector->modes[i]);
1395 if (ret)
1396 goto err_free;
1397 }
1398
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001399 preferred = NULL;
1400 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001401 configured = NULL;
1402
1403 wl_list_for_each(temp, &configured_output_list, link) {
1404 if (strcmp(temp->name, output->name) == 0) {
1405 weston_log("%s mode \"%s\" in config\n",
1406 temp->name, temp->mode);
1407 o = temp;
1408 break;
1409 }
1410 }
1411
1412 if (o && strcmp("off", o->mode) == 0) {
1413 weston_log("Disabling output %s\n", o->name);
1414
1415 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1416 0, 0, 0, 0, 0, NULL);
1417 goto err_free;
1418 }
1419
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001421 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001422 o->height == drm_mode->base.height &&
1423 o->config == OUTPUT_CONFIG_MODE)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001424 configured = &drm_mode->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001425 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001426 current = &drm_mode->base;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001427 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1428 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001429 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001430
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001431 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
1432 ret = drm_output_add_mode(output, &o->crtc_mode);
1433 if (ret)
1434 goto err_free;
1435 configured = container_of(output->base.mode_list.prev,
1436 struct weston_mode, link);
1437 current = configured;
1438 }
1439
Wang Quanxianacb805a2012-07-30 18:09:46 -04001440 if (current == NULL && crtc_mode.clock != 0) {
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001441 ret = drm_output_add_mode(output, &crtc_mode);
1442 if (ret)
1443 goto err_free;
1444 current = container_of(output->base.mode_list.prev,
1445 struct weston_mode, link);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001446 }
1447
Scott Moreau8ab5d452012-07-30 19:51:08 -06001448 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1449 configured = current;
1450
Wang Quanxianacb805a2012-07-30 18:09:46 -04001451 if (option_current_mode && current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001452 output->base.current = current;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001453 else if (configured)
1454 output->base.current = configured;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001455 else if (preferred)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001456 output->base.current = preferred;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001457 else if (current)
1458 output->base.current = current;
1459
1460 if (output->base.current == NULL) {
1461 weston_log("no available modes for %s\n", output->name);
1462 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001463 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001464
Wang Quanxianacb805a2012-07-30 18:09:46 -04001465 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1466
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001467 output->surface = gbm_surface_create(ec->gbm,
1468 output->base.current->width,
1469 output->base.current->height,
1470 GBM_FORMAT_XRGB8888,
1471 GBM_BO_USE_SCANOUT |
1472 GBM_BO_USE_RENDERING);
1473 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001474 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001475 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001476 }
1477
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001478 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001479 eglCreateWindowSurface(ec->base.egl_display,
1480 ec->base.egl_config,
1481 output->surface,
1482 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001483 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001484 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001485 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001486 }
1487
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001488 output->cursor_bo[0] =
1489 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1490 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1491 output->cursor_bo[1] =
1492 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1493 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1494
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001495 output->backlight = backlight_init(drm_device,
1496 connector->connector_type);
1497 if (output->backlight) {
1498 output->base.set_backlight = drm_set_backlight;
1499 output->base.backlight_current = drm_get_backlight(output);
1500 }
1501
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001502 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001503 connector->mmWidth, connector->mmHeight,
1504 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001505
1506 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1507
Alex Wubd3354b2012-04-17 17:20:49 +08001508 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001509 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001510 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001511 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001512 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001513 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001514
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001515 weston_plane_init(&output->cursor_plane, 0, 0);
1516 weston_plane_init(&output->fb_plane, 0, 0);
1517
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001518 weston_log("Output %s, (connector %d, crtc %d)\n",
1519 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001520 wl_list_for_each(m, &output->base.mode_list, link)
1521 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1522 m->width, m->height, m->refresh / 1000.0,
1523 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1524 ", preferred" : "",
1525 m->flags & WL_OUTPUT_MODE_CURRENT ?
1526 ", current" : "",
1527 connector->count_modes == 0 ?
1528 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001529
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001530 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001531
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001532err_surface:
1533 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001534err_free:
1535 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1536 base.link) {
1537 wl_list_remove(&drm_mode->base.link);
1538 free(drm_mode);
1539 }
1540
1541 drmModeFreeCrtc(output->original_crtc);
1542 ec->crtc_allocator &= ~(1 << output->crtc_id);
1543 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001544 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001545 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001546
David Herrmann0f0d54e2011-12-08 17:05:45 +01001547 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001548}
1549
Jesse Barnes58ef3792012-02-23 09:45:49 -05001550static void
1551create_sprites(struct drm_compositor *ec)
1552{
1553 struct drm_sprite *sprite;
1554 drmModePlaneRes *plane_res;
1555 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001556 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001557
1558 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1559 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001560 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001561 strerror(errno));
1562 return;
1563 }
1564
1565 for (i = 0; i < plane_res->count_planes; i++) {
1566 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1567 if (!plane)
1568 continue;
1569
1570 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1571 plane->count_formats));
1572 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001573 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001574 __func__);
1575 free(plane);
1576 continue;
1577 }
1578
1579 memset(sprite, 0, sizeof *sprite);
1580
1581 sprite->possible_crtcs = plane->possible_crtcs;
1582 sprite->plane_id = plane->plane_id;
1583 sprite->surface = NULL;
1584 sprite->pending_surface = NULL;
1585 sprite->fb_id = 0;
1586 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001587 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1588 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001589 sprite_handle_pending_buffer_destroy;
1590 sprite->compositor = ec;
1591 sprite->count_formats = plane->count_formats;
1592 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001593 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001594 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001595 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001596
1597 wl_list_insert(&ec->sprite_list, &sprite->link);
1598 }
1599
1600 free(plane_res->planes);
1601 free(plane_res);
1602}
1603
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001604static void
1605destroy_sprites(struct drm_compositor *compositor)
1606{
1607 struct drm_sprite *sprite, *next;
1608 struct drm_output *output;
1609
1610 output = container_of(compositor->base.output_list.next,
1611 struct drm_output, base.link);
1612
1613 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1614 drmModeSetPlane(compositor->drm.fd,
1615 sprite->plane_id,
1616 output->crtc_id, 0, 0,
1617 0, 0, 0, 0, 0, 0, 0, 0);
1618 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001619 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001620 free(sprite);
1621 }
1622}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001623
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001624static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001625create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001626 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001627{
1628 drmModeConnector *connector;
1629 drmModeRes *resources;
1630 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001631 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001632
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001633 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001634 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001635 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001636 return -1;
1637 }
1638
Jesse Barnes58ef3792012-02-23 09:45:49 -05001639 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001640 if (!ec->crtcs) {
1641 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001642 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001643 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001644
1645 ec->num_crtcs = resources->count_crtcs;
1646 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1647
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001648 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001649 connector = drmModeGetConnector(ec->drm.fd,
1650 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001651 if (connector == NULL)
1652 continue;
1653
1654 if (connector->connection == DRM_MODE_CONNECTED &&
1655 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001656 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001657 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001658 connector, x, y,
1659 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001660 drmModeFreeConnector(connector);
1661 continue;
1662 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001663
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001664 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001665 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001666 link)->current->width;
1667 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001668
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001669 drmModeFreeConnector(connector);
1670 }
1671
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001672 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001673 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001674 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001675 return -1;
1676 }
1677
1678 drmModeFreeResources(resources);
1679
1680 return 0;
1681}
1682
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001683static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001684update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001685{
1686 drmModeConnector *connector;
1687 drmModeRes *resources;
1688 struct drm_output *output, *next;
1689 int x = 0, y = 0;
1690 int x_offset = 0, y_offset = 0;
1691 uint32_t connected = 0, disconnects = 0;
1692 int i;
1693
1694 resources = drmModeGetResources(ec->drm.fd);
1695 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001696 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001697 return;
1698 }
1699
1700 /* collect new connects */
1701 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001702 int connector_id = resources->connectors[i];
1703
1704 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001705 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001706 continue;
1707
David Herrmann7551cff2011-12-08 17:05:43 +01001708 if (connector->connection != DRM_MODE_CONNECTED) {
1709 drmModeFreeConnector(connector);
1710 continue;
1711 }
1712
Benjamin Franzke117483d2011-08-30 11:38:26 +02001713 connected |= (1 << connector_id);
1714
1715 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001716 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001717 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001718 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001719
1720 /* XXX: not yet needed, we die with 0 outputs */
1721 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001722 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001723 else
1724 x = 0;
1725 y = 0;
1726 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001727 connector, x, y,
1728 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001729 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001730
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001731 }
1732 drmModeFreeConnector(connector);
1733 }
1734 drmModeFreeResources(resources);
1735
1736 disconnects = ec->connector_allocator & ~connected;
1737 if (disconnects) {
1738 wl_list_for_each_safe(output, next, &ec->base.output_list,
1739 base.link) {
1740 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001741 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001742 output->base.x - x_offset,
1743 output->base.y - y_offset);
1744 }
1745
1746 if (disconnects & (1 << output->connector_id)) {
1747 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001748 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001749 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001750 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001751 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001752 }
1753 }
1754 }
1755
1756 /* FIXME: handle zero outputs, without terminating */
1757 if (ec->connector_allocator == 0)
1758 wl_display_terminate(ec->base.wl_display);
1759}
1760
1761static int
David Herrmannd7488c22012-03-11 20:05:21 +01001762udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001763{
David Herrmannd7488c22012-03-11 20:05:21 +01001764 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001765 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001766
1767 sysnum = udev_device_get_sysnum(device);
1768 if (!sysnum || atoi(sysnum) != ec->drm.id)
1769 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001770
David Herrmann6ac52db2012-03-11 20:05:22 +01001771 val = udev_device_get_property_value(device, "HOTPLUG");
1772 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001773 return 0;
1774
David Herrmann6ac52db2012-03-11 20:05:22 +01001775 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001776}
1777
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001778static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001779udev_drm_event(int fd, uint32_t mask, void *data)
1780{
1781 struct drm_compositor *ec = data;
1782 struct udev_device *event;
1783
1784 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001785
David Herrmannd7488c22012-03-11 20:05:21 +01001786 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001787 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001788
1789 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001790
1791 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001792}
1793
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001794static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001795drm_restore(struct weston_compositor *ec)
1796{
1797 struct drm_compositor *d = (struct drm_compositor *) ec;
1798
1799 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1800 weston_log("failed to drop master: %m\n");
1801 tty_reset(d->tty);
1802}
1803
Pekka Paalanen33156972012-08-03 13:30:30 -04001804static const char default_seat[] = "seat0";
1805
1806static void
1807device_added(struct udev_device *udev_device, struct drm_seat *master)
1808{
1809 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001810 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001811 const char *devnode;
1812 const char *device_seat;
1813 int fd;
1814
1815 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1816 if (!device_seat)
1817 device_seat = default_seat;
1818
1819 if (strcmp(device_seat, master->seat_id))
1820 return;
1821
1822 c = master->base.compositor;
1823 devnode = udev_device_get_devnode(udev_device);
1824
1825 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001826 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001827 * read. mtdev_get() also expects this. */
1828 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1829 if (fd < 0) {
1830 weston_log("opening input device '%s' failed.\n", devnode);
1831 return;
1832 }
1833
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001834 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001835 if (!device) {
1836 close(fd);
1837 weston_log("not using input device '%s'.\n", devnode);
1838 return;
1839 }
1840
1841 wl_list_insert(master->devices_list.prev, &device->link);
1842}
1843
1844static void
1845evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1846{
1847 struct drm_seat *seat = (struct drm_seat *) seat_base;
1848 struct udev_enumerate *e;
1849 struct udev_list_entry *entry;
1850 struct udev_device *device;
1851 const char *path, *sysname;
1852
1853 e = udev_enumerate_new(udev);
1854 udev_enumerate_add_match_subsystem(e, "input");
1855 udev_enumerate_scan_devices(e);
1856 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1857 path = udev_list_entry_get_name(entry);
1858 device = udev_device_new_from_syspath(udev, path);
1859
1860 sysname = udev_device_get_sysname(device);
1861 if (strncmp("event", sysname, 5) != 0) {
1862 udev_device_unref(device);
1863 continue;
1864 }
1865
1866 device_added(device, seat);
1867
1868 udev_device_unref(device);
1869 }
1870 udev_enumerate_unref(e);
1871
1872 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1873
1874 if (wl_list_empty(&seat->devices_list)) {
1875 weston_log(
1876 "warning: no input devices on entering Weston. "
1877 "Possible causes:\n"
1878 "\t- no permissions to read /dev/input/event*\n"
1879 "\t- seats misconfigured "
1880 "(Weston backend option 'seat', "
1881 "udev device property ID_SEAT)\n");
1882 }
1883}
1884
1885static int
1886evdev_udev_handler(int fd, uint32_t mask, void *data)
1887{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001888 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001889 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001890 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001891 const char *action;
1892 const char *devnode;
1893
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001894 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001895 if (!udev_device)
1896 return 1;
1897
1898 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001899 if (!action)
1900 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001901
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001902 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1903 goto out;
1904
1905 if (!strcmp(action, "add")) {
1906 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001907 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001908 else if (!strcmp(action, "remove")) {
1909 devnode = udev_device_get_devnode(udev_device);
1910 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1911 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001912 weston_log("input device %s, %s removed\n",
1913 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001914 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001915 break;
1916 }
1917 }
1918
1919out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001920 udev_device_unref(udev_device);
1921
1922 return 0;
1923}
1924
1925static int
1926evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1927{
1928 struct drm_seat *master = (struct drm_seat *) seat_base;
1929 struct wl_event_loop *loop;
1930 struct weston_compositor *c = master->base.compositor;
1931 int fd;
1932
1933 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1934 if (!master->udev_monitor) {
1935 weston_log("udev: failed to create the udev monitor\n");
1936 return 0;
1937 }
1938
1939 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1940 "input", NULL);
1941
1942 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1943 weston_log("udev: failed to bind the udev monitor\n");
1944 udev_monitor_unref(master->udev_monitor);
1945 return 0;
1946 }
1947
1948 loop = wl_display_get_event_loop(c->wl_display);
1949 fd = udev_monitor_get_fd(master->udev_monitor);
1950 master->udev_monitor_source =
1951 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1952 evdev_udev_handler, master);
1953 if (!master->udev_monitor_source) {
1954 udev_monitor_unref(master->udev_monitor);
1955 return 0;
1956 }
1957
1958 return 1;
1959}
1960
1961static void
1962evdev_disable_udev_monitor(struct weston_seat *seat_base)
1963{
1964 struct drm_seat *seat = (struct drm_seat *) seat_base;
1965
1966 if (!seat->udev_monitor)
1967 return;
1968
1969 udev_monitor_unref(seat->udev_monitor);
1970 seat->udev_monitor = NULL;
1971 wl_event_source_remove(seat->udev_monitor_source);
1972 seat->udev_monitor_source = NULL;
1973}
1974
1975static void
1976drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1977{
1978 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001979 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001980
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001981 wl_list_for_each(device, &seat->devices_list, link)
1982 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001983}
1984
1985static void
1986evdev_input_create(struct weston_compositor *c, struct udev *udev,
1987 const char *seat_id)
1988{
1989 struct drm_seat *seat;
1990
1991 seat = malloc(sizeof *seat);
1992 if (seat == NULL)
1993 return;
1994
1995 memset(seat, 0, sizeof *seat);
1996 weston_seat_init(&seat->base, c);
1997 seat->base.led_update = drm_led_update;
1998
1999 wl_list_init(&seat->devices_list);
2000 seat->seat_id = strdup(seat_id);
2001 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2002 free(seat->seat_id);
2003 free(seat);
2004 return;
2005 }
2006
2007 evdev_add_devices(udev, &seat->base);
2008
2009 c->seat = &seat->base;
2010}
2011
2012static void
2013evdev_remove_devices(struct weston_seat *seat_base)
2014{
2015 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002016 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002017
2018 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002019 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002020
Pekka Paalanend8583512012-08-03 14:39:11 +03002021 if (seat->base.seat.keyboard)
2022 notify_keyboard_focus_out(&seat->base.seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002023}
2024
2025static void
2026evdev_input_destroy(struct weston_seat *seat_base)
2027{
2028 struct drm_seat *seat = (struct drm_seat *) seat_base;
2029
2030 evdev_remove_devices(seat_base);
2031 evdev_disable_udev_monitor(&seat->base);
2032
2033 weston_seat_release(seat_base);
2034 free(seat->seat_id);
2035 free(seat);
2036}
2037
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002038static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002039drm_free_configured_output(struct drm_configured_output *output)
2040{
2041 free(output->name);
2042 free(output->mode);
2043 free(output);
2044}
2045
2046static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002047drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002048{
2049 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002050 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002051 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002052
Daniel Stone37816df2012-05-16 18:45:18 +01002053 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2054 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002055 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002056 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002057
2058 wl_event_source_remove(d->udev_drm_source);
2059 wl_event_source_remove(d->drm_source);
2060
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002061 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002062
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002063 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002064 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002065 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002066 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002067 eglReleaseThread();
2068
Matt Roper361d2ad2011-08-29 13:52:23 -07002069 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002070 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002071 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002072 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002073 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002074
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002075 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002076}
2077
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002078static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002079drm_compositor_set_modes(struct drm_compositor *compositor)
2080{
2081 struct drm_output *output;
2082 struct drm_mode *drm_mode;
2083 int ret;
2084
2085 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2086 drm_mode = (struct drm_mode *) output->base.current;
2087 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002088 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002089 &output->connector_id, 1,
2090 &drm_mode->mode_info);
2091 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002092 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002093 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002094 drm_mode->base.width, drm_mode->base.height,
2095 output->base.x, output->base.y);
2096 }
2097 }
2098}
2099
2100static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002101vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002102{
2103 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002104 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002105 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002106 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002107
2108 switch (event) {
2109 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002110 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002111 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002112 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002113 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002114 wl_display_terminate(compositor->wl_display);
2115 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002116 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002117 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002118 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002119 wl_list_for_each(seat, &compositor->seat_list, link) {
2120 evdev_add_devices(ec->udev, seat);
2121 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002122 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002123 break;
2124 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002125 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002126 wl_list_for_each(seat, &compositor->seat_list, link) {
2127 evdev_disable_udev_monitor(seat);
2128 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002129 }
2130
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002131 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002132 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002133 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002134
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002135 /* If we have a repaint scheduled (either from a
2136 * pending pageflip or the idle handler), make sure we
2137 * cancel that so we don't try to pageflip when we're
2138 * vt switched away. The SLEEPING state will prevent
2139 * further attemps at repainting. When we switch
2140 * back, we schedule a repaint, which will process
2141 * pending frame callbacks. */
2142
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002143 wl_list_for_each(output, &ec->base.output_list, base.link) {
2144 output->base.repaint_needed = 0;
2145 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002146 }
2147
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002148 output = container_of(ec->base.output_list.next,
2149 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002150
2151 wl_list_for_each(sprite, &ec->sprite_list, link)
2152 drmModeSetPlane(ec->drm.fd,
2153 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002154 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002155 0, 0, 0, 0, 0, 0, 0, 0);
2156
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002157 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002158 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002159
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002160 break;
2161 };
2162}
2163
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002164static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002165switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002166{
2167 struct drm_compositor *ec = data;
2168
Daniel Stone325fc2d2012-05-30 16:31:58 +01002169 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002170}
2171
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002172static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002173drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002174 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002175 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002176{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002177 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002178 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002179 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002180 struct udev_device *device, *drm_device;
2181 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002182 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002183 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002184 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002185
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002186 weston_log("initializing drm backend\n");
2187
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002188 ec = malloc(sizeof *ec);
2189 if (ec == NULL)
2190 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002191 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002192
2193 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002194 config_file) < 0) {
2195 weston_log("weston_compositor_init failed\n");
2196 goto err_base;
2197 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002198
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002199 ec->udev = udev_new();
2200 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002201 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002202 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002203 }
2204
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002205 ec->base.wl_display = display;
2206 ec->tty = tty_create(&ec->base, vt_func, tty);
2207 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002208 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002209 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002210 }
2211
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002212 e = udev_enumerate_new(ec->udev);
2213 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002214 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002215
Benjamin Franzke117483d2011-08-30 11:38:26 +02002216 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002217 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002218 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002219 path = udev_list_entry_get_name(entry);
2220 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002221 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002222 udev_device_get_property_value(device, "ID_SEAT");
2223 if (!device_seat)
2224 device_seat = default_seat;
2225 if (strcmp(device_seat, seat) == 0) {
2226 drm_device = device;
2227 break;
2228 }
2229 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002230 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002231
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002232 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002233 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002234 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002235 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002237 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002238 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002239 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002240 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002241
2242 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002243 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002244
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002245 ec->base.focus = 1;
2246
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002247 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002248
Daniel Stone725c2c32012-06-22 14:04:36 +01002249 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002250 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002251
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002252 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002253 weston_compositor_add_key_binding(&ec->base, key,
2254 MODIFIER_CTRL | MODIFIER_ALT,
2255 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002256
Jesse Barnes58ef3792012-02-23 09:45:49 -05002257 wl_list_init(&ec->sprite_list);
2258 create_sprites(ec);
2259
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002260 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002261 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002262 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002263 }
2264
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002265 path = NULL;
2266
Tiago Vignattice03ec32011-12-19 01:14:03 +02002267 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002268
2269 loop = wl_display_get_event_loop(ec->base.wl_display);
2270 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002271 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002272 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002273
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002274 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2275 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002276 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002277 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002278 }
2279 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2280 "drm", NULL);
2281 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002282 wl_event_loop_add_fd(loop,
2283 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002284 WL_EVENT_READABLE, udev_drm_event, ec);
2285
2286 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002287 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002288 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002289 }
2290
Daniel Stonea96b93c2012-06-22 14:04:37 +01002291 udev_device_unref(drm_device);
2292 udev_enumerate_unref(e);
2293
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002294 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002295
2296err_udev_monitor:
2297 wl_event_source_remove(ec->udev_drm_source);
2298 udev_monitor_unref(ec->udev_monitor);
2299err_drm_source:
2300 wl_event_source_remove(ec->drm_source);
2301 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2302 evdev_input_destroy(weston_seat);
2303err_sprite:
2304 destroy_sprites(ec);
2305err_egl:
2306 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2307 EGL_NO_CONTEXT);
2308 eglTerminate(ec->base.egl_display);
2309 eglReleaseThread();
2310 gbm_device_destroy(ec->gbm);
2311err_udev_dev:
2312 udev_device_unref(drm_device);
2313err_udev_enum:
2314 udev_enumerate_unref(e);
2315 tty_destroy(ec->tty);
2316err_udev:
2317 udev_unref(ec->udev);
2318err_compositor:
2319 weston_compositor_shutdown(&ec->base);
2320err_base:
2321 free(ec);
2322 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002323}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002324
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002325static int
2326set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2327{
2328 mode->flags = 0;
2329
2330 if (strcmp(hsync, "+hsync") == 0)
2331 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2332 else if (strcmp(hsync, "-hsync") == 0)
2333 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2334 else
2335 return -1;
2336
2337 if (strcmp(vsync, "+vsync") == 0)
2338 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2339 else if (strcmp(vsync, "-vsync") == 0)
2340 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2341 else
2342 return -1;
2343
2344 return 0;
2345}
2346
2347static int
2348check_for_modeline(struct drm_configured_output *output)
2349{
2350 drmModeModeInfo mode;
2351 char hsync[16];
2352 char vsync[16];
2353 char mode_name[16];
2354 float fclock;
2355
2356 mode.type = DRM_MODE_TYPE_USERDEF;
2357 mode.hskew = 0;
2358 mode.vscan = 0;
2359 mode.vrefresh = 0;
2360
2361 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2362 &fclock, &mode.hdisplay,
2363 &mode.hsync_start,
2364 &mode.hsync_end, &mode.htotal,
2365 &mode.vdisplay,
2366 &mode.vsync_start,
2367 &mode.vsync_end, &mode.vtotal,
2368 hsync, vsync) == 11) {
2369 if (set_sync_flags(&mode, hsync, vsync))
2370 return -1;
2371
2372 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2373 strcpy(mode.name, mode_name);
2374
2375 mode.clock = fclock * 1000;
2376 } else
2377 return -1;
2378
2379 output->crtc_mode = mode;
2380
2381 return 0;
2382}
2383
Scott Moreau8ab5d452012-07-30 19:51:08 -06002384static void
2385output_section_done(void *data)
2386{
2387 struct drm_configured_output *output;
2388
2389 output = malloc(sizeof *output);
2390
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002391 if (!output || !output_name || !output_mode) {
2392 free(output_name);
2393 output_name = NULL;
2394 free(output_mode);
2395 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002396 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002397 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002398
2399 output->config = OUTPUT_CONFIG_INVALID;
2400 output->name = output_name;
2401 output->mode = output_mode;
2402
2403 if (strcmp(output_mode, "off") == 0)
2404 output->config = OUTPUT_CONFIG_OFF;
2405 else if (strcmp(output_mode, "preferred") == 0)
2406 output->config = OUTPUT_CONFIG_PREFERRED;
2407 else if (strcmp(output_mode, "current") == 0)
2408 output->config = OUTPUT_CONFIG_CURRENT;
2409 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2410 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002411 else if (check_for_modeline(output) == 0)
2412 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002413
2414 if (output->config != OUTPUT_CONFIG_INVALID)
2415 wl_list_insert(&configured_output_list, &output->link);
2416 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002417 weston_log("Invalid mode \"%s\" for output %s\n",
2418 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002419 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002420 }
2421}
2422
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002423WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002424backend_init(struct wl_display *display, int argc, char *argv[],
2425 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002426{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002427 int connector = 0, tty = 0;
2428 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002429
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002430 const struct weston_option drm_options[] = {
2431 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2432 { WESTON_OPTION_STRING, "seat", 0, &seat },
2433 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002434 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002435 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002436
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002437 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002438
Scott Moreau8ab5d452012-07-30 19:51:08 -06002439 wl_list_init(&configured_output_list);
2440
2441 const struct config_key drm_config_keys[] = {
2442 { "name", CONFIG_KEY_STRING, &output_name },
2443 { "mode", CONFIG_KEY_STRING, &output_mode },
2444 };
2445
2446 const struct config_section config_section[] = {
2447 { "output", drm_config_keys,
2448 ARRAY_LENGTH(drm_config_keys), output_section_done },
2449 };
2450
2451 parse_config_file(config_file, config_section,
2452 ARRAY_LENGTH(config_section), NULL);
2453
Daniel Stonec1be8e52012-06-01 11:14:02 -04002454 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2455 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002456}