blob: 861652773a4fad71460e587af1628fe915741974 [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øgsbergd553bfc2012-06-18 22:37:35 -040068enum {
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -040069 WESTON_PLANE_DRM_CURSOR = 0x100,
70 WESTON_PLANE_DRM_PLANE = 0x101,
71 WESTON_PLANE_DRM_FB = 0x102
Kristian Høgsbergd553bfc2012-06-18 22:37:35 -040072};
73
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050075 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
77 struct udev *udev;
78 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040079
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010080 struct udev_monitor *udev_monitor;
81 struct wl_event_source *udev_drm_source;
82
Benjamin Franzke2af7f102011-03-02 11:14:59 +010083 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010084 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010085 int fd;
86 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020087 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050088 uint32_t *crtcs;
89 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050090 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010091 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050092 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020093
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040094 struct gbm_surface *dummy_surface;
95 EGLSurface dummy_egl_surface;
96
Jesse Barnes58ef3792012-02-23 09:45:49 -050097 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050098 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -050099
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200100 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400101};
102
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400103struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500104 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400105 drmModeModeInfo mode_info;
106};
107
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300108struct drm_output;
109
110struct drm_fb {
111 struct gbm_bo *bo;
112 struct drm_output *output;
113 uint32_t fb_id;
114 int is_client_buffer;
115 struct wl_buffer *buffer;
116 struct wl_listener buffer_destroy_listener;
117};
118
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400119struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500120 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400121
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400122 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400123 uint32_t crtc_id;
124 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700125 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200126
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300127 int vblank_pending;
128 int page_flip_pending;
129
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400130 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400131 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400132 int current_cursor, cursor_free, cursor_x, cursor_y;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400133 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300134 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200135 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400136};
137
Jesse Barnes58ef3792012-02-23 09:45:49 -0500138/*
139 * An output has a primary display plane plus zero or more sprites for
140 * blending display contents.
141 */
142struct drm_sprite {
143 struct wl_list link;
144
145 uint32_t fb_id;
146 uint32_t pending_fb_id;
147 struct weston_surface *surface;
148 struct weston_surface *pending_surface;
149
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300150 struct drm_output *output;
151
Jesse Barnes58ef3792012-02-23 09:45:49 -0500152 struct drm_compositor *compositor;
153
154 struct wl_listener destroy_listener;
155 struct wl_listener pending_destroy_listener;
156
157 uint32_t possible_crtcs;
158 uint32_t plane_id;
159 uint32_t count_formats;
160
161 int32_t src_x, src_y;
162 uint32_t src_w, src_h;
163 uint32_t dest_x, dest_y;
164 uint32_t dest_w, dest_h;
165
166 uint32_t formats[];
167};
168
169static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500170drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
171{
172 struct weston_compositor *ec = output_base->compositor;
173 struct drm_compositor *c =(struct drm_compositor *) ec;
174 struct drm_output *output = (struct drm_output *) output_base;
175 int crtc;
176
177 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
178 if (c->crtcs[crtc] != output->crtc_id)
179 continue;
180
181 if (supported & (1 << crtc))
182 return -1;
183 }
184
185 return 0;
186}
187
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300188static void
189drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
190{
191 struct drm_fb *fb = data;
192 struct gbm_device *gbm = gbm_bo_get_device(bo);
193
194 if (fb->fb_id)
195 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
196
197 if (fb->buffer) {
198 weston_buffer_post_release(fb->buffer);
199 wl_list_remove(&fb->buffer_destroy_listener.link);
200 }
201
202 free(data);
203}
204
205static struct drm_fb *
206drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
207{
208 struct drm_fb *fb = gbm_bo_get_user_data(bo);
209 struct drm_compositor *compositor =
210 (struct drm_compositor *) output->base.compositor;
211 uint32_t width, height, stride, handle;
212 int ret;
213
214 if (fb)
215 return fb;
216
217 fb = malloc(sizeof *fb);
218
219 fb->bo = bo;
220 fb->output = output;
221 fb->is_client_buffer = 0;
222 fb->buffer = NULL;
223
224 width = gbm_bo_get_width(bo);
225 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400226 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300227 handle = gbm_bo_get_handle(bo).u32;
228
229 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
230 stride, handle, &fb->fb_id);
231 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200232 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300233 free(fb);
234 return NULL;
235 }
236
237 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
238
239 return fb;
240}
241
242static void
243fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
244{
245 struct drm_fb *fb = container_of(listener, struct drm_fb,
246 buffer_destroy_listener);
247
248 fb->buffer = NULL;
249
250 if (fb == fb->output->next ||
251 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400252 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300253}
254
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500255static int
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400256drm_output_prepare_scanout_surface(struct weston_output *_output,
257 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500258{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400259 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500260 struct drm_compositor *c =
261 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300262 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500263
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500264 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200265 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200266 es->geometry.width != output->base.current->width ||
267 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200268 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400269 es->buffer == NULL)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500270 return -1;
271
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400272 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
273 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500274
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300275 /* Need to verify output->region contained in surface opaque
276 * region. Or maybe just that format doesn't have alpha.
277 * For now, scanout only if format is XRGB8888. */
278 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
279 gbm_bo_destroy(bo);
280 return -1;
281 }
282
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300283 output->next = drm_fb_get_from_bo(bo, output);
284 if (!output->next) {
285 gbm_bo_destroy(bo);
286 return -1;
287 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500288
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300289 output->next->is_client_buffer = 1;
290 output->next->buffer = es->buffer;
291 output->next->buffer->busy_count++;
292 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
293
294 wl_signal_add(&output->next->buffer->resource.destroy_signal,
295 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500296
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400297 es->plane = WESTON_PLANE_DRM_FB;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500298
299 return 0;
300}
301
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500302static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400303drm_output_render(struct drm_output *output, pixman_region32_t *damage)
304{
305 struct drm_compositor *compositor =
306 (struct drm_compositor *) output->base.compositor;
307 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300308 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400309
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400310 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
311 output->egl_surface,
312 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200313 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400314 return;
315 }
316
317 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400318 if (surface->plane == WESTON_PLANE_PRIMARY)
319 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400320
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400321 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600322
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400323 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300324 bo = gbm_surface_lock_front_buffer(output->surface);
325 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200326 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400327 return;
328 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329
330 output->next = drm_fb_get_from_bo(bo, output);
331 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200332 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300333 gbm_surface_release_buffer(output->surface, bo);
334 return;
335 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400336}
337
338static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500339drm_output_repaint(struct weston_output *output_base,
340 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100341{
342 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500343 struct drm_compositor *compositor =
344 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500345 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400346 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500347 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100348
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300349 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400350 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300351 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400352 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100353
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400354 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300355 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400356 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300357 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400358 &output->connector_id, 1,
359 &mode->mode_info);
360 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200361 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400362 return;
363 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200364 }
365
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500366 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500368 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200369 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500370 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500371 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100372
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300373 output->page_flip_pending = 1;
374
Jesse Barnes58ef3792012-02-23 09:45:49 -0500375 /*
376 * Now, update all the sprite surfaces
377 */
378 wl_list_for_each(s, &compositor->sprite_list, link) {
379 uint32_t flags = 0;
380 drmVBlank vbl = {
381 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
382 .request.sequence = 1,
383 };
384
385 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
386 continue;
387
388 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
389 output->crtc_id, s->pending_fb_id, flags,
390 s->dest_x, s->dest_y,
391 s->dest_w, s->dest_h,
392 s->src_x, s->src_y,
393 s->src_w, s->src_h);
394 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200395 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500396 ret, strerror(errno));
397
398 /*
399 * Queue a vblank signal so we know when the surface
400 * becomes active on the display or has been replaced.
401 */
402 vbl.request.signal = (unsigned long)s;
403 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
404 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200405 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500406 ret, strerror(errno));
407 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300408
409 s->output = output;
410 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500411 }
412
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500413 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400414}
415
416static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500417vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
418 void *data)
419{
420 struct drm_sprite *s = (struct drm_sprite *)data;
421 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300422 struct drm_output *output = s->output;
423 uint32_t msecs;
424
425 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500426
427 if (s->surface) {
428 weston_buffer_post_release(s->surface->buffer);
429 wl_list_remove(&s->destroy_listener.link);
430 s->surface = NULL;
431 drmModeRmFB(c->drm.fd, s->fb_id);
432 s->fb_id = 0;
433 }
434
435 if (s->pending_surface) {
436 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400437 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
438 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500439 s->surface = s->pending_surface;
440 s->pending_surface = NULL;
441 s->fb_id = s->pending_fb_id;
442 s->pending_fb_id = 0;
443 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300444
445 if (!output->page_flip_pending) {
446 msecs = sec * 1000 + usec / 1000;
447 weston_output_finish_frame(&output->base, msecs);
448 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500449}
450
451static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400452page_flip_handler(int fd, unsigned int frame,
453 unsigned int sec, unsigned int usec, void *data)
454{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200455 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400456 uint32_t msecs;
457
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300458 output->page_flip_pending = 0;
459
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300460 if (output->current) {
461 if (output->current->is_client_buffer)
462 gbm_bo_destroy(output->current->bo);
463 else
464 gbm_surface_release_buffer(output->surface,
465 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200466 }
467
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300468 output->current = output->next;
469 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400470
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300471 if (!output->vblank_pending) {
472 msecs = sec * 1000 + usec / 1000;
473 weston_output_finish_frame(&output->base, msecs);
474 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200475}
476
477static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500478drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
479{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400480 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500481
482 for (i = 0; i < s->count_formats; i++)
483 if (s->formats[i] == format)
484 return 1;
485
486 return 0;
487}
488
489static int
490drm_surface_transform_supported(struct weston_surface *es)
491{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400492 struct weston_matrix *matrix = &es->transform.matrix;
493 int i;
494
495 if (!es->transform.enabled)
496 return 1;
497
498 for (i = 0; i < 16; i++) {
499 switch (i) {
500 case 10:
501 case 15:
502 if (matrix->d[i] != 1.0)
503 return 0;
504 break;
505 case 0:
506 case 5:
507 case 12:
508 case 13:
509 break;
510 default:
511 if (matrix->d[i] != 0.0)
512 return 0;
513 break;
514 }
515 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500516
517 return 1;
518}
519
Jesse Barnes58ef3792012-02-23 09:45:49 -0500520static void
521drm_disable_unused_sprites(struct weston_output *output_base)
522{
523 struct weston_compositor *ec = output_base->compositor;
524 struct drm_compositor *c =(struct drm_compositor *) ec;
525 struct drm_output *output = (struct drm_output *) output_base;
526 struct drm_sprite *s;
527 int ret;
528
529 wl_list_for_each(s, &c->sprite_list, link) {
530 if (s->pending_fb_id)
531 continue;
532
533 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
534 output->crtc_id, 0, 0,
535 0, 0, 0, 0, 0, 0, 0, 0);
536 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200537 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500538 ret, strerror(errno));
539 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300540
541 if (s->surface) {
542 s->surface = NULL;
543 wl_list_remove(&s->destroy_listener.link);
544 }
545
546 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500547 s->fb_id = 0;
548 s->pending_fb_id = 0;
549 }
550}
551
552/*
553 * This function must take care to damage any previously assigned surface
554 * if the sprite ends up binding to a different surface than in the
555 * previous frame.
556 */
557static int
558drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400559 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500560{
561 struct weston_compositor *ec = output_base->compositor;
562 struct drm_compositor *c =(struct drm_compositor *) ec;
563 struct drm_sprite *s;
564 int found = 0;
565 EGLint handle, stride;
566 struct gbm_bo *bo;
567 uint32_t fb_id = 0;
568 uint32_t handles[4], pitches[4], offsets[4];
569 int ret = 0;
570 pixman_region32_t dest_rect, src_rect;
571 pixman_box32_t *box;
572 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400573 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500575 if (c->sprites_are_broken)
576 return -1;
577
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300578 if (es->output_mask != (1u << output_base->id))
579 return -1;
580
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400581 if (es->buffer == NULL)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500582 return -1;
583
584 if (!drm_surface_transform_supported(es))
585 return -1;
586
Jesse Barnes58ef3792012-02-23 09:45:49 -0500587 wl_list_for_each(s, &c->sprite_list, link) {
588 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
589 continue;
590
591 if (!s->pending_fb_id) {
592 found = 1;
593 break;
594 }
595 }
596
597 /* No sprites available */
598 if (!found)
599 return -1;
600
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400601 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
602 es->buffer, GBM_BO_USE_SCANOUT);
603 if (!bo)
604 return -1;
605
Jesse Barnes58ef3792012-02-23 09:45:49 -0500606 format = gbm_bo_get_format(bo);
607 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400608 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609
610 gbm_bo_destroy(bo);
611
612 if (!drm_surface_format_supported(s, format))
613 return -1;
614
615 if (!handle)
616 return -1;
617
618 handles[0] = handle;
619 pitches[0] = stride;
620 offsets[0] = 0;
621
622 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
623 format, handles, pitches, offsets,
624 &fb_id, 0);
625 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200626 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500627 c->sprites_are_broken = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628 return -1;
629 }
630
Jesse Barnes58ef3792012-02-23 09:45:49 -0500631 s->pending_fb_id = fb_id;
632 s->pending_surface = es;
633 es->buffer->busy_count++;
634
635 /*
636 * Calculate the source & dest rects properly based on actual
637 * postion (note the caller has called weston_surface_update_transform()
638 * for us already).
639 */
640 pixman_region32_init(&dest_rect);
641 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
642 &output_base->region);
643 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
644 box = pixman_region32_extents(&dest_rect);
645 s->dest_x = box->x1;
646 s->dest_y = box->y1;
647 s->dest_w = box->x2 - box->x1;
648 s->dest_h = box->y2 - box->y1;
649 pixman_region32_fini(&dest_rect);
650
651 pixman_region32_init(&src_rect);
652 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
653 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400655
656 weston_surface_from_global_fixed(es,
657 wl_fixed_from_int(box->x1),
658 wl_fixed_from_int(box->y1),
659 &sx1, &sy1);
660 weston_surface_from_global_fixed(es,
661 wl_fixed_from_int(box->x2),
662 wl_fixed_from_int(box->y2),
663 &sx2, &sy2);
664
665 if (sx1 < 0)
666 sx1 = 0;
667 if (sy1 < 0)
668 sy1 = 0;
669 if (sx2 > wl_fixed_from_int(es->geometry.width))
670 sx2 = wl_fixed_from_int(es->geometry.width);
671 if (sy2 > wl_fixed_from_int(es->geometry.height))
672 sy2 = wl_fixed_from_int(es->geometry.height);
673
674 s->src_x = sx1 << 8;
675 s->src_y = sy1 << 8;
676 s->src_w = (sx2 - sx1) << 8;
677 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500678 pixman_region32_fini(&src_rect);
679
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400680 es->plane = WESTON_PLANE_DRM_PLANE;
681
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400682 wl_signal_add(&es->buffer->resource.destroy_signal,
683 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400684
Jesse Barnes58ef3792012-02-23 09:45:49 -0500685 return 0;
686}
687
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500688static void
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400689drm_output_set_cursor(struct weston_output *output_base,
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400690 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500691{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400692 struct drm_output *output = (struct drm_output *) output_base;
693 struct drm_compositor *c =
694 (struct drm_compositor *) output->base.compositor;
695 EGLint handle, stride;
696 struct gbm_bo *bo;
697 uint32_t buf[64 * 64];
698 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400699 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500700
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400701 if (!output->cursor_free)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500702 return;
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400703 if (es->output_mask != (1u << output_base->id))
704 return;
705 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
706 es->geometry.width > 64 || es->geometry.height > 64)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400707 return;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500708
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400709 if (es->buffer && pixman_region32_not_empty(&es->damage)) {
710 output->current_cursor ^= 1;
711 bo = output->cursor_bo[output->current_cursor];
712 memset(buf, 0, sizeof buf);
713 stride = wl_shm_buffer_get_stride(es->buffer);
714 s = wl_shm_buffer_get_data(es->buffer);
715 for (i = 0; i < es->geometry.height; i++)
716 memcpy(buf + i * 64, s + i * stride,
717 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500718
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400719 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
720 return;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400721
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400722 handle = gbm_bo_get_handle(bo).s32;
723 if (drmModeSetCursor(c->drm.fd,
724 output->crtc_id, handle, 64, 64)) {
725 weston_log("failed to set cursor: %n\n");
726 return;
727 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400728 }
729
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400730 x = es->geometry.x - output->base.x;
731 y = es->geometry.y - output->base.y;
732 if (output->cursor_x != x || output->cursor_y != y) {
733 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
734 weston_log("failed to move cursor: %m\n");
735 return;
736 }
737 output->cursor_x = x;
738 output->cursor_y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400739 }
740
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400741 es->plane = WESTON_PLANE_DRM_CURSOR;
742 output->cursor_free = 0;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500743}
744
Jesse Barnes58ef3792012-02-23 09:45:49 -0500745static void
746drm_assign_planes(struct weston_output *output)
747{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400748 struct drm_compositor *c =
749 (struct drm_compositor *) output->compositor;
750 struct drm_output *drm_output = (struct drm_output *) output;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400751 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500752 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400753 int prev_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500754
755 /*
756 * Find a surface for each sprite in the output using some heuristics:
757 * 1) size
758 * 2) frequency of update
759 * 3) opacity (though some hw might support alpha blending)
760 * 4) clipping (this can be fixed with color keys)
761 *
762 * The idea is to save on blitting since this should save power.
763 * If we can get a large video surface on the sprite for example,
764 * the main display surface may not need to update at all, and
765 * the client buffer can be used directly for the sprite surface
766 * as we do for flipping full screen surfaces.
767 */
768 pixman_region32_init(&overlap);
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400769 drm_output->cursor_free = 1;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400770 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771 pixman_region32_init(&surface_overlap);
772 pixman_region32_intersect(&surface_overlap, &overlap,
773 &es->transform.boundingbox);
774
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400775 prev_plane = es->plane;
776 es->plane = WESTON_PLANE_PRIMARY;
777 if (pixman_region32_not_empty(&surface_overlap))
778 goto bail;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500779
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400780 if (es->plane == WESTON_PLANE_PRIMARY)
781 drm_output_set_cursor(output, es);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400782 if (es->plane == WESTON_PLANE_PRIMARY)
783 drm_output_prepare_scanout_surface(output, es);
784 if (es->plane == WESTON_PLANE_PRIMARY)
785 drm_output_prepare_overlay_surface(output, es);
786
787 bail:
788 if (es->plane == WESTON_PLANE_PRIMARY)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500789 pixman_region32_union(&overlap, &overlap,
790 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400791
792 if (prev_plane != WESTON_PLANE_PRIMARY &&
793 es->plane == WESTON_PLANE_PRIMARY)
794 weston_surface_damage(es);
795 else if (prev_plane == WESTON_PLANE_PRIMARY &&
796 es->plane != WESTON_PLANE_PRIMARY)
797 weston_surface_damage_below(es);
798
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799 pixman_region32_fini(&surface_overlap);
800 }
801 pixman_region32_fini(&overlap);
802
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400803 if (drm_output->cursor_free)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400804 drmModeSetCursor(c->drm.fd, drm_output->crtc_id, 0, 0, 0);
Kristian Høgsbergf2735ea2012-06-20 23:03:53 -0400805
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806 drm_disable_unused_sprites(output);
807}
808
Matt Roper361d2ad2011-08-29 13:52:23 -0700809static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500810drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700811{
812 struct drm_output *output = (struct drm_output *) output_base;
813 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200814 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700815 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700816
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200817 if (output->backlight)
818 backlight_destroy(output->backlight);
819
Matt Roper361d2ad2011-08-29 13:52:23 -0700820 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400821 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700822
823 /* Restore original CRTC state */
824 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200825 origcrtc->x, origcrtc->y,
826 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700827 drmModeFreeCrtc(origcrtc);
828
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200829 c->crtc_allocator &= ~(1 << output->crtc_id);
830 c->connector_allocator &= ~(1 << output->connector_id);
831
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400832 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400833 gbm_surface_destroy(output->surface);
834
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500835 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200836 wl_list_remove(&output->base.link);
837
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400838 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700839 free(output);
840}
841
Alex Wub7b8bda2012-04-17 17:20:48 +0800842static struct drm_mode *
843choose_mode (struct drm_output *output, struct weston_mode *target_mode)
844{
845 struct drm_mode *tmp_mode = NULL, *mode;
846
847 if (output->base.current->width == target_mode->width &&
848 output->base.current->height == target_mode->height &&
849 (output->base.current->refresh == target_mode->refresh ||
850 target_mode->refresh == 0))
851 return (struct drm_mode *)output->base.current;
852
853 wl_list_for_each(mode, &output->base.mode_list, base.link) {
854 if (mode->mode_info.hdisplay == target_mode->width &&
855 mode->mode_info.vdisplay == target_mode->height) {
856 if (mode->mode_info.vrefresh == target_mode->refresh ||
857 target_mode->refresh == 0) {
858 return mode;
859 } else if (!tmp_mode)
860 tmp_mode = mode;
861 }
862 }
863
864 return tmp_mode;
865}
866
867static int
868drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
869{
870 struct drm_output *output;
871 struct drm_mode *drm_mode;
872 int ret;
873 struct drm_compositor *ec;
874 struct gbm_surface *surface;
875 EGLSurface egl_surface;
876
877 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200878 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800879 return -1;
880 }
881
882 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200883 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800884 return -1;
885 }
886
887 ec = (struct drm_compositor *)output_base->compositor;
888 output = (struct drm_output *)output_base;
889 drm_mode = choose_mode (output, mode);
890
891 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200892 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800893 return -1;
894 } else if (&drm_mode->base == output->base.current) {
895 return 0;
896 } else if (drm_mode->base.width == output->base.current->width &&
897 drm_mode->base.height == output->base.current->height) {
898 /* only change refresh value */
899 ret = drmModeSetCrtc(ec->drm.fd,
900 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300901 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800902 &output->connector_id, 1, &drm_mode->mode_info);
903
904 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200905 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800906 drm_mode->base.width,
907 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400908 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800909 ret = -1;
910 } else {
911 output->base.current->flags = 0;
912 output->base.current = &drm_mode->base;
913 drm_mode->base.flags =
914 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
915 ret = 0;
916 }
917
918 return ret;
919 }
920
921 drm_mode->base.flags =
922 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
923
924 surface = gbm_surface_create(ec->gbm,
925 drm_mode->base.width,
926 drm_mode->base.height,
927 GBM_FORMAT_XRGB8888,
928 GBM_BO_USE_SCANOUT |
929 GBM_BO_USE_RENDERING);
930 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200931 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800932 return -1;
933 }
934
935 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400936 eglCreateWindowSurface(ec->base.egl_display,
937 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800938 surface, NULL);
939
940 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200941 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800942 goto err;
943 }
944
945 ret = drmModeSetCrtc(ec->drm.fd,
946 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300947 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800948 &output->connector_id, 1, &drm_mode->mode_info);
949 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200950 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800951 goto err;
952 }
953
954 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300955 if (output->current) {
956 if (output->current->is_client_buffer)
957 gbm_bo_destroy(output->current->bo);
958 else
959 gbm_surface_release_buffer(output->surface,
960 output->current->bo);
961 }
962 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800963
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300964 if (output->next) {
965 if (output->next->is_client_buffer)
966 gbm_bo_destroy(output->next->bo);
967 else
968 gbm_surface_release_buffer(output->surface,
969 output->next->bo);
970 }
971 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800972
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400973 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800974 gbm_surface_destroy(output->surface);
975 output->egl_surface = egl_surface;
976 output->surface = surface;
977
978 /*update output*/
979 output->base.current = &drm_mode->base;
980 output->base.dirty = 1;
981 weston_output_move(&output->base, output->base.x, output->base.y);
982 return 0;
983
984err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400985 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800986 gbm_surface_destroy(surface);
987 return -1;
988}
989
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400990static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400991on_drm_input(int fd, uint32_t mask, void *data)
992{
993 drmEventContext evctx;
994
995 memset(&evctx, 0, sizeof evctx);
996 evctx.version = DRM_EVENT_CONTEXT_VERSION;
997 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500998 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400999 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001000
1001 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001002}
1003
1004static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001005init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001006{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001007 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001008 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001009 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001010 static const EGLint context_attribs[] = {
1011 EGL_CONTEXT_CLIENT_VERSION, 2,
1012 EGL_NONE
1013 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001014
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001015 static const EGLint config_attribs[] = {
1016 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1017 EGL_RED_SIZE, 1,
1018 EGL_GREEN_SIZE, 1,
1019 EGL_BLUE_SIZE, 1,
1020 EGL_ALPHA_SIZE, 0,
1021 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1022 EGL_NONE
1023 };
1024
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001025 sysnum = udev_device_get_sysnum(device);
1026 if (sysnum)
1027 ec->drm.id = atoi(sysnum);
1028 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001029 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001030 return -1;
1031 }
1032
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001033 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001034 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001035 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001036 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001037 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001038 udev_device_get_devnode(device));
1039 return -1;
1040 }
1041
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001042 weston_log("using %s\n", filename);
1043
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001044 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001045 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001046 ec->base.egl_display = eglGetDisplay(ec->gbm);
1047 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001048 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001049 return -1;
1050 }
1051
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001052 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001053 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001054 return -1;
1055 }
1056
Darxus55973f22010-11-22 21:24:39 -05001057 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001058 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001059 return -1;
1060 }
1061
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001062 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1063 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001064 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001065 return -1;
1066 }
1067
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001068 ec->base.egl_context =
1069 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1070 EGL_NO_CONTEXT, context_attribs);
1071 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001072 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001073 return -1;
1074 }
1075
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001076 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1077 GBM_FORMAT_XRGB8888,
1078 GBM_BO_USE_RENDERING);
1079 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001080 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001081 return -1;
1082 }
1083
1084 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001085 eglCreateWindowSurface(ec->base.egl_display,
1086 ec->base.egl_config,
1087 ec->dummy_surface,
1088 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001089 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001090 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001091 return -1;
1092 }
1093
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001094 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1095 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001096 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001097 return -1;
1098 }
1099
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001100 return 0;
1101}
1102
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001103static int
1104drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1105{
1106 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001107 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001108
1109 mode = malloc(sizeof *mode);
1110 if (mode == NULL)
1111 return -1;
1112
1113 mode->base.flags = 0;
1114 mode->base.width = info->hdisplay;
1115 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001116
1117 /* Calculate higher precision (mHz) refresh rate */
1118 refresh = (info->clock * 1000000LL / info->htotal +
1119 info->vtotal / 2) / info->vtotal;
1120
1121 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1122 refresh *= 2;
1123 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1124 refresh /= 2;
1125 if (info->vscan > 1)
1126 refresh /= info->vscan;
1127
1128 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001129 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001130
1131 if (info->type & DRM_MODE_TYPE_PREFERRED)
1132 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1133
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001134 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1135
1136 return 0;
1137}
1138
1139static int
1140drm_subpixel_to_wayland(int drm_value)
1141{
1142 switch (drm_value) {
1143 default:
1144 case DRM_MODE_SUBPIXEL_UNKNOWN:
1145 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1146 case DRM_MODE_SUBPIXEL_NONE:
1147 return WL_OUTPUT_SUBPIXEL_NONE;
1148 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1149 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1150 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1151 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1152 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1153 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1154 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1155 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1156 }
1157}
1158
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001159static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001160sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001161{
1162 struct drm_sprite *sprite =
1163 container_of(listener, struct drm_sprite,
1164 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001165 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001166
1167 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001168 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1169 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001170}
1171
1172static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001173sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001174{
1175 struct drm_sprite *sprite =
1176 container_of(listener, struct drm_sprite,
1177 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001178 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001179
1180 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001181 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1182 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001183}
1184
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001185/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001186static uint32_t
1187drm_get_backlight(struct drm_output *output)
1188{
1189 long brightness, max_brightness, norm;
1190
1191 brightness = backlight_get_brightness(output->backlight);
1192 max_brightness = backlight_get_max_brightness(output->backlight);
1193
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001194 /* convert it on a scale of 0 to 255 */
1195 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001196
1197 return (uint32_t) norm;
1198}
1199
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001200/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001201static void
1202drm_set_backlight(struct weston_output *output_base, uint32_t value)
1203{
1204 struct drm_output *output = (struct drm_output *) output_base;
1205 long max_brightness, new_brightness;
1206
1207 if (!output->backlight)
1208 return;
1209
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001210 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001211 return;
1212
1213 max_brightness = backlight_get_max_brightness(output->backlight);
1214
1215 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001216 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001217
1218 backlight_set_brightness(output->backlight, new_brightness);
1219}
1220
1221static drmModePropertyPtr
1222drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1223{
1224 drmModePropertyPtr props;
1225 int i;
1226
1227 for (i = 0; i < connector->count_props; i++) {
1228 props = drmModeGetProperty(fd, connector->props[i]);
1229 if (!props)
1230 continue;
1231
1232 if (!strcmp(props->name, name))
1233 return props;
1234
1235 drmModeFreeProperty(props);
1236 }
1237
1238 return NULL;
1239}
1240
1241static void
1242drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1243{
1244 struct drm_output *output = (struct drm_output *) output_base;
1245 struct weston_compositor *ec = output_base->compositor;
1246 struct drm_compositor *c = (struct drm_compositor *) ec;
1247 drmModeConnectorPtr connector;
1248 drmModePropertyPtr prop;
1249
1250 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1251 if (!connector)
1252 return;
1253
1254 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1255 if (!prop) {
1256 drmModeFreeConnector(connector);
1257 return;
1258 }
1259
1260 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1261 prop->prop_id, level);
1262 drmModeFreeProperty(prop);
1263 drmModeFreeConnector(connector);
1264}
1265
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001266static const char *connector_type_names[] = {
1267 "None",
1268 "VGA",
1269 "DVI",
1270 "DVI",
1271 "DVI",
1272 "Composite",
1273 "TV",
1274 "LVDS",
1275 "CTV",
1276 "DIN",
1277 "DP",
1278 "HDMI",
1279 "HDMI",
1280 "TV",
1281 "eDP",
1282};
1283
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001284static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001285find_crtc_for_connector(struct drm_compositor *ec,
1286 drmModeRes *resources, drmModeConnector *connector)
1287{
1288 drmModeEncoder *encoder;
1289 uint32_t possible_crtcs;
1290 int i, j;
1291
1292 for (j = 0; j < connector->count_encoders; j++) {
1293 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1294 if (encoder == NULL) {
1295 weston_log("Failed to get encoder.\n");
1296 return -1;
1297 }
1298 possible_crtcs = encoder->possible_crtcs;
1299 drmModeFreeEncoder(encoder);
1300
1301 for (i = 0; i < resources->count_crtcs; i++) {
1302 if (possible_crtcs & (1 << i) &&
1303 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1304 return i;
1305 }
1306 }
1307
1308 return -1;
1309}
1310
1311static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001312create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001313 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001314 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001315 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001316{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001317 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001318 struct drm_mode *drm_mode, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001319 struct weston_mode *m, *preferred, *current, *configured;
1320 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001321 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001322 drmModeModeInfo crtc_mode;
1323 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001324 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001325 char name[32];
1326 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001327
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001328 i = find_crtc_for_connector(ec, resources, connector);
1329 if (i < 0) {
1330 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001331 return -1;
1332 }
1333
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001334 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001335 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001336 return -1;
1337
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001338 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001339 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1340 output->base.make = "unknown";
1341 output->base.model = "unknown";
1342 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001343
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001344 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1345 type_name = connector_type_names[connector->connector_type];
1346 else
1347 type_name = "UNKNOWN";
1348 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1349 output->name = strdup(name);
1350
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001351 output->crtc_id = resources->crtcs[i];
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001352 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001353 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001354 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001355
Matt Roper361d2ad2011-08-29 13:52:23 -07001356 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1357
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001358 /* Get the current mode on the crtc that's currently driving
1359 * this connector. */
1360 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001361 memset(&crtc_mode, 0, sizeof crtc_mode);
1362 if (encoder != NULL) {
1363 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1364 drmModeFreeEncoder(encoder);
1365 if (crtc == NULL)
1366 goto err_free;
1367 if (crtc->mode_valid)
1368 crtc_mode = crtc->mode;
1369 drmModeFreeCrtc(crtc);
1370 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001371
David Herrmann0f0d54e2011-12-08 17:05:45 +01001372 for (i = 0; i < connector->count_modes; i++) {
1373 ret = drm_output_add_mode(output, &connector->modes[i]);
1374 if (ret)
1375 goto err_free;
1376 }
1377
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001378 preferred = NULL;
1379 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001380 configured = NULL;
1381
1382 wl_list_for_each(temp, &configured_output_list, link) {
1383 if (strcmp(temp->name, output->name) == 0) {
1384 weston_log("%s mode \"%s\" in config\n",
1385 temp->name, temp->mode);
1386 o = temp;
1387 break;
1388 }
1389 }
1390
1391 if (o && strcmp("off", o->mode) == 0) {
1392 weston_log("Disabling output %s\n", o->name);
1393
1394 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1395 0, 0, 0, 0, 0, NULL);
1396 goto err_free;
1397 }
1398
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001399 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001400 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001401 o->height == drm_mode->base.height &&
1402 o->config == OUTPUT_CONFIG_MODE)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001403 configured = &drm_mode->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001404 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001405 current = &drm_mode->base;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001406 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1407 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001408 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001409
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001410 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
1411 ret = drm_output_add_mode(output, &o->crtc_mode);
1412 if (ret)
1413 goto err_free;
1414 configured = container_of(output->base.mode_list.prev,
1415 struct weston_mode, link);
1416 current = configured;
1417 }
1418
Wang Quanxianacb805a2012-07-30 18:09:46 -04001419 if (current == NULL && crtc_mode.clock != 0) {
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 ret = drm_output_add_mode(output, &crtc_mode);
1421 if (ret)
1422 goto err_free;
1423 current = container_of(output->base.mode_list.prev,
1424 struct weston_mode, link);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001425 }
1426
Scott Moreau8ab5d452012-07-30 19:51:08 -06001427 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1428 configured = current;
1429
Wang Quanxianacb805a2012-07-30 18:09:46 -04001430 if (option_current_mode && current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001431 output->base.current = current;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001432 else if (configured)
1433 output->base.current = configured;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001434 else if (preferred)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001435 output->base.current = preferred;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001436 else if (current)
1437 output->base.current = current;
1438
1439 if (output->base.current == NULL) {
1440 weston_log("no available modes for %s\n", output->name);
1441 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001442 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001443
Wang Quanxianacb805a2012-07-30 18:09:46 -04001444 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1445
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001446 output->surface = gbm_surface_create(ec->gbm,
1447 output->base.current->width,
1448 output->base.current->height,
1449 GBM_FORMAT_XRGB8888,
1450 GBM_BO_USE_SCANOUT |
1451 GBM_BO_USE_RENDERING);
1452 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001453 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001454 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001455 }
1456
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001457 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001458 eglCreateWindowSurface(ec->base.egl_display,
1459 ec->base.egl_config,
1460 output->surface,
1461 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001462 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001463 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001464 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001465 }
1466
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001467 output->cursor_bo[0] =
1468 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1469 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1470 output->cursor_bo[1] =
1471 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1472 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1473
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001474 output->backlight = backlight_init(drm_device,
1475 connector->connector_type);
1476 if (output->backlight) {
1477 output->base.set_backlight = drm_set_backlight;
1478 output->base.backlight_current = drm_get_backlight(output);
1479 }
1480
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001481 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001482 connector->mmWidth, connector->mmHeight,
1483 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001484
1485 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1486
Alex Wubd3354b2012-04-17 17:20:49 +08001487 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001488 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001489 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001490 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001491 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001492 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001493
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001494 weston_log("Output %s, (connector %d, crtc %d)\n",
1495 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001496 wl_list_for_each(m, &output->base.mode_list, link)
1497 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1498 m->width, m->height, m->refresh / 1000.0,
1499 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1500 ", preferred" : "",
1501 m->flags & WL_OUTPUT_MODE_CURRENT ?
1502 ", current" : "",
1503 connector->count_modes == 0 ?
1504 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001505
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001506 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001507
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001508err_surface:
1509 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001510err_free:
1511 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1512 base.link) {
1513 wl_list_remove(&drm_mode->base.link);
1514 free(drm_mode);
1515 }
1516
1517 drmModeFreeCrtc(output->original_crtc);
1518 ec->crtc_allocator &= ~(1 << output->crtc_id);
1519 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001520 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001521 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001522
David Herrmann0f0d54e2011-12-08 17:05:45 +01001523 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001524}
1525
Jesse Barnes58ef3792012-02-23 09:45:49 -05001526static void
1527create_sprites(struct drm_compositor *ec)
1528{
1529 struct drm_sprite *sprite;
1530 drmModePlaneRes *plane_res;
1531 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001532 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001533
1534 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1535 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001536 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001537 strerror(errno));
1538 return;
1539 }
1540
1541 for (i = 0; i < plane_res->count_planes; i++) {
1542 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1543 if (!plane)
1544 continue;
1545
1546 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1547 plane->count_formats));
1548 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001549 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001550 __func__);
1551 free(plane);
1552 continue;
1553 }
1554
1555 memset(sprite, 0, sizeof *sprite);
1556
1557 sprite->possible_crtcs = plane->possible_crtcs;
1558 sprite->plane_id = plane->plane_id;
1559 sprite->surface = NULL;
1560 sprite->pending_surface = NULL;
1561 sprite->fb_id = 0;
1562 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001563 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1564 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001565 sprite_handle_pending_buffer_destroy;
1566 sprite->compositor = ec;
1567 sprite->count_formats = plane->count_formats;
1568 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001569 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001570 drmModeFreePlane(plane);
1571
1572 wl_list_insert(&ec->sprite_list, &sprite->link);
1573 }
1574
1575 free(plane_res->planes);
1576 free(plane_res);
1577}
1578
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001579static void
1580destroy_sprites(struct drm_compositor *compositor)
1581{
1582 struct drm_sprite *sprite, *next;
1583 struct drm_output *output;
1584
1585 output = container_of(compositor->base.output_list.next,
1586 struct drm_output, base.link);
1587
1588 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1589 drmModeSetPlane(compositor->drm.fd,
1590 sprite->plane_id,
1591 output->crtc_id, 0, 0,
1592 0, 0, 0, 0, 0, 0, 0, 0);
1593 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1594 free(sprite);
1595 }
1596}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001597
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001598static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001599create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001600 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001601{
1602 drmModeConnector *connector;
1603 drmModeRes *resources;
1604 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001605 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001606
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001607 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001608 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001609 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001610 return -1;
1611 }
1612
Jesse Barnes58ef3792012-02-23 09:45:49 -05001613 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001614 if (!ec->crtcs) {
1615 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001616 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001617 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001618
1619 ec->num_crtcs = resources->count_crtcs;
1620 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1621
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001622 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001623 connector = drmModeGetConnector(ec->drm.fd,
1624 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001625 if (connector == NULL)
1626 continue;
1627
1628 if (connector->connection == DRM_MODE_CONNECTED &&
1629 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001630 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001631 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001632 connector, x, y,
1633 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001634 drmModeFreeConnector(connector);
1635 continue;
1636 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001637
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001638 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001639 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001640 link)->current->width;
1641 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001642
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001643 drmModeFreeConnector(connector);
1644 }
1645
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001646 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001647 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001648 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001649 return -1;
1650 }
1651
1652 drmModeFreeResources(resources);
1653
1654 return 0;
1655}
1656
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001657static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001658update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001659{
1660 drmModeConnector *connector;
1661 drmModeRes *resources;
1662 struct drm_output *output, *next;
1663 int x = 0, y = 0;
1664 int x_offset = 0, y_offset = 0;
1665 uint32_t connected = 0, disconnects = 0;
1666 int i;
1667
1668 resources = drmModeGetResources(ec->drm.fd);
1669 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001670 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001671 return;
1672 }
1673
1674 /* collect new connects */
1675 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001676 int connector_id = resources->connectors[i];
1677
1678 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001679 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001680 continue;
1681
David Herrmann7551cff2011-12-08 17:05:43 +01001682 if (connector->connection != DRM_MODE_CONNECTED) {
1683 drmModeFreeConnector(connector);
1684 continue;
1685 }
1686
Benjamin Franzke117483d2011-08-30 11:38:26 +02001687 connected |= (1 << connector_id);
1688
1689 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001690 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001691 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001692 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001693
1694 /* XXX: not yet needed, we die with 0 outputs */
1695 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001696 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001697 else
1698 x = 0;
1699 y = 0;
1700 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001701 connector, x, y,
1702 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001703 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001704
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001705 }
1706 drmModeFreeConnector(connector);
1707 }
1708 drmModeFreeResources(resources);
1709
1710 disconnects = ec->connector_allocator & ~connected;
1711 if (disconnects) {
1712 wl_list_for_each_safe(output, next, &ec->base.output_list,
1713 base.link) {
1714 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001715 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001716 output->base.x - x_offset,
1717 output->base.y - y_offset);
1718 }
1719
1720 if (disconnects & (1 << output->connector_id)) {
1721 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001722 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001723 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001724 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001725 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001726 }
1727 }
1728 }
1729
1730 /* FIXME: handle zero outputs, without terminating */
1731 if (ec->connector_allocator == 0)
1732 wl_display_terminate(ec->base.wl_display);
1733}
1734
1735static int
David Herrmannd7488c22012-03-11 20:05:21 +01001736udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001737{
David Herrmannd7488c22012-03-11 20:05:21 +01001738 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001739 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001740
1741 sysnum = udev_device_get_sysnum(device);
1742 if (!sysnum || atoi(sysnum) != ec->drm.id)
1743 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001744
David Herrmann6ac52db2012-03-11 20:05:22 +01001745 val = udev_device_get_property_value(device, "HOTPLUG");
1746 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001747 return 0;
1748
David Herrmann6ac52db2012-03-11 20:05:22 +01001749 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001750}
1751
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001752static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001753udev_drm_event(int fd, uint32_t mask, void *data)
1754{
1755 struct drm_compositor *ec = data;
1756 struct udev_device *event;
1757
1758 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001759
David Herrmannd7488c22012-03-11 20:05:21 +01001760 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001761 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001762
1763 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001764
1765 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001766}
1767
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001768static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001769drm_restore(struct weston_compositor *ec)
1770{
1771 struct drm_compositor *d = (struct drm_compositor *) ec;
1772
1773 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1774 weston_log("failed to drop master: %m\n");
1775 tty_reset(d->tty);
1776}
1777
1778static void
Scott Moreauc50645c2012-07-31 22:29:56 -06001779drm_free_configured_output(struct drm_configured_output *output)
1780{
1781 free(output->name);
1782 free(output->mode);
1783 free(output);
1784}
1785
1786static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001787drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001788{
1789 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001790 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001791 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001792
Daniel Stone37816df2012-05-16 18:45:18 +01001793 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1794 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001795 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06001796 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001797
1798 wl_event_source_remove(d->udev_drm_source);
1799 wl_event_source_remove(d->drm_source);
1800
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001801 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001802
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001803 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001804 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001805 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001806 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001807 eglReleaseThread();
1808
Matt Roper361d2ad2011-08-29 13:52:23 -07001809 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001810 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001811 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001812 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001813 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001814
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001815 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001816}
1817
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001818static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001819drm_compositor_set_modes(struct drm_compositor *compositor)
1820{
1821 struct drm_output *output;
1822 struct drm_mode *drm_mode;
1823 int ret;
1824
1825 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1826 drm_mode = (struct drm_mode *) output->base.current;
1827 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001828 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001829 &output->connector_id, 1,
1830 &drm_mode->mode_info);
1831 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001832 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001833 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001834 drm_mode->base.width, drm_mode->base.height,
1835 output->base.x, output->base.y);
1836 }
1837 }
1838}
1839
1840static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001841vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001842{
1843 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001844 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001845 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001846 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001847
1848 switch (event) {
1849 case TTY_ENTER_VT:
1850 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001851 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001852 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001853 wl_display_terminate(compositor->wl_display);
1854 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001855 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001856 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001857 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01001858 wl_list_for_each(seat, &compositor->seat_list, link) {
1859 evdev_add_devices(ec->udev, seat);
1860 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02001861 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001862 break;
1863 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01001864 wl_list_for_each(seat, &compositor->seat_list, link) {
1865 evdev_disable_udev_monitor(seat);
1866 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04001867 }
1868
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001869 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001870 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001871 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04001872
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001873 /* If we have a repaint scheduled (either from a
1874 * pending pageflip or the idle handler), make sure we
1875 * cancel that so we don't try to pageflip when we're
1876 * vt switched away. The SLEEPING state will prevent
1877 * further attemps at repainting. When we switch
1878 * back, we schedule a repaint, which will process
1879 * pending frame callbacks. */
1880
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001881 wl_list_for_each(output, &ec->base.output_list, base.link) {
1882 output->base.repaint_needed = 0;
1883 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001884 }
1885
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001886 output = container_of(ec->base.output_list.next,
1887 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001888
1889 wl_list_for_each(sprite, &ec->sprite_list, link)
1890 drmModeSetPlane(ec->drm.fd,
1891 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001892 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001893 0, 0, 0, 0, 0, 0, 0, 0);
1894
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001895 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001896 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001897
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001898 break;
1899 };
1900}
1901
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001902static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01001903switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001904{
1905 struct drm_compositor *ec = data;
1906
Daniel Stone325fc2d2012-05-30 16:31:58 +01001907 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001908}
1909
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001910static const char default_seat[] = "seat0";
1911
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001912static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001913drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04001914 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04001915 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001916{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001917 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001918 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001919 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001920 struct udev_device *device, *drm_device;
1921 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001922 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001923 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001924 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001925
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001926 weston_log("initializing drm backend\n");
1927
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001928 ec = malloc(sizeof *ec);
1929 if (ec == NULL)
1930 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001931 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01001932
1933 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01001934 config_file) < 0) {
1935 weston_log("weston_compositor_init failed\n");
1936 goto err_base;
1937 }
Daniel Stone725c2c32012-06-22 14:04:36 +01001938
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001939 ec->udev = udev_new();
1940 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001941 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001942 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001943 }
1944
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001945 ec->base.wl_display = display;
1946 ec->tty = tty_create(&ec->base, vt_func, tty);
1947 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02001948 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001949 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001950 }
1951
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001952 e = udev_enumerate_new(ec->udev);
1953 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02001954 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001955
Benjamin Franzke117483d2011-08-30 11:38:26 +02001956 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001957 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001958 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001959 path = udev_list_entry_get_name(entry);
1960 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001961 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001962 udev_device_get_property_value(device, "ID_SEAT");
1963 if (!device_seat)
1964 device_seat = default_seat;
1965 if (strcmp(device_seat, seat) == 0) {
1966 drm_device = device;
1967 break;
1968 }
1969 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001970 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001971
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001972 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001973 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001974 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001975 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001976
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001977 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001978 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001979 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001980 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001981
1982 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001983 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02001984
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001985 ec->base.focus = 1;
1986
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001987 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001988
Daniel Stone725c2c32012-06-22 14:04:36 +01001989 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01001990 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02001991
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001992 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01001993 weston_compositor_add_key_binding(&ec->base, key,
1994 MODIFIER_CTRL | MODIFIER_ALT,
1995 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001996
Jesse Barnes58ef3792012-02-23 09:45:49 -05001997 wl_list_init(&ec->sprite_list);
1998 create_sprites(ec);
1999
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002000 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002001 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002002 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002003 }
2004
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002005 path = NULL;
2006
Tiago Vignattice03ec32011-12-19 01:14:03 +02002007 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002008
2009 loop = wl_display_get_event_loop(ec->base.wl_display);
2010 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002011 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002012 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002013
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002014 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2015 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002016 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002017 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002018 }
2019 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2020 "drm", NULL);
2021 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002022 wl_event_loop_add_fd(loop,
2023 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002024 WL_EVENT_READABLE, udev_drm_event, ec);
2025
2026 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002027 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002028 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002029 }
2030
Daniel Stonea96b93c2012-06-22 14:04:37 +01002031 udev_device_unref(drm_device);
2032 udev_enumerate_unref(e);
2033
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002034 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002035
2036err_udev_monitor:
2037 wl_event_source_remove(ec->udev_drm_source);
2038 udev_monitor_unref(ec->udev_monitor);
2039err_drm_source:
2040 wl_event_source_remove(ec->drm_source);
2041 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2042 evdev_input_destroy(weston_seat);
2043err_sprite:
2044 destroy_sprites(ec);
2045err_egl:
2046 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2047 EGL_NO_CONTEXT);
2048 eglTerminate(ec->base.egl_display);
2049 eglReleaseThread();
2050 gbm_device_destroy(ec->gbm);
2051err_udev_dev:
2052 udev_device_unref(drm_device);
2053err_udev_enum:
2054 udev_enumerate_unref(e);
2055 tty_destroy(ec->tty);
2056err_udev:
2057 udev_unref(ec->udev);
2058err_compositor:
2059 weston_compositor_shutdown(&ec->base);
2060err_base:
2061 free(ec);
2062 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002063}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002064
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002065static int
2066set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2067{
2068 mode->flags = 0;
2069
2070 if (strcmp(hsync, "+hsync") == 0)
2071 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2072 else if (strcmp(hsync, "-hsync") == 0)
2073 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2074 else
2075 return -1;
2076
2077 if (strcmp(vsync, "+vsync") == 0)
2078 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2079 else if (strcmp(vsync, "-vsync") == 0)
2080 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2081 else
2082 return -1;
2083
2084 return 0;
2085}
2086
2087static int
2088check_for_modeline(struct drm_configured_output *output)
2089{
2090 drmModeModeInfo mode;
2091 char hsync[16];
2092 char vsync[16];
2093 char mode_name[16];
2094 float fclock;
2095
2096 mode.type = DRM_MODE_TYPE_USERDEF;
2097 mode.hskew = 0;
2098 mode.vscan = 0;
2099 mode.vrefresh = 0;
2100
2101 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2102 &fclock, &mode.hdisplay,
2103 &mode.hsync_start,
2104 &mode.hsync_end, &mode.htotal,
2105 &mode.vdisplay,
2106 &mode.vsync_start,
2107 &mode.vsync_end, &mode.vtotal,
2108 hsync, vsync) == 11) {
2109 if (set_sync_flags(&mode, hsync, vsync))
2110 return -1;
2111
2112 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2113 strcpy(mode.name, mode_name);
2114
2115 mode.clock = fclock * 1000;
2116 } else
2117 return -1;
2118
2119 output->crtc_mode = mode;
2120
2121 return 0;
2122}
2123
Scott Moreau8ab5d452012-07-30 19:51:08 -06002124static void
2125output_section_done(void *data)
2126{
2127 struct drm_configured_output *output;
2128
2129 output = malloc(sizeof *output);
2130
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002131 if (!output || !output_name || !output_mode) {
2132 free(output_name);
2133 output_name = NULL;
2134 free(output_mode);
2135 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002136 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002137 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002138
2139 output->config = OUTPUT_CONFIG_INVALID;
2140 output->name = output_name;
2141 output->mode = output_mode;
2142
2143 if (strcmp(output_mode, "off") == 0)
2144 output->config = OUTPUT_CONFIG_OFF;
2145 else if (strcmp(output_mode, "preferred") == 0)
2146 output->config = OUTPUT_CONFIG_PREFERRED;
2147 else if (strcmp(output_mode, "current") == 0)
2148 output->config = OUTPUT_CONFIG_CURRENT;
2149 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2150 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002151 else if (check_for_modeline(output) == 0)
2152 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002153
2154 if (output->config != OUTPUT_CONFIG_INVALID)
2155 wl_list_insert(&configured_output_list, &output->link);
2156 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002157 weston_log("Invalid mode \"%s\" for output %s\n",
2158 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002159 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002160 }
2161}
2162
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002163WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002164backend_init(struct wl_display *display, int argc, char *argv[],
2165 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002166{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002167 int connector = 0, tty = 0;
2168 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002169
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002170 const struct weston_option drm_options[] = {
2171 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2172 { WESTON_OPTION_STRING, "seat", 0, &seat },
2173 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002174 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002175 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002176
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002177 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002178
Scott Moreau8ab5d452012-07-30 19:51:08 -06002179 wl_list_init(&configured_output_list);
2180
2181 const struct config_key drm_config_keys[] = {
2182 { "name", CONFIG_KEY_STRING, &output_name },
2183 { "mode", CONFIG_KEY_STRING, &output_mode },
2184 };
2185
2186 const struct config_section config_section[] = {
2187 { "output", drm_config_keys,
2188 ARRAY_LENGTH(drm_config_keys), output_section_done },
2189 };
2190
2191 parse_config_file(config_file, config_section,
2192 ARRAY_LENGTH(config_section), NULL);
2193
Daniel Stonec1be8e52012-06-01 11:14:02 -04002194 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2195 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002196}