blob: 0e3b6e8a7395bfcaa0938ff4e3c12a082d2d5a9f [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020043#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010044#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Kristian Høgsberg061c4252012-06-28 11:28:15 -040046static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060047static char *output_name;
48static char *output_mode;
49static struct wl_list configured_output_list;
50
51enum output_config {
52 OUTPUT_CONFIG_INVALID = 0,
53 OUTPUT_CONFIG_OFF,
54 OUTPUT_CONFIG_PREFERRED,
55 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060056 OUTPUT_CONFIG_MODE,
57 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060058};
59
60struct drm_configured_output {
61 char *name;
62 char *mode;
63 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060064 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065 enum output_config config;
66 struct wl_list link;
67};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040068
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050070 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
72 struct udev *udev;
73 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010075 struct udev_monitor *udev_monitor;
76 struct wl_event_source *udev_drm_source;
77
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010079 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 int fd;
81 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020082 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050083 uint32_t *crtcs;
84 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050085 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010086 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050087 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020088
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040089 struct gbm_surface *dummy_surface;
90 EGLSurface dummy_egl_surface;
91
Jesse Barnes58ef3792012-02-23 09:45:49 -050092 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050093 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -050094
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020095 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040096};
97
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040098struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050099 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400100 drmModeModeInfo mode_info;
101};
102
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300103struct drm_output;
104
105struct drm_fb {
106 struct gbm_bo *bo;
107 struct drm_output *output;
108 uint32_t fb_id;
109 int is_client_buffer;
110 struct wl_buffer *buffer;
111 struct wl_listener buffer_destroy_listener;
112};
113
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400114struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500115 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400116
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400117 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400118 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500119 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400120 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700121 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200122
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300123 int vblank_pending;
124 int page_flip_pending;
125
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400126 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400127 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400128 struct weston_plane cursor_plane;
129 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400130 struct weston_surface *cursor_surface;
131 int current_cursor;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400132 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300133 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200134 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400135};
136
Jesse Barnes58ef3792012-02-23 09:45:49 -0500137/*
138 * An output has a primary display plane plus zero or more sprites for
139 * blending display contents.
140 */
141struct drm_sprite {
142 struct wl_list link;
143
144 uint32_t fb_id;
145 uint32_t pending_fb_id;
146 struct weston_surface *surface;
147 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400148 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500149
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300150 struct drm_output *output;
151
Jesse Barnes58ef3792012-02-23 09:45:49 -0500152 struct drm_compositor *compositor;
153
154 struct wl_listener destroy_listener;
155 struct wl_listener pending_destroy_listener;
156
157 uint32_t possible_crtcs;
158 uint32_t plane_id;
159 uint32_t count_formats;
160
161 int32_t src_x, src_y;
162 uint32_t src_w, src_h;
163 uint32_t dest_x, dest_y;
164 uint32_t dest_w, dest_h;
165
166 uint32_t formats[];
167};
168
Pekka Paalanen33156972012-08-03 13:30:30 -0400169struct drm_seat {
170 struct weston_seat base;
171 struct wl_list devices_list;
172 struct udev_monitor *udev_monitor;
173 struct wl_event_source *udev_monitor_source;
174 char *seat_id;
175};
176
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400177static void
178drm_output_set_cursor(struct drm_output *output);
179static void
180drm_disable_unused_sprites(struct weston_output *output_base);
181
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
184{
185 struct weston_compositor *ec = output_base->compositor;
186 struct drm_compositor *c =(struct drm_compositor *) ec;
187 struct drm_output *output = (struct drm_output *) output_base;
188 int crtc;
189
190 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
191 if (c->crtcs[crtc] != output->crtc_id)
192 continue;
193
194 if (supported & (1 << crtc))
195 return -1;
196 }
197
198 return 0;
199}
200
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300201static void
202drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
203{
204 struct drm_fb *fb = data;
205 struct gbm_device *gbm = gbm_bo_get_device(bo);
206
207 if (fb->fb_id)
208 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
209
210 if (fb->buffer) {
211 weston_buffer_post_release(fb->buffer);
212 wl_list_remove(&fb->buffer_destroy_listener.link);
213 }
214
215 free(data);
216}
217
218static struct drm_fb *
219drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
220{
221 struct drm_fb *fb = gbm_bo_get_user_data(bo);
222 struct drm_compositor *compositor =
223 (struct drm_compositor *) output->base.compositor;
224 uint32_t width, height, stride, handle;
225 int ret;
226
227 if (fb)
228 return fb;
229
230 fb = malloc(sizeof *fb);
231
232 fb->bo = bo;
233 fb->output = output;
234 fb->is_client_buffer = 0;
235 fb->buffer = NULL;
236
237 width = gbm_bo_get_width(bo);
238 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400239 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300240 handle = gbm_bo_get_handle(bo).u32;
241
242 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
243 stride, handle, &fb->fb_id);
244 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200245 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300246 free(fb);
247 return NULL;
248 }
249
250 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
251
252 return fb;
253}
254
255static void
256fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
257{
258 struct drm_fb *fb = container_of(listener, struct drm_fb,
259 buffer_destroy_listener);
260
261 fb->buffer = NULL;
262
263 if (fb == fb->output->next ||
264 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400265 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300266}
267
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400268static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400269drm_output_prepare_scanout_surface(struct weston_output *_output,
270 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500271{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400272 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500273 struct drm_compositor *c =
274 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300275 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500276
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500277 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200278 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200279 es->geometry.width != output->base.current->width ||
280 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200281 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400282 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400283 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500284
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400285 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
286 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500287
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300288 /* Need to verify output->region contained in surface opaque
289 * region. Or maybe just that format doesn't have alpha.
290 * For now, scanout only if format is XRGB8888. */
291 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
292 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400293 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300294 }
295
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300296 output->next = drm_fb_get_from_bo(bo, output);
297 if (!output->next) {
298 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400299 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300300 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500301
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300302 output->next->is_client_buffer = 1;
303 output->next->buffer = es->buffer;
304 output->next->buffer->busy_count++;
305 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
306
307 wl_signal_add(&output->next->buffer->resource.destroy_signal,
308 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500309
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400310 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500311}
312
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500313static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400314drm_output_render(struct drm_output *output, pixman_region32_t *damage)
315{
316 struct drm_compositor *compositor =
317 (struct drm_compositor *) output->base.compositor;
318 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300319 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400320
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400321 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
322 output->egl_surface,
323 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200324 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400325 return;
326 }
327
328 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400329 if (surface->plane == &compositor->base.primary_plane)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400330 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400331
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400332 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600333
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400334 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300335 bo = gbm_surface_lock_front_buffer(output->surface);
336 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200337 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400338 return;
339 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300340
341 output->next = drm_fb_get_from_bo(bo, output);
342 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200343 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300344 gbm_surface_release_buffer(output->surface, bo);
345 return;
346 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400347}
348
349static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500350drm_output_repaint(struct weston_output *output_base,
351 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100352{
353 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500354 struct drm_compositor *compositor =
355 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500356 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400357 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500358 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100359
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300360 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400361 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400363 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100364
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400365 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400367 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300368 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400369 &output->connector_id, 1,
370 &mode->mode_info);
371 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200372 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400373 return;
374 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200375 }
376
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500377 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500379 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200380 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500381 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500382 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100383
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300384 output->page_flip_pending = 1;
385
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400386 drm_output_set_cursor(output);
387
Jesse Barnes58ef3792012-02-23 09:45:49 -0500388 /*
389 * Now, update all the sprite surfaces
390 */
391 wl_list_for_each(s, &compositor->sprite_list, link) {
392 uint32_t flags = 0;
393 drmVBlank vbl = {
394 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
395 .request.sequence = 1,
396 };
397
398 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
399 continue;
400
401 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
402 output->crtc_id, s->pending_fb_id, flags,
403 s->dest_x, s->dest_y,
404 s->dest_w, s->dest_h,
405 s->src_x, s->src_y,
406 s->src_w, s->src_h);
407 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200408 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500409 ret, strerror(errno));
410
Rob Clark5ca1a472012-08-08 20:27:37 -0500411 if (output->pipe > 0)
412 vbl.request.type |= DRM_VBLANK_SECONDARY;
413
Jesse Barnes58ef3792012-02-23 09:45:49 -0500414 /*
415 * Queue a vblank signal so we know when the surface
416 * becomes active on the display or has been replaced.
417 */
418 vbl.request.signal = (unsigned long)s;
419 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
420 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200421 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500422 ret, strerror(errno));
423 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300424
425 s->output = output;
426 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500427 }
428
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400429 drm_disable_unused_sprites(&output->base);
430
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500431 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400432}
433
434static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500435vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
436 void *data)
437{
438 struct drm_sprite *s = (struct drm_sprite *)data;
439 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300440 struct drm_output *output = s->output;
441 uint32_t msecs;
442
443 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500444
445 if (s->surface) {
446 weston_buffer_post_release(s->surface->buffer);
447 wl_list_remove(&s->destroy_listener.link);
448 s->surface = NULL;
449 drmModeRmFB(c->drm.fd, s->fb_id);
450 s->fb_id = 0;
451 }
452
453 if (s->pending_surface) {
454 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400455 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
456 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500457 s->surface = s->pending_surface;
458 s->pending_surface = NULL;
459 s->fb_id = s->pending_fb_id;
460 s->pending_fb_id = 0;
461 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300462
463 if (!output->page_flip_pending) {
464 msecs = sec * 1000 + usec / 1000;
465 weston_output_finish_frame(&output->base, msecs);
466 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500467}
468
469static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400470page_flip_handler(int fd, unsigned int frame,
471 unsigned int sec, unsigned int usec, void *data)
472{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200473 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400474 uint32_t msecs;
475
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300476 output->page_flip_pending = 0;
477
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300478 if (output->current) {
479 if (output->current->is_client_buffer)
480 gbm_bo_destroy(output->current->bo);
481 else
482 gbm_surface_release_buffer(output->surface,
483 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200484 }
485
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300486 output->current = output->next;
487 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400488
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300489 if (!output->vblank_pending) {
490 msecs = sec * 1000 + usec / 1000;
491 weston_output_finish_frame(&output->base, msecs);
492 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200493}
494
495static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500496drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
497{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400498 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500499
500 for (i = 0; i < s->count_formats; i++)
501 if (s->formats[i] == format)
502 return 1;
503
504 return 0;
505}
506
507static int
508drm_surface_transform_supported(struct weston_surface *es)
509{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400510 struct weston_matrix *matrix = &es->transform.matrix;
511 int i;
512
513 if (!es->transform.enabled)
514 return 1;
515
516 for (i = 0; i < 16; i++) {
517 switch (i) {
518 case 10:
519 case 15:
520 if (matrix->d[i] != 1.0)
521 return 0;
522 break;
523 case 0:
524 case 5:
525 case 12:
526 case 13:
527 break;
528 default:
529 if (matrix->d[i] != 0.0)
530 return 0;
531 break;
532 }
533 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500534
535 return 1;
536}
537
Jesse Barnes58ef3792012-02-23 09:45:49 -0500538static void
539drm_disable_unused_sprites(struct weston_output *output_base)
540{
541 struct weston_compositor *ec = output_base->compositor;
542 struct drm_compositor *c =(struct drm_compositor *) ec;
543 struct drm_output *output = (struct drm_output *) output_base;
544 struct drm_sprite *s;
545 int ret;
546
547 wl_list_for_each(s, &c->sprite_list, link) {
548 if (s->pending_fb_id)
549 continue;
550
551 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
552 output->crtc_id, 0, 0,
553 0, 0, 0, 0, 0, 0, 0, 0);
554 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200555 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500556 ret, strerror(errno));
557 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300558
559 if (s->surface) {
560 s->surface = NULL;
561 wl_list_remove(&s->destroy_listener.link);
562 }
563
564 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500565 s->fb_id = 0;
566 s->pending_fb_id = 0;
567 }
568}
569
570/*
571 * This function must take care to damage any previously assigned surface
572 * if the sprite ends up binding to a different surface than in the
573 * previous frame.
574 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400575static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500576drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400577 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578{
579 struct weston_compositor *ec = output_base->compositor;
580 struct drm_compositor *c =(struct drm_compositor *) ec;
581 struct drm_sprite *s;
582 int found = 0;
583 EGLint handle, stride;
584 struct gbm_bo *bo;
585 uint32_t fb_id = 0;
586 uint32_t handles[4], pitches[4], offsets[4];
587 int ret = 0;
588 pixman_region32_t dest_rect, src_rect;
589 pixman_box32_t *box;
590 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400591 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500592
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500593 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400594 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500595
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300596 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400597 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300598
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400599 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400600 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601
602 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400603 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 wl_list_for_each(s, &c->sprite_list, link) {
606 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
607 continue;
608
609 if (!s->pending_fb_id) {
610 found = 1;
611 break;
612 }
613 }
614
615 /* No sprites available */
616 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400617 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400619 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
620 es->buffer, GBM_BO_USE_SCANOUT);
621 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400622 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400623
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 format = gbm_bo_get_format(bo);
625 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400626 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627
628 gbm_bo_destroy(bo);
629
630 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400631 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632
633 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400634 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635
636 handles[0] = handle;
637 pitches[0] = stride;
638 offsets[0] = 0;
639
640 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
641 format, handles, pitches, offsets,
642 &fb_id, 0);
643 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200644 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500645 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400646 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 }
648
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649 s->pending_fb_id = fb_id;
650 s->pending_surface = es;
651 es->buffer->busy_count++;
652
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400653 box = pixman_region32_extents(&es->transform.boundingbox);
654 s->plane.x = box->x1;
655 s->plane.y = box->y1;
656
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657 /*
658 * Calculate the source & dest rects properly based on actual
659 * postion (note the caller has called weston_surface_update_transform()
660 * for us already).
661 */
662 pixman_region32_init(&dest_rect);
663 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
664 &output_base->region);
665 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
666 box = pixman_region32_extents(&dest_rect);
667 s->dest_x = box->x1;
668 s->dest_y = box->y1;
669 s->dest_w = box->x2 - box->x1;
670 s->dest_h = box->y2 - box->y1;
671 pixman_region32_fini(&dest_rect);
672
673 pixman_region32_init(&src_rect);
674 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
675 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500676 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400677
678 weston_surface_from_global_fixed(es,
679 wl_fixed_from_int(box->x1),
680 wl_fixed_from_int(box->y1),
681 &sx1, &sy1);
682 weston_surface_from_global_fixed(es,
683 wl_fixed_from_int(box->x2),
684 wl_fixed_from_int(box->y2),
685 &sx2, &sy2);
686
687 if (sx1 < 0)
688 sx1 = 0;
689 if (sy1 < 0)
690 sy1 = 0;
691 if (sx2 > wl_fixed_from_int(es->geometry.width))
692 sx2 = wl_fixed_from_int(es->geometry.width);
693 if (sy2 > wl_fixed_from_int(es->geometry.height))
694 sy2 = wl_fixed_from_int(es->geometry.height);
695
696 s->src_x = sx1 << 8;
697 s->src_y = sy1 << 8;
698 s->src_w = (sx2 - sx1) << 8;
699 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500700 pixman_region32_fini(&src_rect);
701
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400702 wl_signal_add(&es->buffer->resource.destroy_signal,
703 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400704
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400705 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706}
707
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400708static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400709drm_output_prepare_cursor_surface(struct weston_output *output_base,
710 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500711{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400712 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400713
714 if (output->cursor_surface)
715 return NULL;
716 if (es->output_mask != (1u << output_base->id))
717 return NULL;
718 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
719 es->geometry.width > 64 || es->geometry.height > 64)
720 return NULL;
721
722 output->cursor_surface = es;
723
724 return &output->cursor_plane;
725}
726
727static void
728drm_output_set_cursor(struct drm_output *output)
729{
730 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400731 struct drm_compositor *c =
732 (struct drm_compositor *) output->base.compositor;
733 EGLint handle, stride;
734 struct gbm_bo *bo;
735 uint32_t buf[64 * 64];
736 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400737 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500738
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400739 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400740 if (es == NULL) {
741 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
742 return;
743 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500744
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400745 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
746 pixman_region32_fini(&output->cursor_plane.damage);
747 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400748 output->current_cursor ^= 1;
749 bo = output->cursor_bo[output->current_cursor];
750 memset(buf, 0, sizeof buf);
751 stride = wl_shm_buffer_get_stride(es->buffer);
752 s = wl_shm_buffer_get_data(es->buffer);
753 for (i = 0; i < es->geometry.height; i++)
754 memcpy(buf + i * 64, s + i * stride,
755 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500756
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400757 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300758 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400759
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400760 handle = gbm_bo_get_handle(bo).s32;
761 if (drmModeSetCursor(c->drm.fd,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400762 output->crtc_id, handle, 64, 64))
Pekka Paalanenae29da22012-08-06 14:57:05 +0300763 weston_log("failed to set cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400764 }
765
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400766 x = es->geometry.x - output->base.x;
767 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400768 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
769 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y))
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400770 weston_log("failed to move cursor: %m\n");
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400771 output->cursor_plane.x = x;
772 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400773 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500774}
775
Jesse Barnes58ef3792012-02-23 09:45:49 -0500776static void
777drm_assign_planes(struct weston_output *output)
778{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400779 struct drm_compositor *c =
780 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400781 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500782 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400783 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500784
785 /*
786 * Find a surface for each sprite in the output using some heuristics:
787 * 1) size
788 * 2) frequency of update
789 * 3) opacity (though some hw might support alpha blending)
790 * 4) clipping (this can be fixed with color keys)
791 *
792 * The idea is to save on blitting since this should save power.
793 * If we can get a large video surface on the sprite for example,
794 * the main display surface may not need to update at all, and
795 * the client buffer can be used directly for the sprite surface
796 * as we do for flipping full screen surfaces.
797 */
798 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400799 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400800 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 pixman_region32_init(&surface_overlap);
802 pixman_region32_intersect(&surface_overlap, &overlap,
803 &es->transform.boundingbox);
804
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400805 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400806 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400807 next_plane = primary;
808 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400809 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 if (next_plane == NULL)
811 next_plane = drm_output_prepare_scanout_surface(output, es);
812 if (next_plane == NULL)
813 next_plane = drm_output_prepare_overlay_surface(output, es);
814 if (next_plane == NULL)
815 next_plane = primary;
816 weston_surface_move_to_plane(es, next_plane);
817 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818 pixman_region32_union(&overlap, &overlap,
819 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400820
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821 pixman_region32_fini(&surface_overlap);
822 }
823 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824}
825
Matt Roper361d2ad2011-08-29 13:52:23 -0700826static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500827drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700828{
829 struct drm_output *output = (struct drm_output *) output_base;
830 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200831 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700832 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700833
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200834 if (output->backlight)
835 backlight_destroy(output->backlight);
836
Matt Roper361d2ad2011-08-29 13:52:23 -0700837 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400838 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700839
840 /* Restore original CRTC state */
841 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200842 origcrtc->x, origcrtc->y,
843 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700844 drmModeFreeCrtc(origcrtc);
845
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200846 c->crtc_allocator &= ~(1 << output->crtc_id);
847 c->connector_allocator &= ~(1 << output->connector_id);
848
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400849 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400850 gbm_surface_destroy(output->surface);
851
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400852 weston_plane_release(&output->fb_plane);
853 weston_plane_release(&output->cursor_plane);
854
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500855 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200856 wl_list_remove(&output->base.link);
857
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400858 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700859 free(output);
860}
861
Alex Wub7b8bda2012-04-17 17:20:48 +0800862static struct drm_mode *
863choose_mode (struct drm_output *output, struct weston_mode *target_mode)
864{
865 struct drm_mode *tmp_mode = NULL, *mode;
866
867 if (output->base.current->width == target_mode->width &&
868 output->base.current->height == target_mode->height &&
869 (output->base.current->refresh == target_mode->refresh ||
870 target_mode->refresh == 0))
871 return (struct drm_mode *)output->base.current;
872
873 wl_list_for_each(mode, &output->base.mode_list, base.link) {
874 if (mode->mode_info.hdisplay == target_mode->width &&
875 mode->mode_info.vdisplay == target_mode->height) {
876 if (mode->mode_info.vrefresh == target_mode->refresh ||
877 target_mode->refresh == 0) {
878 return mode;
879 } else if (!tmp_mode)
880 tmp_mode = mode;
881 }
882 }
883
884 return tmp_mode;
885}
886
887static int
888drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
889{
890 struct drm_output *output;
891 struct drm_mode *drm_mode;
892 int ret;
893 struct drm_compositor *ec;
894 struct gbm_surface *surface;
895 EGLSurface egl_surface;
896
897 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200898 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800899 return -1;
900 }
901
902 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200903 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800904 return -1;
905 }
906
907 ec = (struct drm_compositor *)output_base->compositor;
908 output = (struct drm_output *)output_base;
909 drm_mode = choose_mode (output, mode);
910
911 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200912 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800913 return -1;
914 } else if (&drm_mode->base == output->base.current) {
915 return 0;
916 } else if (drm_mode->base.width == output->base.current->width &&
917 drm_mode->base.height == output->base.current->height) {
918 /* only change refresh value */
919 ret = drmModeSetCrtc(ec->drm.fd,
920 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300921 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800922 &output->connector_id, 1, &drm_mode->mode_info);
923
924 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200925 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800926 drm_mode->base.width,
927 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400928 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800929 ret = -1;
930 } else {
931 output->base.current->flags = 0;
932 output->base.current = &drm_mode->base;
933 drm_mode->base.flags =
934 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
935 ret = 0;
936 }
937
938 return ret;
939 }
940
941 drm_mode->base.flags =
942 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
943
944 surface = gbm_surface_create(ec->gbm,
945 drm_mode->base.width,
946 drm_mode->base.height,
947 GBM_FORMAT_XRGB8888,
948 GBM_BO_USE_SCANOUT |
949 GBM_BO_USE_RENDERING);
950 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200951 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800952 return -1;
953 }
954
955 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400956 eglCreateWindowSurface(ec->base.egl_display,
957 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800958 surface, NULL);
959
960 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200961 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800962 goto err;
963 }
964
965 ret = drmModeSetCrtc(ec->drm.fd,
966 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300967 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800968 &output->connector_id, 1, &drm_mode->mode_info);
969 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200970 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800971 goto err;
972 }
973
974 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300975 if (output->current) {
976 if (output->current->is_client_buffer)
977 gbm_bo_destroy(output->current->bo);
978 else
979 gbm_surface_release_buffer(output->surface,
980 output->current->bo);
981 }
982 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800983
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300984 if (output->next) {
985 if (output->next->is_client_buffer)
986 gbm_bo_destroy(output->next->bo);
987 else
988 gbm_surface_release_buffer(output->surface,
989 output->next->bo);
990 }
991 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800992
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400993 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800994 gbm_surface_destroy(output->surface);
995 output->egl_surface = egl_surface;
996 output->surface = surface;
997
998 /*update output*/
999 output->base.current = &drm_mode->base;
1000 output->base.dirty = 1;
1001 weston_output_move(&output->base, output->base.x, output->base.y);
1002 return 0;
1003
1004err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001005 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001006 gbm_surface_destroy(surface);
1007 return -1;
1008}
1009
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001010static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001011on_drm_input(int fd, uint32_t mask, void *data)
1012{
1013 drmEventContext evctx;
1014
1015 memset(&evctx, 0, sizeof evctx);
1016 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1017 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001018 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001019 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001020
1021 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001022}
1023
1024static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001025init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001026{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001027 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001028 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001029 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001030 static const EGLint context_attribs[] = {
1031 EGL_CONTEXT_CLIENT_VERSION, 2,
1032 EGL_NONE
1033 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001034
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001035 static const EGLint config_attribs[] = {
1036 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1037 EGL_RED_SIZE, 1,
1038 EGL_GREEN_SIZE, 1,
1039 EGL_BLUE_SIZE, 1,
1040 EGL_ALPHA_SIZE, 0,
1041 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1042 EGL_NONE
1043 };
1044
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001045 sysnum = udev_device_get_sysnum(device);
1046 if (sysnum)
1047 ec->drm.id = atoi(sysnum);
1048 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001049 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001050 return -1;
1051 }
1052
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001053 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001054 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001055 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001056 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001057 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001058 udev_device_get_devnode(device));
1059 return -1;
1060 }
1061
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001062 weston_log("using %s\n", filename);
1063
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001064 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001065 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001066 ec->base.egl_display = eglGetDisplay(ec->gbm);
1067 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001068 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001069 return -1;
1070 }
1071
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001072 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001073 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001074 return -1;
1075 }
1076
Darxus55973f22010-11-22 21:24:39 -05001077 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001078 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001079 return -1;
1080 }
1081
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001082 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1083 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001084 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001085 return -1;
1086 }
1087
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001088 ec->base.egl_context =
1089 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1090 EGL_NO_CONTEXT, context_attribs);
1091 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001092 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001093 return -1;
1094 }
1095
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001096 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1097 GBM_FORMAT_XRGB8888,
1098 GBM_BO_USE_RENDERING);
1099 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001100 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001101 return -1;
1102 }
1103
1104 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001105 eglCreateWindowSurface(ec->base.egl_display,
1106 ec->base.egl_config,
1107 ec->dummy_surface,
1108 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001109 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001110 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001111 return -1;
1112 }
1113
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001114 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1115 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001116 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001117 return -1;
1118 }
1119
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001120 return 0;
1121}
1122
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001123static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001124drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1125{
1126 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001127 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001128
1129 mode = malloc(sizeof *mode);
1130 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001131 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001132
1133 mode->base.flags = 0;
1134 mode->base.width = info->hdisplay;
1135 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001136
1137 /* Calculate higher precision (mHz) refresh rate */
1138 refresh = (info->clock * 1000000LL / info->htotal +
1139 info->vtotal / 2) / info->vtotal;
1140
1141 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1142 refresh *= 2;
1143 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1144 refresh /= 2;
1145 if (info->vscan > 1)
1146 refresh /= info->vscan;
1147
1148 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001149 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001150
1151 if (info->type & DRM_MODE_TYPE_PREFERRED)
1152 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1153
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001154 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1155
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001156 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001157}
1158
1159static int
1160drm_subpixel_to_wayland(int drm_value)
1161{
1162 switch (drm_value) {
1163 default:
1164 case DRM_MODE_SUBPIXEL_UNKNOWN:
1165 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1166 case DRM_MODE_SUBPIXEL_NONE:
1167 return WL_OUTPUT_SUBPIXEL_NONE;
1168 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1169 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1170 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1171 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1172 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1173 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1174 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1175 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1176 }
1177}
1178
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001179static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001180sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001181{
1182 struct drm_sprite *sprite =
1183 container_of(listener, struct drm_sprite,
1184 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001185 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001186
1187 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001188 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1189 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001190}
1191
1192static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001193sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001194{
1195 struct drm_sprite *sprite =
1196 container_of(listener, struct drm_sprite,
1197 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001198 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001199
1200 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001201 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1202 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001203}
1204
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001205/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001206static uint32_t
1207drm_get_backlight(struct drm_output *output)
1208{
1209 long brightness, max_brightness, norm;
1210
1211 brightness = backlight_get_brightness(output->backlight);
1212 max_brightness = backlight_get_max_brightness(output->backlight);
1213
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001214 /* convert it on a scale of 0 to 255 */
1215 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001216
1217 return (uint32_t) norm;
1218}
1219
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001220/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001221static void
1222drm_set_backlight(struct weston_output *output_base, uint32_t value)
1223{
1224 struct drm_output *output = (struct drm_output *) output_base;
1225 long max_brightness, new_brightness;
1226
1227 if (!output->backlight)
1228 return;
1229
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001230 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001231 return;
1232
1233 max_brightness = backlight_get_max_brightness(output->backlight);
1234
1235 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001236 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001237
1238 backlight_set_brightness(output->backlight, new_brightness);
1239}
1240
1241static drmModePropertyPtr
1242drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1243{
1244 drmModePropertyPtr props;
1245 int i;
1246
1247 for (i = 0; i < connector->count_props; i++) {
1248 props = drmModeGetProperty(fd, connector->props[i]);
1249 if (!props)
1250 continue;
1251
1252 if (!strcmp(props->name, name))
1253 return props;
1254
1255 drmModeFreeProperty(props);
1256 }
1257
1258 return NULL;
1259}
1260
1261static void
1262drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1263{
1264 struct drm_output *output = (struct drm_output *) output_base;
1265 struct weston_compositor *ec = output_base->compositor;
1266 struct drm_compositor *c = (struct drm_compositor *) ec;
1267 drmModeConnectorPtr connector;
1268 drmModePropertyPtr prop;
1269
1270 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1271 if (!connector)
1272 return;
1273
1274 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1275 if (!prop) {
1276 drmModeFreeConnector(connector);
1277 return;
1278 }
1279
1280 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1281 prop->prop_id, level);
1282 drmModeFreeProperty(prop);
1283 drmModeFreeConnector(connector);
1284}
1285
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001286static const char *connector_type_names[] = {
1287 "None",
1288 "VGA",
1289 "DVI",
1290 "DVI",
1291 "DVI",
1292 "Composite",
1293 "TV",
1294 "LVDS",
1295 "CTV",
1296 "DIN",
1297 "DP",
1298 "HDMI",
1299 "HDMI",
1300 "TV",
1301 "eDP",
1302};
1303
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001304static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001305find_crtc_for_connector(struct drm_compositor *ec,
1306 drmModeRes *resources, drmModeConnector *connector)
1307{
1308 drmModeEncoder *encoder;
1309 uint32_t possible_crtcs;
1310 int i, j;
1311
1312 for (j = 0; j < connector->count_encoders; j++) {
1313 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1314 if (encoder == NULL) {
1315 weston_log("Failed to get encoder.\n");
1316 return -1;
1317 }
1318 possible_crtcs = encoder->possible_crtcs;
1319 drmModeFreeEncoder(encoder);
1320
1321 for (i = 0; i < resources->count_crtcs; i++) {
1322 if (possible_crtcs & (1 << i) &&
1323 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1324 return i;
1325 }
1326 }
1327
1328 return -1;
1329}
1330
1331static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001332create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001333 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001334 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001335 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001336{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001337 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001338 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1339 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001340 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001341 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001342 drmModeModeInfo crtc_mode;
1343 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001344 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001345 char name[32];
1346 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001347
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001348 i = find_crtc_for_connector(ec, resources, connector);
1349 if (i < 0) {
1350 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001351 return -1;
1352 }
1353
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001354 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001355 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001356 return -1;
1357
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001358 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001359 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1360 output->base.make = "unknown";
1361 output->base.model = "unknown";
1362 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001363
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001364 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1365 type_name = connector_type_names[connector->connector_type];
1366 else
1367 type_name = "UNKNOWN";
1368 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1369 output->name = strdup(name);
1370
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001371 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001372 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001373 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001374 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001375 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001376
Matt Roper361d2ad2011-08-29 13:52:23 -07001377 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1378
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001379 /* Get the current mode on the crtc that's currently driving
1380 * this connector. */
1381 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001382 memset(&crtc_mode, 0, sizeof crtc_mode);
1383 if (encoder != NULL) {
1384 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1385 drmModeFreeEncoder(encoder);
1386 if (crtc == NULL)
1387 goto err_free;
1388 if (crtc->mode_valid)
1389 crtc_mode = crtc->mode;
1390 drmModeFreeCrtc(crtc);
1391 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001392
David Herrmann0f0d54e2011-12-08 17:05:45 +01001393 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001394 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1395 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001396 goto err_free;
1397 }
1398
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001399 preferred = NULL;
1400 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001401 configured = NULL;
1402
1403 wl_list_for_each(temp, &configured_output_list, link) {
1404 if (strcmp(temp->name, output->name) == 0) {
1405 weston_log("%s mode \"%s\" in config\n",
1406 temp->name, temp->mode);
1407 o = temp;
1408 break;
1409 }
1410 }
1411
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001412 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001413 weston_log("Disabling output %s\n", o->name);
1414
1415 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1416 0, 0, 0, 0, 0, NULL);
1417 goto err_free;
1418 }
1419
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001421 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001422 o->height == drm_mode->base.height &&
1423 o->config == OUTPUT_CONFIG_MODE)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001424 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001425 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001426 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001427 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001428 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001429 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001430
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001431 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001432 configured = drm_output_add_mode(output, &o->crtc_mode);
1433 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001434 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001435 current = configured;
1436 }
1437
Wang Quanxianacb805a2012-07-30 18:09:46 -04001438 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001439 current = drm_output_add_mode(output, &crtc_mode);
1440 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001441 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001442 }
1443
Scott Moreau8ab5d452012-07-30 19:51:08 -06001444 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1445 configured = current;
1446
Wang Quanxianacb805a2012-07-30 18:09:46 -04001447 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001448 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001449 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001450 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001451 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001452 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001453 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001454 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001455
1456 if (output->base.current == NULL) {
1457 weston_log("no available modes for %s\n", output->name);
1458 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001459 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001460
Wang Quanxianacb805a2012-07-30 18:09:46 -04001461 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1462
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001463 output->surface = gbm_surface_create(ec->gbm,
1464 output->base.current->width,
1465 output->base.current->height,
1466 GBM_FORMAT_XRGB8888,
1467 GBM_BO_USE_SCANOUT |
1468 GBM_BO_USE_RENDERING);
1469 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001470 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001471 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001472 }
1473
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001474 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001475 eglCreateWindowSurface(ec->base.egl_display,
1476 ec->base.egl_config,
1477 output->surface,
1478 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001479 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001480 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001481 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001482 }
1483
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001484 output->cursor_bo[0] =
1485 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1486 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1487 output->cursor_bo[1] =
1488 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1489 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1490
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001491 output->backlight = backlight_init(drm_device,
1492 connector->connector_type);
1493 if (output->backlight) {
1494 output->base.set_backlight = drm_set_backlight;
1495 output->base.backlight_current = drm_get_backlight(output);
1496 }
1497
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001498 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001499 connector->mmWidth, connector->mmHeight,
1500 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001501
1502 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1503
Alex Wubd3354b2012-04-17 17:20:49 +08001504 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001505 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001506 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001507 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001508 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001509 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001510
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001511 weston_plane_init(&output->cursor_plane, 0, 0);
1512 weston_plane_init(&output->fb_plane, 0, 0);
1513
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001514 weston_log("Output %s, (connector %d, crtc %d)\n",
1515 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001516 wl_list_for_each(m, &output->base.mode_list, link)
1517 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1518 m->width, m->height, m->refresh / 1000.0,
1519 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1520 ", preferred" : "",
1521 m->flags & WL_OUTPUT_MODE_CURRENT ?
1522 ", current" : "",
1523 connector->count_modes == 0 ?
1524 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001525
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001526 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001527
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001528err_surface:
1529 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001530err_free:
1531 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1532 base.link) {
1533 wl_list_remove(&drm_mode->base.link);
1534 free(drm_mode);
1535 }
1536
1537 drmModeFreeCrtc(output->original_crtc);
1538 ec->crtc_allocator &= ~(1 << output->crtc_id);
1539 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001540 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001541 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001542
David Herrmann0f0d54e2011-12-08 17:05:45 +01001543 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001544}
1545
Jesse Barnes58ef3792012-02-23 09:45:49 -05001546static void
1547create_sprites(struct drm_compositor *ec)
1548{
1549 struct drm_sprite *sprite;
1550 drmModePlaneRes *plane_res;
1551 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001552 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001553
1554 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1555 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001556 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001557 strerror(errno));
1558 return;
1559 }
1560
1561 for (i = 0; i < plane_res->count_planes; i++) {
1562 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1563 if (!plane)
1564 continue;
1565
1566 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1567 plane->count_formats));
1568 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001569 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001570 __func__);
1571 free(plane);
1572 continue;
1573 }
1574
1575 memset(sprite, 0, sizeof *sprite);
1576
1577 sprite->possible_crtcs = plane->possible_crtcs;
1578 sprite->plane_id = plane->plane_id;
1579 sprite->surface = NULL;
1580 sprite->pending_surface = NULL;
1581 sprite->fb_id = 0;
1582 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001583 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1584 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001585 sprite_handle_pending_buffer_destroy;
1586 sprite->compositor = ec;
1587 sprite->count_formats = plane->count_formats;
1588 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001589 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001590 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001591 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001592
1593 wl_list_insert(&ec->sprite_list, &sprite->link);
1594 }
1595
1596 free(plane_res->planes);
1597 free(plane_res);
1598}
1599
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001600static void
1601destroy_sprites(struct drm_compositor *compositor)
1602{
1603 struct drm_sprite *sprite, *next;
1604 struct drm_output *output;
1605
1606 output = container_of(compositor->base.output_list.next,
1607 struct drm_output, base.link);
1608
1609 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1610 drmModeSetPlane(compositor->drm.fd,
1611 sprite->plane_id,
1612 output->crtc_id, 0, 0,
1613 0, 0, 0, 0, 0, 0, 0, 0);
1614 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001615 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001616 free(sprite);
1617 }
1618}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001619
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001620static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001621create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001622 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001623{
1624 drmModeConnector *connector;
1625 drmModeRes *resources;
1626 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001627 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001628
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001629 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001630 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001631 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001632 return -1;
1633 }
1634
Jesse Barnes58ef3792012-02-23 09:45:49 -05001635 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001636 if (!ec->crtcs) {
1637 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001638 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001639 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001640
1641 ec->num_crtcs = resources->count_crtcs;
1642 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1643
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001644 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001645 connector = drmModeGetConnector(ec->drm.fd,
1646 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001647 if (connector == NULL)
1648 continue;
1649
1650 if (connector->connection == DRM_MODE_CONNECTED &&
1651 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001652 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001653 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001654 connector, x, y,
1655 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001656 drmModeFreeConnector(connector);
1657 continue;
1658 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001659
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001660 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001661 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001662 link)->current->width;
1663 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001664
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001665 drmModeFreeConnector(connector);
1666 }
1667
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001668 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001669 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001670 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001671 return -1;
1672 }
1673
1674 drmModeFreeResources(resources);
1675
1676 return 0;
1677}
1678
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001679static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001680update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001681{
1682 drmModeConnector *connector;
1683 drmModeRes *resources;
1684 struct drm_output *output, *next;
1685 int x = 0, y = 0;
1686 int x_offset = 0, y_offset = 0;
1687 uint32_t connected = 0, disconnects = 0;
1688 int i;
1689
1690 resources = drmModeGetResources(ec->drm.fd);
1691 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001692 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001693 return;
1694 }
1695
1696 /* collect new connects */
1697 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001698 int connector_id = resources->connectors[i];
1699
1700 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001701 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001702 continue;
1703
David Herrmann7551cff2011-12-08 17:05:43 +01001704 if (connector->connection != DRM_MODE_CONNECTED) {
1705 drmModeFreeConnector(connector);
1706 continue;
1707 }
1708
Benjamin Franzke117483d2011-08-30 11:38:26 +02001709 connected |= (1 << connector_id);
1710
1711 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001712 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001713 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001714 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001715
1716 /* XXX: not yet needed, we die with 0 outputs */
1717 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001718 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001719 else
1720 x = 0;
1721 y = 0;
1722 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001723 connector, x, y,
1724 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001725 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001726
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001727 }
1728 drmModeFreeConnector(connector);
1729 }
1730 drmModeFreeResources(resources);
1731
1732 disconnects = ec->connector_allocator & ~connected;
1733 if (disconnects) {
1734 wl_list_for_each_safe(output, next, &ec->base.output_list,
1735 base.link) {
1736 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001737 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001738 output->base.x - x_offset,
1739 output->base.y - y_offset);
1740 }
1741
1742 if (disconnects & (1 << output->connector_id)) {
1743 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001744 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001745 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001746 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001747 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001748 }
1749 }
1750 }
1751
1752 /* FIXME: handle zero outputs, without terminating */
1753 if (ec->connector_allocator == 0)
1754 wl_display_terminate(ec->base.wl_display);
1755}
1756
1757static int
David Herrmannd7488c22012-03-11 20:05:21 +01001758udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001759{
David Herrmannd7488c22012-03-11 20:05:21 +01001760 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001761 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001762
1763 sysnum = udev_device_get_sysnum(device);
1764 if (!sysnum || atoi(sysnum) != ec->drm.id)
1765 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001766
David Herrmann6ac52db2012-03-11 20:05:22 +01001767 val = udev_device_get_property_value(device, "HOTPLUG");
1768 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001769 return 0;
1770
David Herrmann6ac52db2012-03-11 20:05:22 +01001771 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001772}
1773
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001774static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001775udev_drm_event(int fd, uint32_t mask, void *data)
1776{
1777 struct drm_compositor *ec = data;
1778 struct udev_device *event;
1779
1780 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001781
David Herrmannd7488c22012-03-11 20:05:21 +01001782 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001783 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001784
1785 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001786
1787 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001788}
1789
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001790static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001791drm_restore(struct weston_compositor *ec)
1792{
1793 struct drm_compositor *d = (struct drm_compositor *) ec;
1794
1795 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1796 weston_log("failed to drop master: %m\n");
1797 tty_reset(d->tty);
1798}
1799
Pekka Paalanen33156972012-08-03 13:30:30 -04001800static const char default_seat[] = "seat0";
1801
1802static void
1803device_added(struct udev_device *udev_device, struct drm_seat *master)
1804{
1805 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001806 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001807 const char *devnode;
1808 const char *device_seat;
1809 int fd;
1810
1811 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1812 if (!device_seat)
1813 device_seat = default_seat;
1814
1815 if (strcmp(device_seat, master->seat_id))
1816 return;
1817
1818 c = master->base.compositor;
1819 devnode = udev_device_get_devnode(udev_device);
1820
1821 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001822 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001823 * read. mtdev_get() also expects this. */
1824 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1825 if (fd < 0) {
1826 weston_log("opening input device '%s' failed.\n", devnode);
1827 return;
1828 }
1829
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001830 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001831 if (!device) {
1832 close(fd);
1833 weston_log("not using input device '%s'.\n", devnode);
1834 return;
1835 }
1836
1837 wl_list_insert(master->devices_list.prev, &device->link);
1838}
1839
1840static void
1841evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1842{
1843 struct drm_seat *seat = (struct drm_seat *) seat_base;
1844 struct udev_enumerate *e;
1845 struct udev_list_entry *entry;
1846 struct udev_device *device;
1847 const char *path, *sysname;
1848
1849 e = udev_enumerate_new(udev);
1850 udev_enumerate_add_match_subsystem(e, "input");
1851 udev_enumerate_scan_devices(e);
1852 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1853 path = udev_list_entry_get_name(entry);
1854 device = udev_device_new_from_syspath(udev, path);
1855
1856 sysname = udev_device_get_sysname(device);
1857 if (strncmp("event", sysname, 5) != 0) {
1858 udev_device_unref(device);
1859 continue;
1860 }
1861
1862 device_added(device, seat);
1863
1864 udev_device_unref(device);
1865 }
1866 udev_enumerate_unref(e);
1867
1868 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1869
1870 if (wl_list_empty(&seat->devices_list)) {
1871 weston_log(
1872 "warning: no input devices on entering Weston. "
1873 "Possible causes:\n"
1874 "\t- no permissions to read /dev/input/event*\n"
1875 "\t- seats misconfigured "
1876 "(Weston backend option 'seat', "
1877 "udev device property ID_SEAT)\n");
1878 }
1879}
1880
1881static int
1882evdev_udev_handler(int fd, uint32_t mask, void *data)
1883{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001884 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001885 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001886 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001887 const char *action;
1888 const char *devnode;
1889
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001890 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001891 if (!udev_device)
1892 return 1;
1893
1894 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001895 if (!action)
1896 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001897
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001898 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1899 goto out;
1900
1901 if (!strcmp(action, "add")) {
1902 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001903 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001904 else if (!strcmp(action, "remove")) {
1905 devnode = udev_device_get_devnode(udev_device);
1906 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1907 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001908 weston_log("input device %s, %s removed\n",
1909 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001910 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001911 break;
1912 }
1913 }
1914
1915out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001916 udev_device_unref(udev_device);
1917
1918 return 0;
1919}
1920
1921static int
1922evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1923{
1924 struct drm_seat *master = (struct drm_seat *) seat_base;
1925 struct wl_event_loop *loop;
1926 struct weston_compositor *c = master->base.compositor;
1927 int fd;
1928
1929 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1930 if (!master->udev_monitor) {
1931 weston_log("udev: failed to create the udev monitor\n");
1932 return 0;
1933 }
1934
1935 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1936 "input", NULL);
1937
1938 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1939 weston_log("udev: failed to bind the udev monitor\n");
1940 udev_monitor_unref(master->udev_monitor);
1941 return 0;
1942 }
1943
1944 loop = wl_display_get_event_loop(c->wl_display);
1945 fd = udev_monitor_get_fd(master->udev_monitor);
1946 master->udev_monitor_source =
1947 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1948 evdev_udev_handler, master);
1949 if (!master->udev_monitor_source) {
1950 udev_monitor_unref(master->udev_monitor);
1951 return 0;
1952 }
1953
1954 return 1;
1955}
1956
1957static void
1958evdev_disable_udev_monitor(struct weston_seat *seat_base)
1959{
1960 struct drm_seat *seat = (struct drm_seat *) seat_base;
1961
1962 if (!seat->udev_monitor)
1963 return;
1964
1965 udev_monitor_unref(seat->udev_monitor);
1966 seat->udev_monitor = NULL;
1967 wl_event_source_remove(seat->udev_monitor_source);
1968 seat->udev_monitor_source = NULL;
1969}
1970
1971static void
1972drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1973{
1974 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001975 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001976
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001977 wl_list_for_each(device, &seat->devices_list, link)
1978 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001979}
1980
1981static void
1982evdev_input_create(struct weston_compositor *c, struct udev *udev,
1983 const char *seat_id)
1984{
1985 struct drm_seat *seat;
1986
1987 seat = malloc(sizeof *seat);
1988 if (seat == NULL)
1989 return;
1990
1991 memset(seat, 0, sizeof *seat);
1992 weston_seat_init(&seat->base, c);
1993 seat->base.led_update = drm_led_update;
1994
1995 wl_list_init(&seat->devices_list);
1996 seat->seat_id = strdup(seat_id);
1997 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1998 free(seat->seat_id);
1999 free(seat);
2000 return;
2001 }
2002
2003 evdev_add_devices(udev, &seat->base);
2004
2005 c->seat = &seat->base;
2006}
2007
2008static void
2009evdev_remove_devices(struct weston_seat *seat_base)
2010{
2011 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002012 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002013
2014 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002015 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002016
Pekka Paalanend8583512012-08-03 14:39:11 +03002017 if (seat->base.seat.keyboard)
2018 notify_keyboard_focus_out(&seat->base.seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002019}
2020
2021static void
2022evdev_input_destroy(struct weston_seat *seat_base)
2023{
2024 struct drm_seat *seat = (struct drm_seat *) seat_base;
2025
2026 evdev_remove_devices(seat_base);
2027 evdev_disable_udev_monitor(&seat->base);
2028
2029 weston_seat_release(seat_base);
2030 free(seat->seat_id);
2031 free(seat);
2032}
2033
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002034static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002035drm_free_configured_output(struct drm_configured_output *output)
2036{
2037 free(output->name);
2038 free(output->mode);
2039 free(output);
2040}
2041
2042static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002043drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002044{
2045 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002046 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002047 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002048
Daniel Stone37816df2012-05-16 18:45:18 +01002049 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2050 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002051 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002052 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002053
2054 wl_event_source_remove(d->udev_drm_source);
2055 wl_event_source_remove(d->drm_source);
2056
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002057 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002058
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002059 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002060 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002061 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002062 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002063 eglReleaseThread();
2064
Matt Roper361d2ad2011-08-29 13:52:23 -07002065 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002066 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002067 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002068 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002069 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002070
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002071 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002072}
2073
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002074static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002075drm_compositor_set_modes(struct drm_compositor *compositor)
2076{
2077 struct drm_output *output;
2078 struct drm_mode *drm_mode;
2079 int ret;
2080
2081 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2082 drm_mode = (struct drm_mode *) output->base.current;
2083 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002084 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002085 &output->connector_id, 1,
2086 &drm_mode->mode_info);
2087 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002088 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002089 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002090 drm_mode->base.width, drm_mode->base.height,
2091 output->base.x, output->base.y);
2092 }
2093 }
2094}
2095
2096static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002097vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002098{
2099 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002100 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002101 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002102 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002103
2104 switch (event) {
2105 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002106 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002107 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002108 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002109 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002110 wl_display_terminate(compositor->wl_display);
2111 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002112 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002113 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002114 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002115 wl_list_for_each(seat, &compositor->seat_list, link) {
2116 evdev_add_devices(ec->udev, seat);
2117 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002118 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002119 break;
2120 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002121 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002122 wl_list_for_each(seat, &compositor->seat_list, link) {
2123 evdev_disable_udev_monitor(seat);
2124 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002125 }
2126
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002127 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002128 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002129 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002130
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002131 /* If we have a repaint scheduled (either from a
2132 * pending pageflip or the idle handler), make sure we
2133 * cancel that so we don't try to pageflip when we're
2134 * vt switched away. The SLEEPING state will prevent
2135 * further attemps at repainting. When we switch
2136 * back, we schedule a repaint, which will process
2137 * pending frame callbacks. */
2138
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002139 wl_list_for_each(output, &ec->base.output_list, base.link) {
2140 output->base.repaint_needed = 0;
2141 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002142 }
2143
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002144 output = container_of(ec->base.output_list.next,
2145 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002146
2147 wl_list_for_each(sprite, &ec->sprite_list, link)
2148 drmModeSetPlane(ec->drm.fd,
2149 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002150 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002151 0, 0, 0, 0, 0, 0, 0, 0);
2152
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002153 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002154 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002155
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002156 break;
2157 };
2158}
2159
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002160static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002161switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002162{
2163 struct drm_compositor *ec = data;
2164
Daniel Stone325fc2d2012-05-30 16:31:58 +01002165 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002166}
2167
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002168static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002169drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002170 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002171 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002172{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002173 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002174 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002175 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002176 struct udev_device *device, *drm_device;
2177 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002178 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002179 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002180 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002181
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002182 weston_log("initializing drm backend\n");
2183
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002184 ec = malloc(sizeof *ec);
2185 if (ec == NULL)
2186 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002187 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002188
2189 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002190 config_file) < 0) {
2191 weston_log("weston_compositor_init failed\n");
2192 goto err_base;
2193 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002194
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002195 ec->udev = udev_new();
2196 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002197 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002198 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002199 }
2200
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002201 ec->base.wl_display = display;
2202 ec->tty = tty_create(&ec->base, vt_func, tty);
2203 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002204 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002205 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002206 }
2207
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002208 e = udev_enumerate_new(ec->udev);
2209 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002210 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002211
Benjamin Franzke117483d2011-08-30 11:38:26 +02002212 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002213 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002214 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002215 path = udev_list_entry_get_name(entry);
2216 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002217 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002218 udev_device_get_property_value(device, "ID_SEAT");
2219 if (!device_seat)
2220 device_seat = default_seat;
2221 if (strcmp(device_seat, seat) == 0) {
2222 drm_device = device;
2223 break;
2224 }
2225 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002226 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002227
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002228 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002229 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002230 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002231 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002232
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002233 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002234 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002235 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002236 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002237
2238 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002239 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002240
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002241 ec->base.focus = 1;
2242
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002243 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002244
Daniel Stone725c2c32012-06-22 14:04:36 +01002245 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002246 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002247
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002248 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002249 weston_compositor_add_key_binding(&ec->base, key,
2250 MODIFIER_CTRL | MODIFIER_ALT,
2251 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002252
Jesse Barnes58ef3792012-02-23 09:45:49 -05002253 wl_list_init(&ec->sprite_list);
2254 create_sprites(ec);
2255
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002256 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002257 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002258 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002259 }
2260
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002261 path = NULL;
2262
Tiago Vignattice03ec32011-12-19 01:14:03 +02002263 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002264
2265 loop = wl_display_get_event_loop(ec->base.wl_display);
2266 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002267 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002268 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002269
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002270 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2271 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002272 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002273 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002274 }
2275 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2276 "drm", NULL);
2277 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002278 wl_event_loop_add_fd(loop,
2279 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002280 WL_EVENT_READABLE, udev_drm_event, ec);
2281
2282 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002283 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002284 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002285 }
2286
Daniel Stonea96b93c2012-06-22 14:04:37 +01002287 udev_device_unref(drm_device);
2288 udev_enumerate_unref(e);
2289
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002290 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002291
2292err_udev_monitor:
2293 wl_event_source_remove(ec->udev_drm_source);
2294 udev_monitor_unref(ec->udev_monitor);
2295err_drm_source:
2296 wl_event_source_remove(ec->drm_source);
2297 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2298 evdev_input_destroy(weston_seat);
2299err_sprite:
2300 destroy_sprites(ec);
2301err_egl:
2302 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2303 EGL_NO_CONTEXT);
2304 eglTerminate(ec->base.egl_display);
2305 eglReleaseThread();
2306 gbm_device_destroy(ec->gbm);
2307err_udev_dev:
2308 udev_device_unref(drm_device);
2309err_udev_enum:
2310 udev_enumerate_unref(e);
2311 tty_destroy(ec->tty);
2312err_udev:
2313 udev_unref(ec->udev);
2314err_compositor:
2315 weston_compositor_shutdown(&ec->base);
2316err_base:
2317 free(ec);
2318 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002319}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002320
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002321static int
2322set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2323{
2324 mode->flags = 0;
2325
2326 if (strcmp(hsync, "+hsync") == 0)
2327 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2328 else if (strcmp(hsync, "-hsync") == 0)
2329 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2330 else
2331 return -1;
2332
2333 if (strcmp(vsync, "+vsync") == 0)
2334 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2335 else if (strcmp(vsync, "-vsync") == 0)
2336 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2337 else
2338 return -1;
2339
2340 return 0;
2341}
2342
2343static int
2344check_for_modeline(struct drm_configured_output *output)
2345{
2346 drmModeModeInfo mode;
2347 char hsync[16];
2348 char vsync[16];
2349 char mode_name[16];
2350 float fclock;
2351
2352 mode.type = DRM_MODE_TYPE_USERDEF;
2353 mode.hskew = 0;
2354 mode.vscan = 0;
2355 mode.vrefresh = 0;
2356
2357 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2358 &fclock, &mode.hdisplay,
2359 &mode.hsync_start,
2360 &mode.hsync_end, &mode.htotal,
2361 &mode.vdisplay,
2362 &mode.vsync_start,
2363 &mode.vsync_end, &mode.vtotal,
2364 hsync, vsync) == 11) {
2365 if (set_sync_flags(&mode, hsync, vsync))
2366 return -1;
2367
2368 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2369 strcpy(mode.name, mode_name);
2370
2371 mode.clock = fclock * 1000;
2372 } else
2373 return -1;
2374
2375 output->crtc_mode = mode;
2376
2377 return 0;
2378}
2379
Scott Moreau8ab5d452012-07-30 19:51:08 -06002380static void
2381output_section_done(void *data)
2382{
2383 struct drm_configured_output *output;
2384
2385 output = malloc(sizeof *output);
2386
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002387 if (!output || !output_name || !output_mode) {
2388 free(output_name);
2389 output_name = NULL;
2390 free(output_mode);
2391 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002392 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002393 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002394
2395 output->config = OUTPUT_CONFIG_INVALID;
2396 output->name = output_name;
2397 output->mode = output_mode;
2398
2399 if (strcmp(output_mode, "off") == 0)
2400 output->config = OUTPUT_CONFIG_OFF;
2401 else if (strcmp(output_mode, "preferred") == 0)
2402 output->config = OUTPUT_CONFIG_PREFERRED;
2403 else if (strcmp(output_mode, "current") == 0)
2404 output->config = OUTPUT_CONFIG_CURRENT;
2405 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2406 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002407 else if (check_for_modeline(output) == 0)
2408 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002409
2410 if (output->config != OUTPUT_CONFIG_INVALID)
2411 wl_list_insert(&configured_output_list, &output->link);
2412 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002413 weston_log("Invalid mode \"%s\" for output %s\n",
2414 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002415 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002416 }
2417}
2418
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002419WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002420backend_init(struct wl_display *display, int argc, char *argv[],
2421 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002422{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002423 int connector = 0, tty = 0;
2424 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002425
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002426 const struct weston_option drm_options[] = {
2427 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2428 { WESTON_OPTION_STRING, "seat", 0, &seat },
2429 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002430 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002431 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002432
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002433 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002434
Scott Moreau8ab5d452012-07-30 19:51:08 -06002435 wl_list_init(&configured_output_list);
2436
2437 const struct config_key drm_config_keys[] = {
2438 { "name", CONFIG_KEY_STRING, &output_name },
2439 { "mode", CONFIG_KEY_STRING, &output_mode },
2440 };
2441
2442 const struct config_section config_section[] = {
2443 { "output", drm_config_keys,
2444 ARRAY_LENGTH(drm_config_keys), output_section_done },
2445 };
2446
2447 parse_config_file(config_file, config_section,
2448 ARRAY_LENGTH(config_section), NULL);
2449
Daniel Stonec1be8e52012-06-01 11:14:02 -04002450 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2451 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002452}