blob: 657e70afef2abcff7afbfb6d672f758973c4627a [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
Rob Clark702ffae2012-08-09 14:18:27 -0500602 if (wl_buffer_is_shm(es->buffer))
603 return NULL;
604
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400606 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500607
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 wl_list_for_each(s, &c->sprite_list, link) {
609 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
610 continue;
611
612 if (!s->pending_fb_id) {
613 found = 1;
614 break;
615 }
616 }
617
618 /* No sprites available */
619 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400620 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400622 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
623 es->buffer, GBM_BO_USE_SCANOUT);
624 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400625 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400626
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 format = gbm_bo_get_format(bo);
628 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400629 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500630
631 gbm_bo_destroy(bo);
632
633 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400634 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635
636 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400637 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638
639 handles[0] = handle;
640 pitches[0] = stride;
641 offsets[0] = 0;
642
643 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
644 format, handles, pitches, offsets,
645 &fb_id, 0);
646 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200647 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500648 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400649 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650 }
651
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 s->pending_fb_id = fb_id;
653 s->pending_surface = es;
654 es->buffer->busy_count++;
655
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400656 box = pixman_region32_extents(&es->transform.boundingbox);
657 s->plane.x = box->x1;
658 s->plane.y = box->y1;
659
Jesse Barnes58ef3792012-02-23 09:45:49 -0500660 /*
661 * Calculate the source & dest rects properly based on actual
662 * postion (note the caller has called weston_surface_update_transform()
663 * for us already).
664 */
665 pixman_region32_init(&dest_rect);
666 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
667 &output_base->region);
668 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
669 box = pixman_region32_extents(&dest_rect);
670 s->dest_x = box->x1;
671 s->dest_y = box->y1;
672 s->dest_w = box->x2 - box->x1;
673 s->dest_h = box->y2 - box->y1;
674 pixman_region32_fini(&dest_rect);
675
676 pixman_region32_init(&src_rect);
677 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
678 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500679 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400680
681 weston_surface_from_global_fixed(es,
682 wl_fixed_from_int(box->x1),
683 wl_fixed_from_int(box->y1),
684 &sx1, &sy1);
685 weston_surface_from_global_fixed(es,
686 wl_fixed_from_int(box->x2),
687 wl_fixed_from_int(box->y2),
688 &sx2, &sy2);
689
690 if (sx1 < 0)
691 sx1 = 0;
692 if (sy1 < 0)
693 sy1 = 0;
694 if (sx2 > wl_fixed_from_int(es->geometry.width))
695 sx2 = wl_fixed_from_int(es->geometry.width);
696 if (sy2 > wl_fixed_from_int(es->geometry.height))
697 sy2 = wl_fixed_from_int(es->geometry.height);
698
699 s->src_x = sx1 << 8;
700 s->src_y = sy1 << 8;
701 s->src_w = (sx2 - sx1) << 8;
702 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500703 pixman_region32_fini(&src_rect);
704
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400705 wl_signal_add(&es->buffer->resource.destroy_signal,
706 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400707
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400708 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500709}
710
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400711static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400712drm_output_prepare_cursor_surface(struct weston_output *output_base,
713 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500714{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400715 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400716
717 if (output->cursor_surface)
718 return NULL;
719 if (es->output_mask != (1u << output_base->id))
720 return NULL;
721 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
722 es->geometry.width > 64 || es->geometry.height > 64)
723 return NULL;
724
725 output->cursor_surface = es;
726
727 return &output->cursor_plane;
728}
729
730static void
731drm_output_set_cursor(struct drm_output *output)
732{
733 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400734 struct drm_compositor *c =
735 (struct drm_compositor *) output->base.compositor;
736 EGLint handle, stride;
737 struct gbm_bo *bo;
738 uint32_t buf[64 * 64];
739 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400740 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500741
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400742 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400743 if (es == NULL) {
744 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
745 return;
746 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500747
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400748 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
749 pixman_region32_fini(&output->cursor_plane.damage);
750 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400751 output->current_cursor ^= 1;
752 bo = output->cursor_bo[output->current_cursor];
753 memset(buf, 0, sizeof buf);
754 stride = wl_shm_buffer_get_stride(es->buffer);
755 s = wl_shm_buffer_get_data(es->buffer);
756 for (i = 0; i < es->geometry.height; i++)
757 memcpy(buf + i * 64, s + i * stride,
758 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500759
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400760 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300761 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400762
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400763 handle = gbm_bo_get_handle(bo).s32;
764 if (drmModeSetCursor(c->drm.fd,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400765 output->crtc_id, handle, 64, 64))
Pekka Paalanenae29da22012-08-06 14:57:05 +0300766 weston_log("failed to set cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400767 }
768
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400769 x = es->geometry.x - output->base.x;
770 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400771 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
772 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y))
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400773 weston_log("failed to move cursor: %m\n");
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400774 output->cursor_plane.x = x;
775 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400776 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500777}
778
Jesse Barnes58ef3792012-02-23 09:45:49 -0500779static void
780drm_assign_planes(struct weston_output *output)
781{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400782 struct drm_compositor *c =
783 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400784 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400786 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500787
788 /*
789 * Find a surface for each sprite in the output using some heuristics:
790 * 1) size
791 * 2) frequency of update
792 * 3) opacity (though some hw might support alpha blending)
793 * 4) clipping (this can be fixed with color keys)
794 *
795 * The idea is to save on blitting since this should save power.
796 * If we can get a large video surface on the sprite for example,
797 * the main display surface may not need to update at all, and
798 * the client buffer can be used directly for the sprite surface
799 * as we do for flipping full screen surfaces.
800 */
801 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400802 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400803 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804 pixman_region32_init(&surface_overlap);
805 pixman_region32_intersect(&surface_overlap, &overlap,
806 &es->transform.boundingbox);
807
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400808 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400809 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 next_plane = primary;
811 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400812 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400813 if (next_plane == NULL)
814 next_plane = drm_output_prepare_scanout_surface(output, es);
815 if (next_plane == NULL)
816 next_plane = drm_output_prepare_overlay_surface(output, es);
817 if (next_plane == NULL)
818 next_plane = primary;
819 weston_surface_move_to_plane(es, next_plane);
820 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821 pixman_region32_union(&overlap, &overlap,
822 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400823
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824 pixman_region32_fini(&surface_overlap);
825 }
826 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500827}
828
Matt Roper361d2ad2011-08-29 13:52:23 -0700829static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500830drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700831{
832 struct drm_output *output = (struct drm_output *) output_base;
833 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200834 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700835 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700836
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200837 if (output->backlight)
838 backlight_destroy(output->backlight);
839
Matt Roper361d2ad2011-08-29 13:52:23 -0700840 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400841 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700842
843 /* Restore original CRTC state */
844 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200845 origcrtc->x, origcrtc->y,
846 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700847 drmModeFreeCrtc(origcrtc);
848
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200849 c->crtc_allocator &= ~(1 << output->crtc_id);
850 c->connector_allocator &= ~(1 << output->connector_id);
851
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400852 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400853 gbm_surface_destroy(output->surface);
854
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400855 weston_plane_release(&output->fb_plane);
856 weston_plane_release(&output->cursor_plane);
857
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500858 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200859 wl_list_remove(&output->base.link);
860
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400861 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700862 free(output);
863}
864
Alex Wub7b8bda2012-04-17 17:20:48 +0800865static struct drm_mode *
866choose_mode (struct drm_output *output, struct weston_mode *target_mode)
867{
868 struct drm_mode *tmp_mode = NULL, *mode;
869
870 if (output->base.current->width == target_mode->width &&
871 output->base.current->height == target_mode->height &&
872 (output->base.current->refresh == target_mode->refresh ||
873 target_mode->refresh == 0))
874 return (struct drm_mode *)output->base.current;
875
876 wl_list_for_each(mode, &output->base.mode_list, base.link) {
877 if (mode->mode_info.hdisplay == target_mode->width &&
878 mode->mode_info.vdisplay == target_mode->height) {
879 if (mode->mode_info.vrefresh == target_mode->refresh ||
880 target_mode->refresh == 0) {
881 return mode;
882 } else if (!tmp_mode)
883 tmp_mode = mode;
884 }
885 }
886
887 return tmp_mode;
888}
889
890static int
891drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
892{
893 struct drm_output *output;
894 struct drm_mode *drm_mode;
895 int ret;
896 struct drm_compositor *ec;
897 struct gbm_surface *surface;
898 EGLSurface egl_surface;
899
900 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200901 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800902 return -1;
903 }
904
905 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200906 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800907 return -1;
908 }
909
910 ec = (struct drm_compositor *)output_base->compositor;
911 output = (struct drm_output *)output_base;
912 drm_mode = choose_mode (output, mode);
913
914 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200915 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800916 return -1;
917 } else if (&drm_mode->base == output->base.current) {
918 return 0;
919 } else if (drm_mode->base.width == output->base.current->width &&
920 drm_mode->base.height == output->base.current->height) {
921 /* only change refresh value */
922 ret = drmModeSetCrtc(ec->drm.fd,
923 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300924 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800925 &output->connector_id, 1, &drm_mode->mode_info);
926
927 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200928 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800929 drm_mode->base.width,
930 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400931 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800932 ret = -1;
933 } else {
934 output->base.current->flags = 0;
935 output->base.current = &drm_mode->base;
936 drm_mode->base.flags =
937 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
938 ret = 0;
939 }
940
941 return ret;
942 }
943
944 drm_mode->base.flags =
945 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
946
947 surface = gbm_surface_create(ec->gbm,
948 drm_mode->base.width,
949 drm_mode->base.height,
950 GBM_FORMAT_XRGB8888,
951 GBM_BO_USE_SCANOUT |
952 GBM_BO_USE_RENDERING);
953 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200954 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800955 return -1;
956 }
957
958 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400959 eglCreateWindowSurface(ec->base.egl_display,
960 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800961 surface, NULL);
962
963 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200964 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800965 goto err;
966 }
967
968 ret = drmModeSetCrtc(ec->drm.fd,
969 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300970 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800971 &output->connector_id, 1, &drm_mode->mode_info);
972 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200973 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800974 goto err;
975 }
976
977 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300978 if (output->current) {
979 if (output->current->is_client_buffer)
980 gbm_bo_destroy(output->current->bo);
981 else
982 gbm_surface_release_buffer(output->surface,
983 output->current->bo);
984 }
985 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800986
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300987 if (output->next) {
988 if (output->next->is_client_buffer)
989 gbm_bo_destroy(output->next->bo);
990 else
991 gbm_surface_release_buffer(output->surface,
992 output->next->bo);
993 }
994 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800995
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400996 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800997 gbm_surface_destroy(output->surface);
998 output->egl_surface = egl_surface;
999 output->surface = surface;
1000
1001 /*update output*/
1002 output->base.current = &drm_mode->base;
1003 output->base.dirty = 1;
1004 weston_output_move(&output->base, output->base.x, output->base.y);
1005 return 0;
1006
1007err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001008 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001009 gbm_surface_destroy(surface);
1010 return -1;
1011}
1012
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001013static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001014on_drm_input(int fd, uint32_t mask, void *data)
1015{
1016 drmEventContext evctx;
1017
1018 memset(&evctx, 0, sizeof evctx);
1019 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1020 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001021 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001022 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001023
1024 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001025}
1026
1027static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001028init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001029{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001030 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001031 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001032 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001033 static const EGLint context_attribs[] = {
1034 EGL_CONTEXT_CLIENT_VERSION, 2,
1035 EGL_NONE
1036 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001037
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001038 static const EGLint config_attribs[] = {
1039 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1040 EGL_RED_SIZE, 1,
1041 EGL_GREEN_SIZE, 1,
1042 EGL_BLUE_SIZE, 1,
1043 EGL_ALPHA_SIZE, 0,
1044 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1045 EGL_NONE
1046 };
1047
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001048 sysnum = udev_device_get_sysnum(device);
1049 if (sysnum)
1050 ec->drm.id = atoi(sysnum);
1051 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001052 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001053 return -1;
1054 }
1055
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001056 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001057 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001058 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001059 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001060 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001061 udev_device_get_devnode(device));
1062 return -1;
1063 }
1064
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001065 weston_log("using %s\n", filename);
1066
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001067 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001068 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001069 ec->base.egl_display = eglGetDisplay(ec->gbm);
1070 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001071 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001072 return -1;
1073 }
1074
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001075 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001076 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001077 return -1;
1078 }
1079
Darxus55973f22010-11-22 21:24:39 -05001080 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001081 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001082 return -1;
1083 }
1084
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001085 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1086 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001087 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001088 return -1;
1089 }
1090
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001091 ec->base.egl_context =
1092 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1093 EGL_NO_CONTEXT, context_attribs);
1094 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001095 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001096 return -1;
1097 }
1098
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001099 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1100 GBM_FORMAT_XRGB8888,
1101 GBM_BO_USE_RENDERING);
1102 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001103 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001104 return -1;
1105 }
1106
1107 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001108 eglCreateWindowSurface(ec->base.egl_display,
1109 ec->base.egl_config,
1110 ec->dummy_surface,
1111 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001112 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001113 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001114 return -1;
1115 }
1116
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001117 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1118 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001119 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001120 return -1;
1121 }
1122
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001123 return 0;
1124}
1125
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001126static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001127drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1128{
1129 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001130 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001131
1132 mode = malloc(sizeof *mode);
1133 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001134 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001135
1136 mode->base.flags = 0;
1137 mode->base.width = info->hdisplay;
1138 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001139
1140 /* Calculate higher precision (mHz) refresh rate */
1141 refresh = (info->clock * 1000000LL / info->htotal +
1142 info->vtotal / 2) / info->vtotal;
1143
1144 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1145 refresh *= 2;
1146 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1147 refresh /= 2;
1148 if (info->vscan > 1)
1149 refresh /= info->vscan;
1150
1151 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001152 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001153
1154 if (info->type & DRM_MODE_TYPE_PREFERRED)
1155 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1156
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001157 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1158
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001159 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001160}
1161
1162static int
1163drm_subpixel_to_wayland(int drm_value)
1164{
1165 switch (drm_value) {
1166 default:
1167 case DRM_MODE_SUBPIXEL_UNKNOWN:
1168 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1169 case DRM_MODE_SUBPIXEL_NONE:
1170 return WL_OUTPUT_SUBPIXEL_NONE;
1171 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1172 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1173 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1174 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1175 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1176 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1177 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1178 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1179 }
1180}
1181
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001182static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001183sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001184{
1185 struct drm_sprite *sprite =
1186 container_of(listener, struct drm_sprite,
1187 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001188 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001189
1190 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001191 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1192 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001193}
1194
1195static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001196sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001197{
1198 struct drm_sprite *sprite =
1199 container_of(listener, struct drm_sprite,
1200 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001201 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001202
1203 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001204 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1205 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001206}
1207
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001208/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001209static uint32_t
1210drm_get_backlight(struct drm_output *output)
1211{
1212 long brightness, max_brightness, norm;
1213
1214 brightness = backlight_get_brightness(output->backlight);
1215 max_brightness = backlight_get_max_brightness(output->backlight);
1216
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001217 /* convert it on a scale of 0 to 255 */
1218 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001219
1220 return (uint32_t) norm;
1221}
1222
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001223/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001224static void
1225drm_set_backlight(struct weston_output *output_base, uint32_t value)
1226{
1227 struct drm_output *output = (struct drm_output *) output_base;
1228 long max_brightness, new_brightness;
1229
1230 if (!output->backlight)
1231 return;
1232
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001233 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001234 return;
1235
1236 max_brightness = backlight_get_max_brightness(output->backlight);
1237
1238 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001239 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001240
1241 backlight_set_brightness(output->backlight, new_brightness);
1242}
1243
1244static drmModePropertyPtr
1245drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1246{
1247 drmModePropertyPtr props;
1248 int i;
1249
1250 for (i = 0; i < connector->count_props; i++) {
1251 props = drmModeGetProperty(fd, connector->props[i]);
1252 if (!props)
1253 continue;
1254
1255 if (!strcmp(props->name, name))
1256 return props;
1257
1258 drmModeFreeProperty(props);
1259 }
1260
1261 return NULL;
1262}
1263
1264static void
1265drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1266{
1267 struct drm_output *output = (struct drm_output *) output_base;
1268 struct weston_compositor *ec = output_base->compositor;
1269 struct drm_compositor *c = (struct drm_compositor *) ec;
1270 drmModeConnectorPtr connector;
1271 drmModePropertyPtr prop;
1272
1273 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1274 if (!connector)
1275 return;
1276
1277 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1278 if (!prop) {
1279 drmModeFreeConnector(connector);
1280 return;
1281 }
1282
1283 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1284 prop->prop_id, level);
1285 drmModeFreeProperty(prop);
1286 drmModeFreeConnector(connector);
1287}
1288
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001289static const char *connector_type_names[] = {
1290 "None",
1291 "VGA",
1292 "DVI",
1293 "DVI",
1294 "DVI",
1295 "Composite",
1296 "TV",
1297 "LVDS",
1298 "CTV",
1299 "DIN",
1300 "DP",
1301 "HDMI",
1302 "HDMI",
1303 "TV",
1304 "eDP",
1305};
1306
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001307static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001308find_crtc_for_connector(struct drm_compositor *ec,
1309 drmModeRes *resources, drmModeConnector *connector)
1310{
1311 drmModeEncoder *encoder;
1312 uint32_t possible_crtcs;
1313 int i, j;
1314
1315 for (j = 0; j < connector->count_encoders; j++) {
1316 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1317 if (encoder == NULL) {
1318 weston_log("Failed to get encoder.\n");
1319 return -1;
1320 }
1321 possible_crtcs = encoder->possible_crtcs;
1322 drmModeFreeEncoder(encoder);
1323
1324 for (i = 0; i < resources->count_crtcs; i++) {
1325 if (possible_crtcs & (1 << i) &&
1326 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1327 return i;
1328 }
1329 }
1330
1331 return -1;
1332}
1333
1334static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001335create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001336 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001337 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001338 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001339{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001340 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001341 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1342 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001343 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001344 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001345 drmModeModeInfo crtc_mode;
1346 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001347 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001348 char name[32];
1349 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001350
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001351 i = find_crtc_for_connector(ec, resources, connector);
1352 if (i < 0) {
1353 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001354 return -1;
1355 }
1356
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001357 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001358 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001359 return -1;
1360
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001361 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001362 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1363 output->base.make = "unknown";
1364 output->base.model = "unknown";
1365 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001366
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001367 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1368 type_name = connector_type_names[connector->connector_type];
1369 else
1370 type_name = "UNKNOWN";
1371 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1372 output->name = strdup(name);
1373
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001374 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001375 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001376 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001377 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001378 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001379
Matt Roper361d2ad2011-08-29 13:52:23 -07001380 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1381
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001382 /* Get the current mode on the crtc that's currently driving
1383 * this connector. */
1384 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001385 memset(&crtc_mode, 0, sizeof crtc_mode);
1386 if (encoder != NULL) {
1387 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1388 drmModeFreeEncoder(encoder);
1389 if (crtc == NULL)
1390 goto err_free;
1391 if (crtc->mode_valid)
1392 crtc_mode = crtc->mode;
1393 drmModeFreeCrtc(crtc);
1394 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001395
David Herrmann0f0d54e2011-12-08 17:05:45 +01001396 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001397 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1398 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001399 goto err_free;
1400 }
1401
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001402 preferred = NULL;
1403 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001404 configured = NULL;
1405
1406 wl_list_for_each(temp, &configured_output_list, link) {
1407 if (strcmp(temp->name, output->name) == 0) {
1408 weston_log("%s mode \"%s\" in config\n",
1409 temp->name, temp->mode);
1410 o = temp;
1411 break;
1412 }
1413 }
1414
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001415 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001416 weston_log("Disabling output %s\n", o->name);
1417
1418 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1419 0, 0, 0, 0, 0, NULL);
1420 goto err_free;
1421 }
1422
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001423 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001424 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001425 o->height == drm_mode->base.height &&
1426 o->config == OUTPUT_CONFIG_MODE)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001427 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001428 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001429 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001430 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001431 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001432 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001433
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001434 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001435 configured = drm_output_add_mode(output, &o->crtc_mode);
1436 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001437 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001438 current = configured;
1439 }
1440
Wang Quanxianacb805a2012-07-30 18:09:46 -04001441 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001442 current = drm_output_add_mode(output, &crtc_mode);
1443 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001444 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001445 }
1446
Scott Moreau8ab5d452012-07-30 19:51:08 -06001447 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1448 configured = current;
1449
Wang Quanxianacb805a2012-07-30 18:09:46 -04001450 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001451 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001452 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001453 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001454 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001455 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001456 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001457 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001458
1459 if (output->base.current == NULL) {
1460 weston_log("no available modes for %s\n", output->name);
1461 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001462 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001463
Wang Quanxianacb805a2012-07-30 18:09:46 -04001464 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1465
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001466 output->surface = gbm_surface_create(ec->gbm,
1467 output->base.current->width,
1468 output->base.current->height,
1469 GBM_FORMAT_XRGB8888,
1470 GBM_BO_USE_SCANOUT |
1471 GBM_BO_USE_RENDERING);
1472 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001473 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001474 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001475 }
1476
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001477 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001478 eglCreateWindowSurface(ec->base.egl_display,
1479 ec->base.egl_config,
1480 output->surface,
1481 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001482 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001483 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001484 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001485 }
1486
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001487 output->cursor_bo[0] =
1488 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1489 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1490 output->cursor_bo[1] =
1491 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1492 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1493
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001494 output->backlight = backlight_init(drm_device,
1495 connector->connector_type);
1496 if (output->backlight) {
1497 output->base.set_backlight = drm_set_backlight;
1498 output->base.backlight_current = drm_get_backlight(output);
1499 }
1500
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001501 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001502 connector->mmWidth, connector->mmHeight,
1503 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001504
1505 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1506
Alex Wubd3354b2012-04-17 17:20:49 +08001507 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001508 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001509 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001510 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001511 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001512 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001513
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001514 weston_plane_init(&output->cursor_plane, 0, 0);
1515 weston_plane_init(&output->fb_plane, 0, 0);
1516
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001517 weston_log("Output %s, (connector %d, crtc %d)\n",
1518 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001519 wl_list_for_each(m, &output->base.mode_list, link)
1520 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1521 m->width, m->height, m->refresh / 1000.0,
1522 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1523 ", preferred" : "",
1524 m->flags & WL_OUTPUT_MODE_CURRENT ?
1525 ", current" : "",
1526 connector->count_modes == 0 ?
1527 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001528
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001529 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001530
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001531err_surface:
1532 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001533err_free:
1534 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1535 base.link) {
1536 wl_list_remove(&drm_mode->base.link);
1537 free(drm_mode);
1538 }
1539
1540 drmModeFreeCrtc(output->original_crtc);
1541 ec->crtc_allocator &= ~(1 << output->crtc_id);
1542 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001543 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001544 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001545
David Herrmann0f0d54e2011-12-08 17:05:45 +01001546 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001547}
1548
Jesse Barnes58ef3792012-02-23 09:45:49 -05001549static void
1550create_sprites(struct drm_compositor *ec)
1551{
1552 struct drm_sprite *sprite;
1553 drmModePlaneRes *plane_res;
1554 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001555 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001556
1557 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1558 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001559 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001560 strerror(errno));
1561 return;
1562 }
1563
1564 for (i = 0; i < plane_res->count_planes; i++) {
1565 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1566 if (!plane)
1567 continue;
1568
1569 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1570 plane->count_formats));
1571 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001572 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001573 __func__);
1574 free(plane);
1575 continue;
1576 }
1577
1578 memset(sprite, 0, sizeof *sprite);
1579
1580 sprite->possible_crtcs = plane->possible_crtcs;
1581 sprite->plane_id = plane->plane_id;
1582 sprite->surface = NULL;
1583 sprite->pending_surface = NULL;
1584 sprite->fb_id = 0;
1585 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001586 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1587 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001588 sprite_handle_pending_buffer_destroy;
1589 sprite->compositor = ec;
1590 sprite->count_formats = plane->count_formats;
1591 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001592 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001593 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001594 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001595
1596 wl_list_insert(&ec->sprite_list, &sprite->link);
1597 }
1598
1599 free(plane_res->planes);
1600 free(plane_res);
1601}
1602
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001603static void
1604destroy_sprites(struct drm_compositor *compositor)
1605{
1606 struct drm_sprite *sprite, *next;
1607 struct drm_output *output;
1608
1609 output = container_of(compositor->base.output_list.next,
1610 struct drm_output, base.link);
1611
1612 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1613 drmModeSetPlane(compositor->drm.fd,
1614 sprite->plane_id,
1615 output->crtc_id, 0, 0,
1616 0, 0, 0, 0, 0, 0, 0, 0);
1617 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001618 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001619 free(sprite);
1620 }
1621}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001622
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001623static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001624create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001625 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001626{
1627 drmModeConnector *connector;
1628 drmModeRes *resources;
1629 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001630 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001631
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001632 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001633 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001634 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001635 return -1;
1636 }
1637
Jesse Barnes58ef3792012-02-23 09:45:49 -05001638 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001639 if (!ec->crtcs) {
1640 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001641 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001642 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001643
1644 ec->num_crtcs = resources->count_crtcs;
1645 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1646
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001647 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001648 connector = drmModeGetConnector(ec->drm.fd,
1649 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001650 if (connector == NULL)
1651 continue;
1652
1653 if (connector->connection == DRM_MODE_CONNECTED &&
1654 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001655 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001656 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001657 connector, x, y,
1658 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001659 drmModeFreeConnector(connector);
1660 continue;
1661 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001662
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001663 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001664 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001665 link)->current->width;
1666 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001667
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001668 drmModeFreeConnector(connector);
1669 }
1670
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001671 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001672 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001673 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001674 return -1;
1675 }
1676
1677 drmModeFreeResources(resources);
1678
1679 return 0;
1680}
1681
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001682static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001683update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001684{
1685 drmModeConnector *connector;
1686 drmModeRes *resources;
1687 struct drm_output *output, *next;
1688 int x = 0, y = 0;
1689 int x_offset = 0, y_offset = 0;
1690 uint32_t connected = 0, disconnects = 0;
1691 int i;
1692
1693 resources = drmModeGetResources(ec->drm.fd);
1694 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001695 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001696 return;
1697 }
1698
1699 /* collect new connects */
1700 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001701 int connector_id = resources->connectors[i];
1702
1703 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001704 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001705 continue;
1706
David Herrmann7551cff2011-12-08 17:05:43 +01001707 if (connector->connection != DRM_MODE_CONNECTED) {
1708 drmModeFreeConnector(connector);
1709 continue;
1710 }
1711
Benjamin Franzke117483d2011-08-30 11:38:26 +02001712 connected |= (1 << connector_id);
1713
1714 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001715 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001716 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001717 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718
1719 /* XXX: not yet needed, we die with 0 outputs */
1720 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001721 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001722 else
1723 x = 0;
1724 y = 0;
1725 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001726 connector, x, y,
1727 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001728 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001729
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001730 }
1731 drmModeFreeConnector(connector);
1732 }
1733 drmModeFreeResources(resources);
1734
1735 disconnects = ec->connector_allocator & ~connected;
1736 if (disconnects) {
1737 wl_list_for_each_safe(output, next, &ec->base.output_list,
1738 base.link) {
1739 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001740 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001741 output->base.x - x_offset,
1742 output->base.y - y_offset);
1743 }
1744
1745 if (disconnects & (1 << output->connector_id)) {
1746 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001747 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001748 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001749 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001750 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001751 }
1752 }
1753 }
1754
1755 /* FIXME: handle zero outputs, without terminating */
1756 if (ec->connector_allocator == 0)
1757 wl_display_terminate(ec->base.wl_display);
1758}
1759
1760static int
David Herrmannd7488c22012-03-11 20:05:21 +01001761udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001762{
David Herrmannd7488c22012-03-11 20:05:21 +01001763 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001764 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001765
1766 sysnum = udev_device_get_sysnum(device);
1767 if (!sysnum || atoi(sysnum) != ec->drm.id)
1768 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001769
David Herrmann6ac52db2012-03-11 20:05:22 +01001770 val = udev_device_get_property_value(device, "HOTPLUG");
1771 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001772 return 0;
1773
David Herrmann6ac52db2012-03-11 20:05:22 +01001774 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001775}
1776
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001777static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001778udev_drm_event(int fd, uint32_t mask, void *data)
1779{
1780 struct drm_compositor *ec = data;
1781 struct udev_device *event;
1782
1783 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001784
David Herrmannd7488c22012-03-11 20:05:21 +01001785 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001786 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001787
1788 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001789
1790 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001791}
1792
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001793static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001794drm_restore(struct weston_compositor *ec)
1795{
1796 struct drm_compositor *d = (struct drm_compositor *) ec;
1797
1798 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1799 weston_log("failed to drop master: %m\n");
1800 tty_reset(d->tty);
1801}
1802
Pekka Paalanen33156972012-08-03 13:30:30 -04001803static const char default_seat[] = "seat0";
1804
1805static void
1806device_added(struct udev_device *udev_device, struct drm_seat *master)
1807{
1808 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001809 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001810 const char *devnode;
1811 const char *device_seat;
1812 int fd;
1813
1814 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1815 if (!device_seat)
1816 device_seat = default_seat;
1817
1818 if (strcmp(device_seat, master->seat_id))
1819 return;
1820
1821 c = master->base.compositor;
1822 devnode = udev_device_get_devnode(udev_device);
1823
1824 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001825 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001826 * read. mtdev_get() also expects this. */
1827 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1828 if (fd < 0) {
1829 weston_log("opening input device '%s' failed.\n", devnode);
1830 return;
1831 }
1832
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001833 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001834 if (!device) {
1835 close(fd);
1836 weston_log("not using input device '%s'.\n", devnode);
1837 return;
1838 }
1839
1840 wl_list_insert(master->devices_list.prev, &device->link);
1841}
1842
1843static void
1844evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1845{
1846 struct drm_seat *seat = (struct drm_seat *) seat_base;
1847 struct udev_enumerate *e;
1848 struct udev_list_entry *entry;
1849 struct udev_device *device;
1850 const char *path, *sysname;
1851
1852 e = udev_enumerate_new(udev);
1853 udev_enumerate_add_match_subsystem(e, "input");
1854 udev_enumerate_scan_devices(e);
1855 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1856 path = udev_list_entry_get_name(entry);
1857 device = udev_device_new_from_syspath(udev, path);
1858
1859 sysname = udev_device_get_sysname(device);
1860 if (strncmp("event", sysname, 5) != 0) {
1861 udev_device_unref(device);
1862 continue;
1863 }
1864
1865 device_added(device, seat);
1866
1867 udev_device_unref(device);
1868 }
1869 udev_enumerate_unref(e);
1870
1871 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1872
1873 if (wl_list_empty(&seat->devices_list)) {
1874 weston_log(
1875 "warning: no input devices on entering Weston. "
1876 "Possible causes:\n"
1877 "\t- no permissions to read /dev/input/event*\n"
1878 "\t- seats misconfigured "
1879 "(Weston backend option 'seat', "
1880 "udev device property ID_SEAT)\n");
1881 }
1882}
1883
1884static int
1885evdev_udev_handler(int fd, uint32_t mask, void *data)
1886{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001887 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001888 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001889 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001890 const char *action;
1891 const char *devnode;
1892
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001893 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001894 if (!udev_device)
1895 return 1;
1896
1897 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001898 if (!action)
1899 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001900
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001901 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1902 goto out;
1903
1904 if (!strcmp(action, "add")) {
1905 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001906 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001907 else if (!strcmp(action, "remove")) {
1908 devnode = udev_device_get_devnode(udev_device);
1909 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1910 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001911 weston_log("input device %s, %s removed\n",
1912 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001913 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001914 break;
1915 }
1916 }
1917
1918out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001919 udev_device_unref(udev_device);
1920
1921 return 0;
1922}
1923
1924static int
1925evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1926{
1927 struct drm_seat *master = (struct drm_seat *) seat_base;
1928 struct wl_event_loop *loop;
1929 struct weston_compositor *c = master->base.compositor;
1930 int fd;
1931
1932 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1933 if (!master->udev_monitor) {
1934 weston_log("udev: failed to create the udev monitor\n");
1935 return 0;
1936 }
1937
1938 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1939 "input", NULL);
1940
1941 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1942 weston_log("udev: failed to bind the udev monitor\n");
1943 udev_monitor_unref(master->udev_monitor);
1944 return 0;
1945 }
1946
1947 loop = wl_display_get_event_loop(c->wl_display);
1948 fd = udev_monitor_get_fd(master->udev_monitor);
1949 master->udev_monitor_source =
1950 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1951 evdev_udev_handler, master);
1952 if (!master->udev_monitor_source) {
1953 udev_monitor_unref(master->udev_monitor);
1954 return 0;
1955 }
1956
1957 return 1;
1958}
1959
1960static void
1961evdev_disable_udev_monitor(struct weston_seat *seat_base)
1962{
1963 struct drm_seat *seat = (struct drm_seat *) seat_base;
1964
1965 if (!seat->udev_monitor)
1966 return;
1967
1968 udev_monitor_unref(seat->udev_monitor);
1969 seat->udev_monitor = NULL;
1970 wl_event_source_remove(seat->udev_monitor_source);
1971 seat->udev_monitor_source = NULL;
1972}
1973
1974static void
1975drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1976{
1977 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001978 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001979
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001980 wl_list_for_each(device, &seat->devices_list, link)
1981 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001982}
1983
1984static void
1985evdev_input_create(struct weston_compositor *c, struct udev *udev,
1986 const char *seat_id)
1987{
1988 struct drm_seat *seat;
1989
1990 seat = malloc(sizeof *seat);
1991 if (seat == NULL)
1992 return;
1993
1994 memset(seat, 0, sizeof *seat);
1995 weston_seat_init(&seat->base, c);
1996 seat->base.led_update = drm_led_update;
1997
1998 wl_list_init(&seat->devices_list);
1999 seat->seat_id = strdup(seat_id);
2000 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2001 free(seat->seat_id);
2002 free(seat);
2003 return;
2004 }
2005
2006 evdev_add_devices(udev, &seat->base);
2007
2008 c->seat = &seat->base;
2009}
2010
2011static void
2012evdev_remove_devices(struct weston_seat *seat_base)
2013{
2014 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002015 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002016
2017 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002018 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002019
Pekka Paalanend8583512012-08-03 14:39:11 +03002020 if (seat->base.seat.keyboard)
2021 notify_keyboard_focus_out(&seat->base.seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002022}
2023
2024static void
2025evdev_input_destroy(struct weston_seat *seat_base)
2026{
2027 struct drm_seat *seat = (struct drm_seat *) seat_base;
2028
2029 evdev_remove_devices(seat_base);
2030 evdev_disable_udev_monitor(&seat->base);
2031
2032 weston_seat_release(seat_base);
2033 free(seat->seat_id);
2034 free(seat);
2035}
2036
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002037static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002038drm_free_configured_output(struct drm_configured_output *output)
2039{
2040 free(output->name);
2041 free(output->mode);
2042 free(output);
2043}
2044
2045static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002046drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002047{
2048 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002049 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002050 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002051
Daniel Stone37816df2012-05-16 18:45:18 +01002052 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2053 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002054 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002055 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002056
2057 wl_event_source_remove(d->udev_drm_source);
2058 wl_event_source_remove(d->drm_source);
2059
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002060 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002061
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002062 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002063 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002064 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002065 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002066 eglReleaseThread();
2067
Matt Roper361d2ad2011-08-29 13:52:23 -07002068 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002069 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002070 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002071 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002072 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002073
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002074 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002075}
2076
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002077static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002078drm_compositor_set_modes(struct drm_compositor *compositor)
2079{
2080 struct drm_output *output;
2081 struct drm_mode *drm_mode;
2082 int ret;
2083
2084 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2085 drm_mode = (struct drm_mode *) output->base.current;
2086 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002087 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002088 &output->connector_id, 1,
2089 &drm_mode->mode_info);
2090 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002091 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002092 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002093 drm_mode->base.width, drm_mode->base.height,
2094 output->base.x, output->base.y);
2095 }
2096 }
2097}
2098
2099static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002100vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002101{
2102 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002103 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002104 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002105 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002106
2107 switch (event) {
2108 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002109 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002110 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002111 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002112 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002113 wl_display_terminate(compositor->wl_display);
2114 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002115 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002116 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002117 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002118 wl_list_for_each(seat, &compositor->seat_list, link) {
2119 evdev_add_devices(ec->udev, seat);
2120 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002121 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002122 break;
2123 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002124 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002125 wl_list_for_each(seat, &compositor->seat_list, link) {
2126 evdev_disable_udev_monitor(seat);
2127 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002128 }
2129
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002130 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002131 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002132 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002133
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002134 /* If we have a repaint scheduled (either from a
2135 * pending pageflip or the idle handler), make sure we
2136 * cancel that so we don't try to pageflip when we're
2137 * vt switched away. The SLEEPING state will prevent
2138 * further attemps at repainting. When we switch
2139 * back, we schedule a repaint, which will process
2140 * pending frame callbacks. */
2141
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002142 wl_list_for_each(output, &ec->base.output_list, base.link) {
2143 output->base.repaint_needed = 0;
2144 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002145 }
2146
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002147 output = container_of(ec->base.output_list.next,
2148 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002149
2150 wl_list_for_each(sprite, &ec->sprite_list, link)
2151 drmModeSetPlane(ec->drm.fd,
2152 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002153 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002154 0, 0, 0, 0, 0, 0, 0, 0);
2155
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002156 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002157 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002158
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002159 break;
2160 };
2161}
2162
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002163static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002164switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002165{
2166 struct drm_compositor *ec = data;
2167
Daniel Stone325fc2d2012-05-30 16:31:58 +01002168 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002169}
2170
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002171static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002172drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002173 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002174 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002175{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002176 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002177 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002178 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002179 struct udev_device *device, *drm_device;
2180 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002181 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002182 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002183 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002184
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002185 weston_log("initializing drm backend\n");
2186
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002187 ec = malloc(sizeof *ec);
2188 if (ec == NULL)
2189 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002190 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002191
2192 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002193 config_file) < 0) {
2194 weston_log("weston_compositor_init failed\n");
2195 goto err_base;
2196 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002197
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002198 ec->udev = udev_new();
2199 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002200 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002201 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002202 }
2203
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002204 ec->base.wl_display = display;
2205 ec->tty = tty_create(&ec->base, vt_func, tty);
2206 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002207 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002208 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002209 }
2210
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211 e = udev_enumerate_new(ec->udev);
2212 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002213 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002214
Benjamin Franzke117483d2011-08-30 11:38:26 +02002215 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002216 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002217 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002218 path = udev_list_entry_get_name(entry);
2219 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002220 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002221 udev_device_get_property_value(device, "ID_SEAT");
2222 if (!device_seat)
2223 device_seat = default_seat;
2224 if (strcmp(device_seat, seat) == 0) {
2225 drm_device = device;
2226 break;
2227 }
2228 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002229 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002230
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002231 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002232 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002233 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002234 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002235
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002236 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002237 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002238 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002239 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002240
2241 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002242 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002243
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002244 ec->base.focus = 1;
2245
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002246 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002247
Daniel Stone725c2c32012-06-22 14:04:36 +01002248 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002249 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002250
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002251 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002252 weston_compositor_add_key_binding(&ec->base, key,
2253 MODIFIER_CTRL | MODIFIER_ALT,
2254 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002255
Jesse Barnes58ef3792012-02-23 09:45:49 -05002256 wl_list_init(&ec->sprite_list);
2257 create_sprites(ec);
2258
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002259 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002260 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002261 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002262 }
2263
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002264 path = NULL;
2265
Tiago Vignattice03ec32011-12-19 01:14:03 +02002266 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002267
2268 loop = wl_display_get_event_loop(ec->base.wl_display);
2269 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002270 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002271 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002272
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002273 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2274 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002275 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002276 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002277 }
2278 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2279 "drm", NULL);
2280 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002281 wl_event_loop_add_fd(loop,
2282 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002283 WL_EVENT_READABLE, udev_drm_event, ec);
2284
2285 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002286 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002287 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002288 }
2289
Daniel Stonea96b93c2012-06-22 14:04:37 +01002290 udev_device_unref(drm_device);
2291 udev_enumerate_unref(e);
2292
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002293 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002294
2295err_udev_monitor:
2296 wl_event_source_remove(ec->udev_drm_source);
2297 udev_monitor_unref(ec->udev_monitor);
2298err_drm_source:
2299 wl_event_source_remove(ec->drm_source);
2300 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2301 evdev_input_destroy(weston_seat);
2302err_sprite:
2303 destroy_sprites(ec);
2304err_egl:
2305 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2306 EGL_NO_CONTEXT);
2307 eglTerminate(ec->base.egl_display);
2308 eglReleaseThread();
2309 gbm_device_destroy(ec->gbm);
2310err_udev_dev:
2311 udev_device_unref(drm_device);
2312err_udev_enum:
2313 udev_enumerate_unref(e);
2314 tty_destroy(ec->tty);
2315err_udev:
2316 udev_unref(ec->udev);
2317err_compositor:
2318 weston_compositor_shutdown(&ec->base);
2319err_base:
2320 free(ec);
2321 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002322}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002323
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002324static int
2325set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2326{
2327 mode->flags = 0;
2328
2329 if (strcmp(hsync, "+hsync") == 0)
2330 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2331 else if (strcmp(hsync, "-hsync") == 0)
2332 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2333 else
2334 return -1;
2335
2336 if (strcmp(vsync, "+vsync") == 0)
2337 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2338 else if (strcmp(vsync, "-vsync") == 0)
2339 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2340 else
2341 return -1;
2342
2343 return 0;
2344}
2345
2346static int
2347check_for_modeline(struct drm_configured_output *output)
2348{
2349 drmModeModeInfo mode;
2350 char hsync[16];
2351 char vsync[16];
2352 char mode_name[16];
2353 float fclock;
2354
2355 mode.type = DRM_MODE_TYPE_USERDEF;
2356 mode.hskew = 0;
2357 mode.vscan = 0;
2358 mode.vrefresh = 0;
2359
2360 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2361 &fclock, &mode.hdisplay,
2362 &mode.hsync_start,
2363 &mode.hsync_end, &mode.htotal,
2364 &mode.vdisplay,
2365 &mode.vsync_start,
2366 &mode.vsync_end, &mode.vtotal,
2367 hsync, vsync) == 11) {
2368 if (set_sync_flags(&mode, hsync, vsync))
2369 return -1;
2370
2371 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2372 strcpy(mode.name, mode_name);
2373
2374 mode.clock = fclock * 1000;
2375 } else
2376 return -1;
2377
2378 output->crtc_mode = mode;
2379
2380 return 0;
2381}
2382
Scott Moreau8ab5d452012-07-30 19:51:08 -06002383static void
2384output_section_done(void *data)
2385{
2386 struct drm_configured_output *output;
2387
2388 output = malloc(sizeof *output);
2389
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002390 if (!output || !output_name || !output_mode) {
2391 free(output_name);
2392 output_name = NULL;
2393 free(output_mode);
2394 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002395 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002396 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002397
2398 output->config = OUTPUT_CONFIG_INVALID;
2399 output->name = output_name;
2400 output->mode = output_mode;
2401
2402 if (strcmp(output_mode, "off") == 0)
2403 output->config = OUTPUT_CONFIG_OFF;
2404 else if (strcmp(output_mode, "preferred") == 0)
2405 output->config = OUTPUT_CONFIG_PREFERRED;
2406 else if (strcmp(output_mode, "current") == 0)
2407 output->config = OUTPUT_CONFIG_CURRENT;
2408 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2409 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002410 else if (check_for_modeline(output) == 0)
2411 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002412
2413 if (output->config != OUTPUT_CONFIG_INVALID)
2414 wl_list_insert(&configured_output_list, &output->link);
2415 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002416 weston_log("Invalid mode \"%s\" for output %s\n",
2417 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002418 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002419 }
2420}
2421
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002422WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002423backend_init(struct wl_display *display, int argc, char *argv[],
2424 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002425{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002426 int connector = 0, tty = 0;
2427 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002428
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002429 const struct weston_option drm_options[] = {
2430 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2431 { WESTON_OPTION_STRING, "seat", 0, &seat },
2432 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002433 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002434 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002435
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002436 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002437
Scott Moreau8ab5d452012-07-30 19:51:08 -06002438 wl_list_init(&configured_output_list);
2439
2440 const struct config_key drm_config_keys[] = {
2441 { "name", CONFIG_KEY_STRING, &output_name },
2442 { "mode", CONFIG_KEY_STRING, &output_mode },
2443 };
2444
2445 const struct config_section config_section[] = {
2446 { "output", drm_config_keys,
2447 ARRAY_LENGTH(drm_config_keys), output_section_done },
2448 };
2449
2450 parse_config_file(config_file, config_section,
2451 ARRAY_LENGTH(config_section), NULL);
2452
Daniel Stonec1be8e52012-06-01 11:14:02 -04002453 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2454 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002455}