blob: afed9fe005747ce768a04dc9cec9e427528a3a3a [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>
Benjamin Franzke060cf802011-04-30 09:32:11 +020040
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040041#include "compositor.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020042#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010043#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040044
Kristian Høgsberg061c4252012-06-28 11:28:15 -040045static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060046static char *output_name;
47static char *output_mode;
48static struct wl_list configured_output_list;
49
50enum output_config {
51 OUTPUT_CONFIG_INVALID = 0,
52 OUTPUT_CONFIG_OFF,
53 OUTPUT_CONFIG_PREFERRED,
54 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060055 OUTPUT_CONFIG_MODE,
56 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060057};
58
59struct drm_configured_output {
60 char *name;
61 char *mode;
62 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060063 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060064 enum output_config config;
65 struct wl_list link;
66};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040067
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040068struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050069 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040070
71 struct udev *udev;
72 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010074 struct udev_monitor *udev_monitor;
75 struct wl_event_source *udev_drm_source;
76
Benjamin Franzke2af7f102011-03-02 11:14:59 +010077 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010078 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010079 int fd;
80 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020081 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050082 uint32_t *crtcs;
83 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050084 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010085 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050086 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020087
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040088 struct gbm_surface *dummy_surface;
89 EGLSurface dummy_egl_surface;
90
Jesse Barnes58ef3792012-02-23 09:45:49 -050091 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050092 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -050093
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020094 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040095};
96
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040097struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050098 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040099 drmModeModeInfo mode_info;
100};
101
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300102struct drm_output;
103
104struct drm_fb {
105 struct gbm_bo *bo;
106 struct drm_output *output;
107 uint32_t fb_id;
108 int is_client_buffer;
109 struct wl_buffer *buffer;
110 struct wl_listener buffer_destroy_listener;
111};
112
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400113struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400115
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400116 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400117 uint32_t crtc_id;
118 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700119 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200120
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300121 int vblank_pending;
122 int page_flip_pending;
123
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400124 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400125 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400126 struct weston_plane cursor_plane;
127 struct weston_plane fb_plane;
128 int current_cursor, cursor_free;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400129 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300130 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200131 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400132};
133
Jesse Barnes58ef3792012-02-23 09:45:49 -0500134/*
135 * An output has a primary display plane plus zero or more sprites for
136 * blending display contents.
137 */
138struct drm_sprite {
139 struct wl_list link;
140
141 uint32_t fb_id;
142 uint32_t pending_fb_id;
143 struct weston_surface *surface;
144 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400145 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500146
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300147 struct drm_output *output;
148
Jesse Barnes58ef3792012-02-23 09:45:49 -0500149 struct drm_compositor *compositor;
150
151 struct wl_listener destroy_listener;
152 struct wl_listener pending_destroy_listener;
153
154 uint32_t possible_crtcs;
155 uint32_t plane_id;
156 uint32_t count_formats;
157
158 int32_t src_x, src_y;
159 uint32_t src_w, src_h;
160 uint32_t dest_x, dest_y;
161 uint32_t dest_w, dest_h;
162
163 uint32_t formats[];
164};
165
166static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500167drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
168{
169 struct weston_compositor *ec = output_base->compositor;
170 struct drm_compositor *c =(struct drm_compositor *) ec;
171 struct drm_output *output = (struct drm_output *) output_base;
172 int crtc;
173
174 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
175 if (c->crtcs[crtc] != output->crtc_id)
176 continue;
177
178 if (supported & (1 << crtc))
179 return -1;
180 }
181
182 return 0;
183}
184
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300185static void
186drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
187{
188 struct drm_fb *fb = data;
189 struct gbm_device *gbm = gbm_bo_get_device(bo);
190
191 if (fb->fb_id)
192 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
193
194 if (fb->buffer) {
195 weston_buffer_post_release(fb->buffer);
196 wl_list_remove(&fb->buffer_destroy_listener.link);
197 }
198
199 free(data);
200}
201
202static struct drm_fb *
203drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
204{
205 struct drm_fb *fb = gbm_bo_get_user_data(bo);
206 struct drm_compositor *compositor =
207 (struct drm_compositor *) output->base.compositor;
208 uint32_t width, height, stride, handle;
209 int ret;
210
211 if (fb)
212 return fb;
213
214 fb = malloc(sizeof *fb);
215
216 fb->bo = bo;
217 fb->output = output;
218 fb->is_client_buffer = 0;
219 fb->buffer = NULL;
220
221 width = gbm_bo_get_width(bo);
222 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400223 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300224 handle = gbm_bo_get_handle(bo).u32;
225
226 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
227 stride, handle, &fb->fb_id);
228 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200229 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300230 free(fb);
231 return NULL;
232 }
233
234 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
235
236 return fb;
237}
238
239static void
240fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
241{
242 struct drm_fb *fb = container_of(listener, struct drm_fb,
243 buffer_destroy_listener);
244
245 fb->buffer = NULL;
246
247 if (fb == fb->output->next ||
248 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400249 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300250}
251
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400252static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400253drm_output_prepare_scanout_surface(struct weston_output *_output,
254 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500255{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400256 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500257 struct drm_compositor *c =
258 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300259 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500260
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500261 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200262 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200263 es->geometry.width != output->base.current->width ||
264 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200265 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400266 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400267 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500268
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400269 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
270 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500271
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300272 /* Need to verify output->region contained in surface opaque
273 * region. Or maybe just that format doesn't have alpha.
274 * For now, scanout only if format is XRGB8888. */
275 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
276 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400277 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300278 }
279
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300280 output->next = drm_fb_get_from_bo(bo, output);
281 if (!output->next) {
282 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400283 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300284 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500285
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300286 output->next->is_client_buffer = 1;
287 output->next->buffer = es->buffer;
288 output->next->buffer->busy_count++;
289 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
290
291 wl_signal_add(&output->next->buffer->resource.destroy_signal,
292 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500293
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400294 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500295}
296
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500297static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400298drm_output_render(struct drm_output *output, pixman_region32_t *damage)
299{
300 struct drm_compositor *compositor =
301 (struct drm_compositor *) output->base.compositor;
302 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300303 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400304
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400305 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
306 output->egl_surface,
307 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200308 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400309 return;
310 }
311
312 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400313 if (surface->plane == &compositor->base.primary_plane)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400314 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400315
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400316 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600317
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400318 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300319 bo = gbm_surface_lock_front_buffer(output->surface);
320 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200321 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400322 return;
323 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300324
325 output->next = drm_fb_get_from_bo(bo, output);
326 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200327 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300328 gbm_surface_release_buffer(output->surface, bo);
329 return;
330 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400331}
332
333static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500334drm_output_repaint(struct weston_output *output_base,
335 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100336{
337 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500338 struct drm_compositor *compositor =
339 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500340 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400341 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500342 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100343
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300344 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400345 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300346 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400347 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100348
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400349 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300350 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400351 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300352 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400353 &output->connector_id, 1,
354 &mode->mode_info);
355 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200356 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400357 return;
358 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200359 }
360
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500361 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500363 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200364 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500365 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500366 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100367
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300368 output->page_flip_pending = 1;
369
Jesse Barnes58ef3792012-02-23 09:45:49 -0500370 /*
371 * Now, update all the sprite surfaces
372 */
373 wl_list_for_each(s, &compositor->sprite_list, link) {
374 uint32_t flags = 0;
375 drmVBlank vbl = {
376 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
377 .request.sequence = 1,
378 };
379
380 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
381 continue;
382
383 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
384 output->crtc_id, s->pending_fb_id, flags,
385 s->dest_x, s->dest_y,
386 s->dest_w, s->dest_h,
387 s->src_x, s->src_y,
388 s->src_w, s->src_h);
389 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200390 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500391 ret, strerror(errno));
392
393 /*
394 * Queue a vblank signal so we know when the surface
395 * becomes active on the display or has been replaced.
396 */
397 vbl.request.signal = (unsigned long)s;
398 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
399 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200400 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500401 ret, strerror(errno));
402 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300403
404 s->output = output;
405 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500406 }
407
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500408 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400409}
410
411static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500412vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
413 void *data)
414{
415 struct drm_sprite *s = (struct drm_sprite *)data;
416 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300417 struct drm_output *output = s->output;
418 uint32_t msecs;
419
420 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500421
422 if (s->surface) {
423 weston_buffer_post_release(s->surface->buffer);
424 wl_list_remove(&s->destroy_listener.link);
425 s->surface = NULL;
426 drmModeRmFB(c->drm.fd, s->fb_id);
427 s->fb_id = 0;
428 }
429
430 if (s->pending_surface) {
431 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400432 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
433 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500434 s->surface = s->pending_surface;
435 s->pending_surface = NULL;
436 s->fb_id = s->pending_fb_id;
437 s->pending_fb_id = 0;
438 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300439
440 if (!output->page_flip_pending) {
441 msecs = sec * 1000 + usec / 1000;
442 weston_output_finish_frame(&output->base, msecs);
443 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500444}
445
446static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400447page_flip_handler(int fd, unsigned int frame,
448 unsigned int sec, unsigned int usec, void *data)
449{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200450 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400451 uint32_t msecs;
452
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300453 output->page_flip_pending = 0;
454
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300455 if (output->current) {
456 if (output->current->is_client_buffer)
457 gbm_bo_destroy(output->current->bo);
458 else
459 gbm_surface_release_buffer(output->surface,
460 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200461 }
462
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300463 output->current = output->next;
464 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400465
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300466 if (!output->vblank_pending) {
467 msecs = sec * 1000 + usec / 1000;
468 weston_output_finish_frame(&output->base, msecs);
469 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200470}
471
472static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500473drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
474{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400475 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500476
477 for (i = 0; i < s->count_formats; i++)
478 if (s->formats[i] == format)
479 return 1;
480
481 return 0;
482}
483
484static int
485drm_surface_transform_supported(struct weston_surface *es)
486{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400487 struct weston_matrix *matrix = &es->transform.matrix;
488 int i;
489
490 if (!es->transform.enabled)
491 return 1;
492
493 for (i = 0; i < 16; i++) {
494 switch (i) {
495 case 10:
496 case 15:
497 if (matrix->d[i] != 1.0)
498 return 0;
499 break;
500 case 0:
501 case 5:
502 case 12:
503 case 13:
504 break;
505 default:
506 if (matrix->d[i] != 0.0)
507 return 0;
508 break;
509 }
510 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500511
512 return 1;
513}
514
Jesse Barnes58ef3792012-02-23 09:45:49 -0500515static void
516drm_disable_unused_sprites(struct weston_output *output_base)
517{
518 struct weston_compositor *ec = output_base->compositor;
519 struct drm_compositor *c =(struct drm_compositor *) ec;
520 struct drm_output *output = (struct drm_output *) output_base;
521 struct drm_sprite *s;
522 int ret;
523
524 wl_list_for_each(s, &c->sprite_list, link) {
525 if (s->pending_fb_id)
526 continue;
527
528 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
529 output->crtc_id, 0, 0,
530 0, 0, 0, 0, 0, 0, 0, 0);
531 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200532 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500533 ret, strerror(errno));
534 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300535
536 if (s->surface) {
537 s->surface = NULL;
538 wl_list_remove(&s->destroy_listener.link);
539 }
540
541 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500542 s->fb_id = 0;
543 s->pending_fb_id = 0;
544 }
545}
546
547/*
548 * This function must take care to damage any previously assigned surface
549 * if the sprite ends up binding to a different surface than in the
550 * previous frame.
551 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400552static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500553drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400554 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500555{
556 struct weston_compositor *ec = output_base->compositor;
557 struct drm_compositor *c =(struct drm_compositor *) ec;
558 struct drm_sprite *s;
559 int found = 0;
560 EGLint handle, stride;
561 struct gbm_bo *bo;
562 uint32_t fb_id = 0;
563 uint32_t handles[4], pitches[4], offsets[4];
564 int ret = 0;
565 pixman_region32_t dest_rect, src_rect;
566 pixman_box32_t *box;
567 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400568 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500569
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500570 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400571 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500572
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300573 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400574 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300575
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400576 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400577 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578
579 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400580 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500581
Jesse Barnes58ef3792012-02-23 09:45:49 -0500582 wl_list_for_each(s, &c->sprite_list, link) {
583 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
584 continue;
585
586 if (!s->pending_fb_id) {
587 found = 1;
588 break;
589 }
590 }
591
592 /* No sprites available */
593 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400594 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500595
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400596 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
597 es->buffer, GBM_BO_USE_SCANOUT);
598 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400599 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400600
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 format = gbm_bo_get_format(bo);
602 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400603 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500604
605 gbm_bo_destroy(bo);
606
607 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400608 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609
610 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400611 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500612
613 handles[0] = handle;
614 pitches[0] = stride;
615 offsets[0] = 0;
616
617 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
618 format, handles, pitches, offsets,
619 &fb_id, 0);
620 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200621 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500622 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400623 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 }
625
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 s->pending_fb_id = fb_id;
627 s->pending_surface = es;
628 es->buffer->busy_count++;
629
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400630 box = pixman_region32_extents(&es->transform.boundingbox);
631 s->plane.x = box->x1;
632 s->plane.y = box->y1;
633
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 /*
635 * Calculate the source & dest rects properly based on actual
636 * postion (note the caller has called weston_surface_update_transform()
637 * for us already).
638 */
639 pixman_region32_init(&dest_rect);
640 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
641 &output_base->region);
642 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
643 box = pixman_region32_extents(&dest_rect);
644 s->dest_x = box->x1;
645 s->dest_y = box->y1;
646 s->dest_w = box->x2 - box->x1;
647 s->dest_h = box->y2 - box->y1;
648 pixman_region32_fini(&dest_rect);
649
650 pixman_region32_init(&src_rect);
651 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
652 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400654
655 weston_surface_from_global_fixed(es,
656 wl_fixed_from_int(box->x1),
657 wl_fixed_from_int(box->y1),
658 &sx1, &sy1);
659 weston_surface_from_global_fixed(es,
660 wl_fixed_from_int(box->x2),
661 wl_fixed_from_int(box->y2),
662 &sx2, &sy2);
663
664 if (sx1 < 0)
665 sx1 = 0;
666 if (sy1 < 0)
667 sy1 = 0;
668 if (sx2 > wl_fixed_from_int(es->geometry.width))
669 sx2 = wl_fixed_from_int(es->geometry.width);
670 if (sy2 > wl_fixed_from_int(es->geometry.height))
671 sy2 = wl_fixed_from_int(es->geometry.height);
672
673 s->src_x = sx1 << 8;
674 s->src_y = sy1 << 8;
675 s->src_w = (sx2 - sx1) << 8;
676 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500677 pixman_region32_fini(&src_rect);
678
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400679 wl_signal_add(&es->buffer->resource.destroy_signal,
680 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400681
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400682 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500683}
684
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400685static struct weston_plane *
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400686drm_output_set_cursor(struct weston_output *output_base,
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400687 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500688{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400689 struct drm_output *output = (struct drm_output *) output_base;
690 struct drm_compositor *c =
691 (struct drm_compositor *) output->base.compositor;
692 EGLint handle, stride;
693 struct gbm_bo *bo;
694 uint32_t buf[64 * 64];
695 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400696 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500697
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400698 if (!output->cursor_free)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400699 return NULL;
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400700 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400701 return NULL;
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400702 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
703 es->geometry.width > 64 || es->geometry.height > 64)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400704 return NULL;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500705
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400706 output->cursor_free = 0;
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400707 if (es->buffer && pixman_region32_not_empty(&es->damage)) {
708 output->current_cursor ^= 1;
709 bo = output->cursor_bo[output->current_cursor];
710 memset(buf, 0, sizeof buf);
711 stride = wl_shm_buffer_get_stride(es->buffer);
712 s = wl_shm_buffer_get_data(es->buffer);
713 for (i = 0; i < es->geometry.height; i++)
714 memcpy(buf + i * 64, s + i * stride,
715 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500716
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400717 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400718 weston_log("failed update cursor: %n\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400719
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400720 handle = gbm_bo_get_handle(bo).s32;
721 if (drmModeSetCursor(c->drm.fd,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400722 output->crtc_id, handle, 64, 64))
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400723 weston_log("failed to set cursor: %n\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400724 }
725
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400726 x = es->geometry.x - output->base.x;
727 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400728 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
729 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y))
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400730 weston_log("failed to move cursor: %m\n");
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400731 output->cursor_plane.x = x;
732 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400733 }
734
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400735 return &output->cursor_plane;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500736}
737
Jesse Barnes58ef3792012-02-23 09:45:49 -0500738static void
739drm_assign_planes(struct weston_output *output)
740{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400741 struct drm_compositor *c =
742 (struct drm_compositor *) output->compositor;
743 struct drm_output *drm_output = (struct drm_output *) output;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400744 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500745 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400746 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500747
748 /*
749 * Find a surface for each sprite in the output using some heuristics:
750 * 1) size
751 * 2) frequency of update
752 * 3) opacity (though some hw might support alpha blending)
753 * 4) clipping (this can be fixed with color keys)
754 *
755 * The idea is to save on blitting since this should save power.
756 * If we can get a large video surface on the sprite for example,
757 * the main display surface may not need to update at all, and
758 * the client buffer can be used directly for the sprite surface
759 * as we do for flipping full screen surfaces.
760 */
761 pixman_region32_init(&overlap);
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400762 drm_output->cursor_free = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400763 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400764 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500765 pixman_region32_init(&surface_overlap);
766 pixman_region32_intersect(&surface_overlap, &overlap,
767 &es->transform.boundingbox);
768
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400769 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400770 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400771 next_plane = primary;
772 if (next_plane == NULL)
773 next_plane = drm_output_set_cursor(output, es);
774 if (next_plane == NULL)
775 next_plane = drm_output_prepare_scanout_surface(output, es);
776 if (next_plane == NULL)
777 next_plane = drm_output_prepare_overlay_surface(output, es);
778 if (next_plane == NULL)
779 next_plane = primary;
780 weston_surface_move_to_plane(es, next_plane);
781 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500782 pixman_region32_union(&overlap, &overlap,
783 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400784
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785 pixman_region32_fini(&surface_overlap);
786 }
787 pixman_region32_fini(&overlap);
788
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400789 if (drm_output->cursor_free)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400790 drmModeSetCursor(c->drm.fd, drm_output->crtc_id, 0, 0, 0);
Kristian Høgsbergf2735ea2012-06-20 23:03:53 -0400791
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792 drm_disable_unused_sprites(output);
793}
794
Matt Roper361d2ad2011-08-29 13:52:23 -0700795static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500796drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700797{
798 struct drm_output *output = (struct drm_output *) output_base;
799 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200800 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700801 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700802
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200803 if (output->backlight)
804 backlight_destroy(output->backlight);
805
Matt Roper361d2ad2011-08-29 13:52:23 -0700806 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400807 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700808
809 /* Restore original CRTC state */
810 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200811 origcrtc->x, origcrtc->y,
812 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700813 drmModeFreeCrtc(origcrtc);
814
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200815 c->crtc_allocator &= ~(1 << output->crtc_id);
816 c->connector_allocator &= ~(1 << output->connector_id);
817
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400818 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400819 gbm_surface_destroy(output->surface);
820
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400821 weston_plane_release(&output->fb_plane);
822 weston_plane_release(&output->cursor_plane);
823
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500824 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200825 wl_list_remove(&output->base.link);
826
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400827 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700828 free(output);
829}
830
Alex Wub7b8bda2012-04-17 17:20:48 +0800831static struct drm_mode *
832choose_mode (struct drm_output *output, struct weston_mode *target_mode)
833{
834 struct drm_mode *tmp_mode = NULL, *mode;
835
836 if (output->base.current->width == target_mode->width &&
837 output->base.current->height == target_mode->height &&
838 (output->base.current->refresh == target_mode->refresh ||
839 target_mode->refresh == 0))
840 return (struct drm_mode *)output->base.current;
841
842 wl_list_for_each(mode, &output->base.mode_list, base.link) {
843 if (mode->mode_info.hdisplay == target_mode->width &&
844 mode->mode_info.vdisplay == target_mode->height) {
845 if (mode->mode_info.vrefresh == target_mode->refresh ||
846 target_mode->refresh == 0) {
847 return mode;
848 } else if (!tmp_mode)
849 tmp_mode = mode;
850 }
851 }
852
853 return tmp_mode;
854}
855
856static int
857drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
858{
859 struct drm_output *output;
860 struct drm_mode *drm_mode;
861 int ret;
862 struct drm_compositor *ec;
863 struct gbm_surface *surface;
864 EGLSurface egl_surface;
865
866 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200867 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800868 return -1;
869 }
870
871 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200872 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800873 return -1;
874 }
875
876 ec = (struct drm_compositor *)output_base->compositor;
877 output = (struct drm_output *)output_base;
878 drm_mode = choose_mode (output, mode);
879
880 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200881 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800882 return -1;
883 } else if (&drm_mode->base == output->base.current) {
884 return 0;
885 } else if (drm_mode->base.width == output->base.current->width &&
886 drm_mode->base.height == output->base.current->height) {
887 /* only change refresh value */
888 ret = drmModeSetCrtc(ec->drm.fd,
889 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300890 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800891 &output->connector_id, 1, &drm_mode->mode_info);
892
893 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200894 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800895 drm_mode->base.width,
896 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400897 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800898 ret = -1;
899 } else {
900 output->base.current->flags = 0;
901 output->base.current = &drm_mode->base;
902 drm_mode->base.flags =
903 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
904 ret = 0;
905 }
906
907 return ret;
908 }
909
910 drm_mode->base.flags =
911 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
912
913 surface = gbm_surface_create(ec->gbm,
914 drm_mode->base.width,
915 drm_mode->base.height,
916 GBM_FORMAT_XRGB8888,
917 GBM_BO_USE_SCANOUT |
918 GBM_BO_USE_RENDERING);
919 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200920 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800921 return -1;
922 }
923
924 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400925 eglCreateWindowSurface(ec->base.egl_display,
926 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800927 surface, NULL);
928
929 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200930 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800931 goto err;
932 }
933
934 ret = drmModeSetCrtc(ec->drm.fd,
935 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300936 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800937 &output->connector_id, 1, &drm_mode->mode_info);
938 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200939 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800940 goto err;
941 }
942
943 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300944 if (output->current) {
945 if (output->current->is_client_buffer)
946 gbm_bo_destroy(output->current->bo);
947 else
948 gbm_surface_release_buffer(output->surface,
949 output->current->bo);
950 }
951 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800952
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300953 if (output->next) {
954 if (output->next->is_client_buffer)
955 gbm_bo_destroy(output->next->bo);
956 else
957 gbm_surface_release_buffer(output->surface,
958 output->next->bo);
959 }
960 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800961
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400962 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800963 gbm_surface_destroy(output->surface);
964 output->egl_surface = egl_surface;
965 output->surface = surface;
966
967 /*update output*/
968 output->base.current = &drm_mode->base;
969 output->base.dirty = 1;
970 weston_output_move(&output->base, output->base.x, output->base.y);
971 return 0;
972
973err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400974 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800975 gbm_surface_destroy(surface);
976 return -1;
977}
978
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400979static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400980on_drm_input(int fd, uint32_t mask, void *data)
981{
982 drmEventContext evctx;
983
984 memset(&evctx, 0, sizeof evctx);
985 evctx.version = DRM_EVENT_CONTEXT_VERSION;
986 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500987 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400988 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400989
990 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400991}
992
993static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400994init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400995{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400996 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -0400997 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400998 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400999 static const EGLint context_attribs[] = {
1000 EGL_CONTEXT_CLIENT_VERSION, 2,
1001 EGL_NONE
1002 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001003
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001004 static const EGLint config_attribs[] = {
1005 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1006 EGL_RED_SIZE, 1,
1007 EGL_GREEN_SIZE, 1,
1008 EGL_BLUE_SIZE, 1,
1009 EGL_ALPHA_SIZE, 0,
1010 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1011 EGL_NONE
1012 };
1013
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001014 sysnum = udev_device_get_sysnum(device);
1015 if (sysnum)
1016 ec->drm.id = atoi(sysnum);
1017 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001018 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001019 return -1;
1020 }
1021
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001022 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001023 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001024 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001025 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001026 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001027 udev_device_get_devnode(device));
1028 return -1;
1029 }
1030
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001031 weston_log("using %s\n", filename);
1032
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001033 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001034 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001035 ec->base.egl_display = eglGetDisplay(ec->gbm);
1036 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001037 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001038 return -1;
1039 }
1040
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001041 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001042 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001043 return -1;
1044 }
1045
Darxus55973f22010-11-22 21:24:39 -05001046 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001047 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001048 return -1;
1049 }
1050
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001051 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1052 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001053 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001054 return -1;
1055 }
1056
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001057 ec->base.egl_context =
1058 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1059 EGL_NO_CONTEXT, context_attribs);
1060 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001061 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001062 return -1;
1063 }
1064
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001065 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1066 GBM_FORMAT_XRGB8888,
1067 GBM_BO_USE_RENDERING);
1068 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001069 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001070 return -1;
1071 }
1072
1073 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001074 eglCreateWindowSurface(ec->base.egl_display,
1075 ec->base.egl_config,
1076 ec->dummy_surface,
1077 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001078 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001079 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001080 return -1;
1081 }
1082
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001083 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1084 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001085 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001086 return -1;
1087 }
1088
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001089 return 0;
1090}
1091
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001092static int
1093drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1094{
1095 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001096 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001097
1098 mode = malloc(sizeof *mode);
1099 if (mode == NULL)
1100 return -1;
1101
1102 mode->base.flags = 0;
1103 mode->base.width = info->hdisplay;
1104 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001105
1106 /* Calculate higher precision (mHz) refresh rate */
1107 refresh = (info->clock * 1000000LL / info->htotal +
1108 info->vtotal / 2) / info->vtotal;
1109
1110 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1111 refresh *= 2;
1112 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1113 refresh /= 2;
1114 if (info->vscan > 1)
1115 refresh /= info->vscan;
1116
1117 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001118 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001119
1120 if (info->type & DRM_MODE_TYPE_PREFERRED)
1121 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1122
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001123 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1124
1125 return 0;
1126}
1127
1128static int
1129drm_subpixel_to_wayland(int drm_value)
1130{
1131 switch (drm_value) {
1132 default:
1133 case DRM_MODE_SUBPIXEL_UNKNOWN:
1134 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1135 case DRM_MODE_SUBPIXEL_NONE:
1136 return WL_OUTPUT_SUBPIXEL_NONE;
1137 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1138 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1139 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1140 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1141 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1142 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1143 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1144 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1145 }
1146}
1147
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001148static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001149sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001150{
1151 struct drm_sprite *sprite =
1152 container_of(listener, struct drm_sprite,
1153 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001154 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001155
1156 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001157 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1158 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001159}
1160
1161static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001162sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001163{
1164 struct drm_sprite *sprite =
1165 container_of(listener, struct drm_sprite,
1166 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001167 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001168
1169 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001170 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1171 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001172}
1173
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001174/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001175static uint32_t
1176drm_get_backlight(struct drm_output *output)
1177{
1178 long brightness, max_brightness, norm;
1179
1180 brightness = backlight_get_brightness(output->backlight);
1181 max_brightness = backlight_get_max_brightness(output->backlight);
1182
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001183 /* convert it on a scale of 0 to 255 */
1184 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001185
1186 return (uint32_t) norm;
1187}
1188
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001189/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001190static void
1191drm_set_backlight(struct weston_output *output_base, uint32_t value)
1192{
1193 struct drm_output *output = (struct drm_output *) output_base;
1194 long max_brightness, new_brightness;
1195
1196 if (!output->backlight)
1197 return;
1198
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001199 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001200 return;
1201
1202 max_brightness = backlight_get_max_brightness(output->backlight);
1203
1204 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001205 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001206
1207 backlight_set_brightness(output->backlight, new_brightness);
1208}
1209
1210static drmModePropertyPtr
1211drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1212{
1213 drmModePropertyPtr props;
1214 int i;
1215
1216 for (i = 0; i < connector->count_props; i++) {
1217 props = drmModeGetProperty(fd, connector->props[i]);
1218 if (!props)
1219 continue;
1220
1221 if (!strcmp(props->name, name))
1222 return props;
1223
1224 drmModeFreeProperty(props);
1225 }
1226
1227 return NULL;
1228}
1229
1230static void
1231drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1232{
1233 struct drm_output *output = (struct drm_output *) output_base;
1234 struct weston_compositor *ec = output_base->compositor;
1235 struct drm_compositor *c = (struct drm_compositor *) ec;
1236 drmModeConnectorPtr connector;
1237 drmModePropertyPtr prop;
1238
1239 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1240 if (!connector)
1241 return;
1242
1243 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1244 if (!prop) {
1245 drmModeFreeConnector(connector);
1246 return;
1247 }
1248
1249 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1250 prop->prop_id, level);
1251 drmModeFreeProperty(prop);
1252 drmModeFreeConnector(connector);
1253}
1254
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001255static const char *connector_type_names[] = {
1256 "None",
1257 "VGA",
1258 "DVI",
1259 "DVI",
1260 "DVI",
1261 "Composite",
1262 "TV",
1263 "LVDS",
1264 "CTV",
1265 "DIN",
1266 "DP",
1267 "HDMI",
1268 "HDMI",
1269 "TV",
1270 "eDP",
1271};
1272
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001273static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001274find_crtc_for_connector(struct drm_compositor *ec,
1275 drmModeRes *resources, drmModeConnector *connector)
1276{
1277 drmModeEncoder *encoder;
1278 uint32_t possible_crtcs;
1279 int i, j;
1280
1281 for (j = 0; j < connector->count_encoders; j++) {
1282 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1283 if (encoder == NULL) {
1284 weston_log("Failed to get encoder.\n");
1285 return -1;
1286 }
1287 possible_crtcs = encoder->possible_crtcs;
1288 drmModeFreeEncoder(encoder);
1289
1290 for (i = 0; i < resources->count_crtcs; i++) {
1291 if (possible_crtcs & (1 << i) &&
1292 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1293 return i;
1294 }
1295 }
1296
1297 return -1;
1298}
1299
1300static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001301create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001302 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001303 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001304 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001305{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001306 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001307 struct drm_mode *drm_mode, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001308 struct weston_mode *m, *preferred, *current, *configured;
1309 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001310 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001311 drmModeModeInfo crtc_mode;
1312 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001313 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001314 char name[32];
1315 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001316
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001317 i = find_crtc_for_connector(ec, resources, connector);
1318 if (i < 0) {
1319 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001320 return -1;
1321 }
1322
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001323 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001324 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001325 return -1;
1326
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001327 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001328 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1329 output->base.make = "unknown";
1330 output->base.model = "unknown";
1331 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001332
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001333 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1334 type_name = connector_type_names[connector->connector_type];
1335 else
1336 type_name = "UNKNOWN";
1337 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1338 output->name = strdup(name);
1339
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001340 output->crtc_id = resources->crtcs[i];
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001341 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001342 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001343 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001344
Matt Roper361d2ad2011-08-29 13:52:23 -07001345 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1346
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001347 /* Get the current mode on the crtc that's currently driving
1348 * this connector. */
1349 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001350 memset(&crtc_mode, 0, sizeof crtc_mode);
1351 if (encoder != NULL) {
1352 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1353 drmModeFreeEncoder(encoder);
1354 if (crtc == NULL)
1355 goto err_free;
1356 if (crtc->mode_valid)
1357 crtc_mode = crtc->mode;
1358 drmModeFreeCrtc(crtc);
1359 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001360
David Herrmann0f0d54e2011-12-08 17:05:45 +01001361 for (i = 0; i < connector->count_modes; i++) {
1362 ret = drm_output_add_mode(output, &connector->modes[i]);
1363 if (ret)
1364 goto err_free;
1365 }
1366
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001367 preferred = NULL;
1368 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001369 configured = NULL;
1370
1371 wl_list_for_each(temp, &configured_output_list, link) {
1372 if (strcmp(temp->name, output->name) == 0) {
1373 weston_log("%s mode \"%s\" in config\n",
1374 temp->name, temp->mode);
1375 o = temp;
1376 break;
1377 }
1378 }
1379
1380 if (o && strcmp("off", o->mode) == 0) {
1381 weston_log("Disabling output %s\n", o->name);
1382
1383 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1384 0, 0, 0, 0, 0, NULL);
1385 goto err_free;
1386 }
1387
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001388 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001389 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001390 o->height == drm_mode->base.height &&
1391 o->config == OUTPUT_CONFIG_MODE)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001392 configured = &drm_mode->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001393 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001394 current = &drm_mode->base;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001395 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1396 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001397 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001398
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001399 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
1400 ret = drm_output_add_mode(output, &o->crtc_mode);
1401 if (ret)
1402 goto err_free;
1403 configured = container_of(output->base.mode_list.prev,
1404 struct weston_mode, link);
1405 current = configured;
1406 }
1407
Wang Quanxianacb805a2012-07-30 18:09:46 -04001408 if (current == NULL && crtc_mode.clock != 0) {
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001409 ret = drm_output_add_mode(output, &crtc_mode);
1410 if (ret)
1411 goto err_free;
1412 current = container_of(output->base.mode_list.prev,
1413 struct weston_mode, link);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001414 }
1415
Scott Moreau8ab5d452012-07-30 19:51:08 -06001416 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1417 configured = current;
1418
Wang Quanxianacb805a2012-07-30 18:09:46 -04001419 if (option_current_mode && current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 output->base.current = current;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001421 else if (configured)
1422 output->base.current = configured;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001423 else if (preferred)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001424 output->base.current = preferred;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001425 else if (current)
1426 output->base.current = current;
1427
1428 if (output->base.current == NULL) {
1429 weston_log("no available modes for %s\n", output->name);
1430 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001431 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001432
Wang Quanxianacb805a2012-07-30 18:09:46 -04001433 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1434
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001435 output->surface = gbm_surface_create(ec->gbm,
1436 output->base.current->width,
1437 output->base.current->height,
1438 GBM_FORMAT_XRGB8888,
1439 GBM_BO_USE_SCANOUT |
1440 GBM_BO_USE_RENDERING);
1441 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001442 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001443 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001444 }
1445
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001446 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001447 eglCreateWindowSurface(ec->base.egl_display,
1448 ec->base.egl_config,
1449 output->surface,
1450 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001451 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001452 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001453 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001454 }
1455
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001456 output->cursor_bo[0] =
1457 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1458 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1459 output->cursor_bo[1] =
1460 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1461 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1462
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001463 output->backlight = backlight_init(drm_device,
1464 connector->connector_type);
1465 if (output->backlight) {
1466 output->base.set_backlight = drm_set_backlight;
1467 output->base.backlight_current = drm_get_backlight(output);
1468 }
1469
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001470 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001471 connector->mmWidth, connector->mmHeight,
1472 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001473
1474 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1475
Alex Wubd3354b2012-04-17 17:20:49 +08001476 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001477 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001478 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001479 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001480 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001481 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001482
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001483 weston_plane_init(&output->cursor_plane, 0, 0);
1484 weston_plane_init(&output->fb_plane, 0, 0);
1485
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001486 weston_log("Output %s, (connector %d, crtc %d)\n",
1487 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001488 wl_list_for_each(m, &output->base.mode_list, link)
1489 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1490 m->width, m->height, m->refresh / 1000.0,
1491 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1492 ", preferred" : "",
1493 m->flags & WL_OUTPUT_MODE_CURRENT ?
1494 ", current" : "",
1495 connector->count_modes == 0 ?
1496 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001497
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001498 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001499
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001500err_surface:
1501 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001502err_free:
1503 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1504 base.link) {
1505 wl_list_remove(&drm_mode->base.link);
1506 free(drm_mode);
1507 }
1508
1509 drmModeFreeCrtc(output->original_crtc);
1510 ec->crtc_allocator &= ~(1 << output->crtc_id);
1511 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001512 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001513 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001514
David Herrmann0f0d54e2011-12-08 17:05:45 +01001515 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001516}
1517
Jesse Barnes58ef3792012-02-23 09:45:49 -05001518static void
1519create_sprites(struct drm_compositor *ec)
1520{
1521 struct drm_sprite *sprite;
1522 drmModePlaneRes *plane_res;
1523 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001524 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001525
1526 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1527 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001528 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001529 strerror(errno));
1530 return;
1531 }
1532
1533 for (i = 0; i < plane_res->count_planes; i++) {
1534 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1535 if (!plane)
1536 continue;
1537
1538 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1539 plane->count_formats));
1540 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001541 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001542 __func__);
1543 free(plane);
1544 continue;
1545 }
1546
1547 memset(sprite, 0, sizeof *sprite);
1548
1549 sprite->possible_crtcs = plane->possible_crtcs;
1550 sprite->plane_id = plane->plane_id;
1551 sprite->surface = NULL;
1552 sprite->pending_surface = NULL;
1553 sprite->fb_id = 0;
1554 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001555 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1556 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001557 sprite_handle_pending_buffer_destroy;
1558 sprite->compositor = ec;
1559 sprite->count_formats = plane->count_formats;
1560 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001561 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001562 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001563 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001564
1565 wl_list_insert(&ec->sprite_list, &sprite->link);
1566 }
1567
1568 free(plane_res->planes);
1569 free(plane_res);
1570}
1571
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001572static void
1573destroy_sprites(struct drm_compositor *compositor)
1574{
1575 struct drm_sprite *sprite, *next;
1576 struct drm_output *output;
1577
1578 output = container_of(compositor->base.output_list.next,
1579 struct drm_output, base.link);
1580
1581 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1582 drmModeSetPlane(compositor->drm.fd,
1583 sprite->plane_id,
1584 output->crtc_id, 0, 0,
1585 0, 0, 0, 0, 0, 0, 0, 0);
1586 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001587 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001588 free(sprite);
1589 }
1590}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001591
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001592static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001593create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001594 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001595{
1596 drmModeConnector *connector;
1597 drmModeRes *resources;
1598 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001599 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001600
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001601 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001602 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001603 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001604 return -1;
1605 }
1606
Jesse Barnes58ef3792012-02-23 09:45:49 -05001607 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001608 if (!ec->crtcs) {
1609 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001610 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001611 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001612
1613 ec->num_crtcs = resources->count_crtcs;
1614 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1615
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001616 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001617 connector = drmModeGetConnector(ec->drm.fd,
1618 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001619 if (connector == NULL)
1620 continue;
1621
1622 if (connector->connection == DRM_MODE_CONNECTED &&
1623 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001624 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001625 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001626 connector, x, y,
1627 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001628 drmModeFreeConnector(connector);
1629 continue;
1630 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001631
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001632 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001633 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001634 link)->current->width;
1635 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001636
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001637 drmModeFreeConnector(connector);
1638 }
1639
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001640 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001641 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001642 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001643 return -1;
1644 }
1645
1646 drmModeFreeResources(resources);
1647
1648 return 0;
1649}
1650
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001651static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001652update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001653{
1654 drmModeConnector *connector;
1655 drmModeRes *resources;
1656 struct drm_output *output, *next;
1657 int x = 0, y = 0;
1658 int x_offset = 0, y_offset = 0;
1659 uint32_t connected = 0, disconnects = 0;
1660 int i;
1661
1662 resources = drmModeGetResources(ec->drm.fd);
1663 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001664 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001665 return;
1666 }
1667
1668 /* collect new connects */
1669 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001670 int connector_id = resources->connectors[i];
1671
1672 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001673 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001674 continue;
1675
David Herrmann7551cff2011-12-08 17:05:43 +01001676 if (connector->connection != DRM_MODE_CONNECTED) {
1677 drmModeFreeConnector(connector);
1678 continue;
1679 }
1680
Benjamin Franzke117483d2011-08-30 11:38:26 +02001681 connected |= (1 << connector_id);
1682
1683 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001684 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001685 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001686 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001687
1688 /* XXX: not yet needed, we die with 0 outputs */
1689 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001690 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001691 else
1692 x = 0;
1693 y = 0;
1694 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001695 connector, x, y,
1696 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001697 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001698
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001699 }
1700 drmModeFreeConnector(connector);
1701 }
1702 drmModeFreeResources(resources);
1703
1704 disconnects = ec->connector_allocator & ~connected;
1705 if (disconnects) {
1706 wl_list_for_each_safe(output, next, &ec->base.output_list,
1707 base.link) {
1708 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001709 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001710 output->base.x - x_offset,
1711 output->base.y - y_offset);
1712 }
1713
1714 if (disconnects & (1 << output->connector_id)) {
1715 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001716 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001717 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001718 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001719 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001720 }
1721 }
1722 }
1723
1724 /* FIXME: handle zero outputs, without terminating */
1725 if (ec->connector_allocator == 0)
1726 wl_display_terminate(ec->base.wl_display);
1727}
1728
1729static int
David Herrmannd7488c22012-03-11 20:05:21 +01001730udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001731{
David Herrmannd7488c22012-03-11 20:05:21 +01001732 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001733 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001734
1735 sysnum = udev_device_get_sysnum(device);
1736 if (!sysnum || atoi(sysnum) != ec->drm.id)
1737 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001738
David Herrmann6ac52db2012-03-11 20:05:22 +01001739 val = udev_device_get_property_value(device, "HOTPLUG");
1740 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001741 return 0;
1742
David Herrmann6ac52db2012-03-11 20:05:22 +01001743 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001744}
1745
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001746static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001747udev_drm_event(int fd, uint32_t mask, void *data)
1748{
1749 struct drm_compositor *ec = data;
1750 struct udev_device *event;
1751
1752 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001753
David Herrmannd7488c22012-03-11 20:05:21 +01001754 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001755 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001756
1757 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001758
1759 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001760}
1761
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001762static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001763drm_restore(struct weston_compositor *ec)
1764{
1765 struct drm_compositor *d = (struct drm_compositor *) ec;
1766
1767 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1768 weston_log("failed to drop master: %m\n");
1769 tty_reset(d->tty);
1770}
1771
1772static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001773drm_free_configured_output(struct drm_configured_output *output)
1774{
1775 free(output->name);
1776 free(output->mode);
1777 free(output);
1778}
1779
1780static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001781drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001782{
1783 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001784 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001785 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001786
Daniel Stone37816df2012-05-16 18:45:18 +01001787 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1788 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001789 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001790 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001791
1792 wl_event_source_remove(d->udev_drm_source);
1793 wl_event_source_remove(d->drm_source);
1794
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001795 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001796
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001797 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001798 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001799 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001800 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001801 eglReleaseThread();
1802
Matt Roper361d2ad2011-08-29 13:52:23 -07001803 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001804 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001805 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001806 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001807 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001808
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001809 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001810}
1811
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001812static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001813drm_compositor_set_modes(struct drm_compositor *compositor)
1814{
1815 struct drm_output *output;
1816 struct drm_mode *drm_mode;
1817 int ret;
1818
1819 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1820 drm_mode = (struct drm_mode *) output->base.current;
1821 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001822 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001823 &output->connector_id, 1,
1824 &drm_mode->mode_info);
1825 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001826 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001827 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001828 drm_mode->base.width, drm_mode->base.height,
1829 output->base.x, output->base.y);
1830 }
1831 }
1832}
1833
1834static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001835vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001836{
1837 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001838 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001839 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001840 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001841
1842 switch (event) {
1843 case TTY_ENTER_VT:
1844 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001845 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001846 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001847 wl_display_terminate(compositor->wl_display);
1848 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001849 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001850 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001851 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01001852 wl_list_for_each(seat, &compositor->seat_list, link) {
1853 evdev_add_devices(ec->udev, seat);
1854 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02001855 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001856 break;
1857 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01001858 wl_list_for_each(seat, &compositor->seat_list, link) {
1859 evdev_disable_udev_monitor(seat);
1860 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04001861 }
1862
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001863 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001864 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001865 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04001866
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001867 /* If we have a repaint scheduled (either from a
1868 * pending pageflip or the idle handler), make sure we
1869 * cancel that so we don't try to pageflip when we're
1870 * vt switched away. The SLEEPING state will prevent
1871 * further attemps at repainting. When we switch
1872 * back, we schedule a repaint, which will process
1873 * pending frame callbacks. */
1874
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001875 wl_list_for_each(output, &ec->base.output_list, base.link) {
1876 output->base.repaint_needed = 0;
1877 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001878 }
1879
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001880 output = container_of(ec->base.output_list.next,
1881 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001882
1883 wl_list_for_each(sprite, &ec->sprite_list, link)
1884 drmModeSetPlane(ec->drm.fd,
1885 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001886 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001887 0, 0, 0, 0, 0, 0, 0, 0);
1888
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001889 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001890 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001891
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001892 break;
1893 };
1894}
1895
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001896static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01001897switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001898{
1899 struct drm_compositor *ec = data;
1900
Daniel Stone325fc2d2012-05-30 16:31:58 +01001901 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001902}
1903
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001904static const char default_seat[] = "seat0";
1905
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001906static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001907drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04001908 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04001909 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001910{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001911 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001912 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001913 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001914 struct udev_device *device, *drm_device;
1915 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001916 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001917 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001918 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001919
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001920 weston_log("initializing drm backend\n");
1921
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001922 ec = malloc(sizeof *ec);
1923 if (ec == NULL)
1924 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001925 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01001926
1927 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01001928 config_file) < 0) {
1929 weston_log("weston_compositor_init failed\n");
1930 goto err_base;
1931 }
Daniel Stone725c2c32012-06-22 14:04:36 +01001932
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001933 ec->udev = udev_new();
1934 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001935 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001936 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001937 }
1938
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001939 ec->base.wl_display = display;
1940 ec->tty = tty_create(&ec->base, vt_func, tty);
1941 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02001942 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001943 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001944 }
1945
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001946 e = udev_enumerate_new(ec->udev);
1947 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02001948 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001949
Benjamin Franzke117483d2011-08-30 11:38:26 +02001950 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001951 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001952 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001953 path = udev_list_entry_get_name(entry);
1954 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001955 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001956 udev_device_get_property_value(device, "ID_SEAT");
1957 if (!device_seat)
1958 device_seat = default_seat;
1959 if (strcmp(device_seat, seat) == 0) {
1960 drm_device = device;
1961 break;
1962 }
1963 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001964 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001965
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001966 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001967 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001968 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001969 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001970
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001971 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001972 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001973 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001974 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001975
1976 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001977 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02001978
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001979 ec->base.focus = 1;
1980
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001981 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001982
Daniel Stone725c2c32012-06-22 14:04:36 +01001983 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01001984 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02001985
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001986 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01001987 weston_compositor_add_key_binding(&ec->base, key,
1988 MODIFIER_CTRL | MODIFIER_ALT,
1989 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001990
Jesse Barnes58ef3792012-02-23 09:45:49 -05001991 wl_list_init(&ec->sprite_list);
1992 create_sprites(ec);
1993
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001994 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001995 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01001996 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001997 }
1998
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02001999 path = NULL;
2000
Tiago Vignattice03ec32011-12-19 01:14:03 +02002001 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002002
2003 loop = wl_display_get_event_loop(ec->base.wl_display);
2004 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002005 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002006 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002007
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002008 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2009 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002010 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002011 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002012 }
2013 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2014 "drm", NULL);
2015 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002016 wl_event_loop_add_fd(loop,
2017 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002018 WL_EVENT_READABLE, udev_drm_event, ec);
2019
2020 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002021 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002022 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002023 }
2024
Daniel Stonea96b93c2012-06-22 14:04:37 +01002025 udev_device_unref(drm_device);
2026 udev_enumerate_unref(e);
2027
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002028 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002029
2030err_udev_monitor:
2031 wl_event_source_remove(ec->udev_drm_source);
2032 udev_monitor_unref(ec->udev_monitor);
2033err_drm_source:
2034 wl_event_source_remove(ec->drm_source);
2035 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2036 evdev_input_destroy(weston_seat);
2037err_sprite:
2038 destroy_sprites(ec);
2039err_egl:
2040 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2041 EGL_NO_CONTEXT);
2042 eglTerminate(ec->base.egl_display);
2043 eglReleaseThread();
2044 gbm_device_destroy(ec->gbm);
2045err_udev_dev:
2046 udev_device_unref(drm_device);
2047err_udev_enum:
2048 udev_enumerate_unref(e);
2049 tty_destroy(ec->tty);
2050err_udev:
2051 udev_unref(ec->udev);
2052err_compositor:
2053 weston_compositor_shutdown(&ec->base);
2054err_base:
2055 free(ec);
2056 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002057}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002058
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002059static int
2060set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2061{
2062 mode->flags = 0;
2063
2064 if (strcmp(hsync, "+hsync") == 0)
2065 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2066 else if (strcmp(hsync, "-hsync") == 0)
2067 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2068 else
2069 return -1;
2070
2071 if (strcmp(vsync, "+vsync") == 0)
2072 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2073 else if (strcmp(vsync, "-vsync") == 0)
2074 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2075 else
2076 return -1;
2077
2078 return 0;
2079}
2080
2081static int
2082check_for_modeline(struct drm_configured_output *output)
2083{
2084 drmModeModeInfo mode;
2085 char hsync[16];
2086 char vsync[16];
2087 char mode_name[16];
2088 float fclock;
2089
2090 mode.type = DRM_MODE_TYPE_USERDEF;
2091 mode.hskew = 0;
2092 mode.vscan = 0;
2093 mode.vrefresh = 0;
2094
2095 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2096 &fclock, &mode.hdisplay,
2097 &mode.hsync_start,
2098 &mode.hsync_end, &mode.htotal,
2099 &mode.vdisplay,
2100 &mode.vsync_start,
2101 &mode.vsync_end, &mode.vtotal,
2102 hsync, vsync) == 11) {
2103 if (set_sync_flags(&mode, hsync, vsync))
2104 return -1;
2105
2106 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2107 strcpy(mode.name, mode_name);
2108
2109 mode.clock = fclock * 1000;
2110 } else
2111 return -1;
2112
2113 output->crtc_mode = mode;
2114
2115 return 0;
2116}
2117
Scott Moreau8ab5d452012-07-30 19:51:08 -06002118static void
2119output_section_done(void *data)
2120{
2121 struct drm_configured_output *output;
2122
2123 output = malloc(sizeof *output);
2124
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002125 if (!output || !output_name || !output_mode) {
2126 free(output_name);
2127 output_name = NULL;
2128 free(output_mode);
2129 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002130 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002131 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002132
2133 output->config = OUTPUT_CONFIG_INVALID;
2134 output->name = output_name;
2135 output->mode = output_mode;
2136
2137 if (strcmp(output_mode, "off") == 0)
2138 output->config = OUTPUT_CONFIG_OFF;
2139 else if (strcmp(output_mode, "preferred") == 0)
2140 output->config = OUTPUT_CONFIG_PREFERRED;
2141 else if (strcmp(output_mode, "current") == 0)
2142 output->config = OUTPUT_CONFIG_CURRENT;
2143 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2144 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002145 else if (check_for_modeline(output) == 0)
2146 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002147
2148 if (output->config != OUTPUT_CONFIG_INVALID)
2149 wl_list_insert(&configured_output_list, &output->link);
2150 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002151 weston_log("Invalid mode \"%s\" for output %s\n",
2152 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002153 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002154 }
2155}
2156
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002157WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002158backend_init(struct wl_display *display, int argc, char *argv[],
2159 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002160{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002161 int connector = 0, tty = 0;
2162 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002163
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002164 const struct weston_option drm_options[] = {
2165 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2166 { WESTON_OPTION_STRING, "seat", 0, &seat },
2167 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002168 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002169 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002170
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002171 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002172
Scott Moreau8ab5d452012-07-30 19:51:08 -06002173 wl_list_init(&configured_output_list);
2174
2175 const struct config_key drm_config_keys[] = {
2176 { "name", CONFIG_KEY_STRING, &output_name },
2177 { "mode", CONFIG_KEY_STRING, &output_mode },
2178 };
2179
2180 const struct config_section config_section[] = {
2181 { "output", drm_config_keys,
2182 ARRAY_LENGTH(drm_config_keys), output_section_done },
2183 };
2184
2185 parse_config_file(config_file, config_section,
2186 ARRAY_LENGTH(config_section), NULL);
2187
Daniel Stonec1be8e52012-06-01 11:14:02 -04002188 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2189 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002190}