blob: 0ab1dadb61a14f20052aad5ff2fe39fe0636a1f9 [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"
Martin Minarik6d118362012-06-07 18:01:59 +020044#include "log.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Kristian Høgsberg061c4252012-06-28 11:28:15 -040046static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060047static char *output_name;
48static char *output_mode;
49static struct wl_list configured_output_list;
50
51enum output_config {
52 OUTPUT_CONFIG_INVALID = 0,
53 OUTPUT_CONFIG_OFF,
54 OUTPUT_CONFIG_PREFERRED,
55 OUTPUT_CONFIG_CURRENT,
56 OUTPUT_CONFIG_MODE
57};
58
59struct drm_configured_output {
60 char *name;
61 char *mode;
62 int32_t width, height;
63 enum output_config config;
64 struct wl_list link;
65};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040066
Kristian Høgsbergd553bfc2012-06-18 22:37:35 -040067enum {
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -040068 WESTON_PLANE_DRM_CURSOR = 0x100,
69 WESTON_PLANE_DRM_PLANE = 0x101,
70 WESTON_PLANE_DRM_FB = 0x102
Kristian Høgsbergd553bfc2012-06-18 22:37:35 -040071};
72
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050074 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040075
76 struct udev *udev;
77 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040078
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010079 struct udev_monitor *udev_monitor;
80 struct wl_event_source *udev_drm_source;
81
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010083 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010084 int fd;
85 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020086 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050087 uint32_t *crtcs;
88 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050089 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010090 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050091 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020092
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040093 struct gbm_surface *dummy_surface;
94 EGLSurface dummy_egl_surface;
95
Jesse Barnes58ef3792012-02-23 09:45:49 -050096 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050097 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -050098
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020099 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400100};
101
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400102struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500103 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400104 drmModeModeInfo mode_info;
105};
106
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300107struct drm_output;
108
109struct drm_fb {
110 struct gbm_bo *bo;
111 struct drm_output *output;
112 uint32_t fb_id;
113 int is_client_buffer;
114 struct wl_buffer *buffer;
115 struct wl_listener buffer_destroy_listener;
116};
117
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400118struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500119 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400120
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400121 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400122 uint32_t crtc_id;
123 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700124 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200125
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300126 int vblank_pending;
127 int page_flip_pending;
128
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400129 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400130 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400131 int current_cursor, cursor_free, cursor_x, cursor_y;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400132 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300133 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200134 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400135};
136
Jesse Barnes58ef3792012-02-23 09:45:49 -0500137/*
138 * An output has a primary display plane plus zero or more sprites for
139 * blending display contents.
140 */
141struct drm_sprite {
142 struct wl_list link;
143
144 uint32_t fb_id;
145 uint32_t pending_fb_id;
146 struct weston_surface *surface;
147 struct weston_surface *pending_surface;
148
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300149 struct drm_output *output;
150
Jesse Barnes58ef3792012-02-23 09:45:49 -0500151 struct drm_compositor *compositor;
152
153 struct wl_listener destroy_listener;
154 struct wl_listener pending_destroy_listener;
155
156 uint32_t possible_crtcs;
157 uint32_t plane_id;
158 uint32_t count_formats;
159
160 int32_t src_x, src_y;
161 uint32_t src_w, src_h;
162 uint32_t dest_x, dest_y;
163 uint32_t dest_w, dest_h;
164
165 uint32_t formats[];
166};
167
168static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500169drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
170{
171 struct weston_compositor *ec = output_base->compositor;
172 struct drm_compositor *c =(struct drm_compositor *) ec;
173 struct drm_output *output = (struct drm_output *) output_base;
174 int crtc;
175
176 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
177 if (c->crtcs[crtc] != output->crtc_id)
178 continue;
179
180 if (supported & (1 << crtc))
181 return -1;
182 }
183
184 return 0;
185}
186
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300187static void
188drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
189{
190 struct drm_fb *fb = data;
191 struct gbm_device *gbm = gbm_bo_get_device(bo);
192
193 if (fb->fb_id)
194 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
195
196 if (fb->buffer) {
197 weston_buffer_post_release(fb->buffer);
198 wl_list_remove(&fb->buffer_destroy_listener.link);
199 }
200
201 free(data);
202}
203
204static struct drm_fb *
205drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
206{
207 struct drm_fb *fb = gbm_bo_get_user_data(bo);
208 struct drm_compositor *compositor =
209 (struct drm_compositor *) output->base.compositor;
210 uint32_t width, height, stride, handle;
211 int ret;
212
213 if (fb)
214 return fb;
215
216 fb = malloc(sizeof *fb);
217
218 fb->bo = bo;
219 fb->output = output;
220 fb->is_client_buffer = 0;
221 fb->buffer = NULL;
222
223 width = gbm_bo_get_width(bo);
224 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400225 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300226 handle = gbm_bo_get_handle(bo).u32;
227
228 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
229 stride, handle, &fb->fb_id);
230 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200231 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232 free(fb);
233 return NULL;
234 }
235
236 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
237
238 return fb;
239}
240
241static void
242fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
243{
244 struct drm_fb *fb = container_of(listener, struct drm_fb,
245 buffer_destroy_listener);
246
247 fb->buffer = NULL;
248
249 if (fb == fb->output->next ||
250 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400251 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300252}
253
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500254static int
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400255drm_output_prepare_scanout_surface(struct weston_output *_output,
256 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500257{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400258 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500259 struct drm_compositor *c =
260 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300261 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500262
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500263 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200264 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200265 es->geometry.width != output->base.current->width ||
266 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200267 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400268 es->buffer == NULL)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500269 return -1;
270
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400271 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
272 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500273
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300274 /* Need to verify output->region contained in surface opaque
275 * region. Or maybe just that format doesn't have alpha.
276 * For now, scanout only if format is XRGB8888. */
277 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
278 gbm_bo_destroy(bo);
279 return -1;
280 }
281
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300282 output->next = drm_fb_get_from_bo(bo, output);
283 if (!output->next) {
284 gbm_bo_destroy(bo);
285 return -1;
286 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500287
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300288 output->next->is_client_buffer = 1;
289 output->next->buffer = es->buffer;
290 output->next->buffer->busy_count++;
291 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
292
293 wl_signal_add(&output->next->buffer->resource.destroy_signal,
294 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500295
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400296 es->plane = WESTON_PLANE_DRM_FB;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500297
298 return 0;
299}
300
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500301static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400302drm_output_render(struct drm_output *output, pixman_region32_t *damage)
303{
304 struct drm_compositor *compositor =
305 (struct drm_compositor *) output->base.compositor;
306 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300307 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400308
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400309 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
310 output->egl_surface,
311 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200312 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400313 return;
314 }
315
316 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400317 if (surface->plane == WESTON_PLANE_PRIMARY)
318 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400319
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400320 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600321
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400322 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300323 bo = gbm_surface_lock_front_buffer(output->surface);
324 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200325 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400326 return;
327 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300328
329 output->next = drm_fb_get_from_bo(bo, output);
330 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200331 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300332 gbm_surface_release_buffer(output->surface, bo);
333 return;
334 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400335}
336
337static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500338drm_output_repaint(struct weston_output *output_base,
339 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100340{
341 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500342 struct drm_compositor *compositor =
343 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500344 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400345 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500346 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100347
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300348 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400349 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300350 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400351 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100352
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400353 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400355 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400357 &output->connector_id, 1,
358 &mode->mode_info);
359 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200360 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400361 return;
362 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200363 }
364
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500365 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500367 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200368 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500369 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500370 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100371
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300372 output->page_flip_pending = 1;
373
Jesse Barnes58ef3792012-02-23 09:45:49 -0500374 /*
375 * Now, update all the sprite surfaces
376 */
377 wl_list_for_each(s, &compositor->sprite_list, link) {
378 uint32_t flags = 0;
379 drmVBlank vbl = {
380 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
381 .request.sequence = 1,
382 };
383
384 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
385 continue;
386
387 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
388 output->crtc_id, s->pending_fb_id, flags,
389 s->dest_x, s->dest_y,
390 s->dest_w, s->dest_h,
391 s->src_x, s->src_y,
392 s->src_w, s->src_h);
393 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200394 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500395 ret, strerror(errno));
396
397 /*
398 * Queue a vblank signal so we know when the surface
399 * becomes active on the display or has been replaced.
400 */
401 vbl.request.signal = (unsigned long)s;
402 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
403 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200404 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500405 ret, strerror(errno));
406 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300407
408 s->output = output;
409 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500410 }
411
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500412 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400413}
414
415static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500416vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
417 void *data)
418{
419 struct drm_sprite *s = (struct drm_sprite *)data;
420 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300421 struct drm_output *output = s->output;
422 uint32_t msecs;
423
424 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500425
426 if (s->surface) {
427 weston_buffer_post_release(s->surface->buffer);
428 wl_list_remove(&s->destroy_listener.link);
429 s->surface = NULL;
430 drmModeRmFB(c->drm.fd, s->fb_id);
431 s->fb_id = 0;
432 }
433
434 if (s->pending_surface) {
435 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400436 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
437 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500438 s->surface = s->pending_surface;
439 s->pending_surface = NULL;
440 s->fb_id = s->pending_fb_id;
441 s->pending_fb_id = 0;
442 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300443
444 if (!output->page_flip_pending) {
445 msecs = sec * 1000 + usec / 1000;
446 weston_output_finish_frame(&output->base, msecs);
447 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500448}
449
450static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400451page_flip_handler(int fd, unsigned int frame,
452 unsigned int sec, unsigned int usec, void *data)
453{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200454 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400455 uint32_t msecs;
456
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300457 output->page_flip_pending = 0;
458
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300459 if (output->current) {
460 if (output->current->is_client_buffer)
461 gbm_bo_destroy(output->current->bo);
462 else
463 gbm_surface_release_buffer(output->surface,
464 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200465 }
466
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300467 output->current = output->next;
468 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400469
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300470 if (!output->vblank_pending) {
471 msecs = sec * 1000 + usec / 1000;
472 weston_output_finish_frame(&output->base, msecs);
473 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200474}
475
476static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500477drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
478{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400479 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500480
481 for (i = 0; i < s->count_formats; i++)
482 if (s->formats[i] == format)
483 return 1;
484
485 return 0;
486}
487
488static int
489drm_surface_transform_supported(struct weston_surface *es)
490{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400491 struct weston_matrix *matrix = &es->transform.matrix;
492 int i;
493
494 if (!es->transform.enabled)
495 return 1;
496
497 for (i = 0; i < 16; i++) {
498 switch (i) {
499 case 10:
500 case 15:
501 if (matrix->d[i] != 1.0)
502 return 0;
503 break;
504 case 0:
505 case 5:
506 case 12:
507 case 13:
508 break;
509 default:
510 if (matrix->d[i] != 0.0)
511 return 0;
512 break;
513 }
514 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500515
516 return 1;
517}
518
Jesse Barnes58ef3792012-02-23 09:45:49 -0500519static void
520drm_disable_unused_sprites(struct weston_output *output_base)
521{
522 struct weston_compositor *ec = output_base->compositor;
523 struct drm_compositor *c =(struct drm_compositor *) ec;
524 struct drm_output *output = (struct drm_output *) output_base;
525 struct drm_sprite *s;
526 int ret;
527
528 wl_list_for_each(s, &c->sprite_list, link) {
529 if (s->pending_fb_id)
530 continue;
531
532 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
533 output->crtc_id, 0, 0,
534 0, 0, 0, 0, 0, 0, 0, 0);
535 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200536 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500537 ret, strerror(errno));
538 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300539
540 if (s->surface) {
541 s->surface = NULL;
542 wl_list_remove(&s->destroy_listener.link);
543 }
544
545 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500546 s->fb_id = 0;
547 s->pending_fb_id = 0;
548 }
549}
550
551/*
552 * This function must take care to damage any previously assigned surface
553 * if the sprite ends up binding to a different surface than in the
554 * previous frame.
555 */
556static int
557drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400558 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500559{
560 struct weston_compositor *ec = output_base->compositor;
561 struct drm_compositor *c =(struct drm_compositor *) ec;
562 struct drm_sprite *s;
563 int found = 0;
564 EGLint handle, stride;
565 struct gbm_bo *bo;
566 uint32_t fb_id = 0;
567 uint32_t handles[4], pitches[4], offsets[4];
568 int ret = 0;
569 pixman_region32_t dest_rect, src_rect;
570 pixman_box32_t *box;
571 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400572 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500573
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500574 if (c->sprites_are_broken)
575 return -1;
576
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300577 if (es->output_mask != (1u << output_base->id))
578 return -1;
579
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400580 if (es->buffer == NULL)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500581 return -1;
582
583 if (!drm_surface_transform_supported(es))
584 return -1;
585
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 wl_list_for_each(s, &c->sprite_list, link) {
587 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
588 continue;
589
590 if (!s->pending_fb_id) {
591 found = 1;
592 break;
593 }
594 }
595
596 /* No sprites available */
597 if (!found)
598 return -1;
599
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400600 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
601 es->buffer, GBM_BO_USE_SCANOUT);
602 if (!bo)
603 return -1;
604
Jesse Barnes58ef3792012-02-23 09:45:49 -0500605 format = gbm_bo_get_format(bo);
606 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400607 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608
609 gbm_bo_destroy(bo);
610
611 if (!drm_surface_format_supported(s, format))
612 return -1;
613
614 if (!handle)
615 return -1;
616
617 handles[0] = handle;
618 pitches[0] = stride;
619 offsets[0] = 0;
620
621 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
622 format, handles, pitches, offsets,
623 &fb_id, 0);
624 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200625 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500626 c->sprites_are_broken = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 return -1;
628 }
629
Jesse Barnes58ef3792012-02-23 09:45:49 -0500630 s->pending_fb_id = fb_id;
631 s->pending_surface = es;
632 es->buffer->busy_count++;
633
634 /*
635 * Calculate the source & dest rects properly based on actual
636 * postion (note the caller has called weston_surface_update_transform()
637 * for us already).
638 */
639 pixman_region32_init(&dest_rect);
640 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
641 &output_base->region);
642 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
643 box = pixman_region32_extents(&dest_rect);
644 s->dest_x = box->x1;
645 s->dest_y = box->y1;
646 s->dest_w = box->x2 - box->x1;
647 s->dest_h = box->y2 - box->y1;
648 pixman_region32_fini(&dest_rect);
649
650 pixman_region32_init(&src_rect);
651 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
652 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400654
655 weston_surface_from_global_fixed(es,
656 wl_fixed_from_int(box->x1),
657 wl_fixed_from_int(box->y1),
658 &sx1, &sy1);
659 weston_surface_from_global_fixed(es,
660 wl_fixed_from_int(box->x2),
661 wl_fixed_from_int(box->y2),
662 &sx2, &sy2);
663
664 if (sx1 < 0)
665 sx1 = 0;
666 if (sy1 < 0)
667 sy1 = 0;
668 if (sx2 > wl_fixed_from_int(es->geometry.width))
669 sx2 = wl_fixed_from_int(es->geometry.width);
670 if (sy2 > wl_fixed_from_int(es->geometry.height))
671 sy2 = wl_fixed_from_int(es->geometry.height);
672
673 s->src_x = sx1 << 8;
674 s->src_y = sy1 << 8;
675 s->src_w = (sx2 - sx1) << 8;
676 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500677 pixman_region32_fini(&src_rect);
678
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400679 es->plane = WESTON_PLANE_DRM_PLANE;
680
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400681 wl_signal_add(&es->buffer->resource.destroy_signal,
682 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400683
Jesse Barnes58ef3792012-02-23 09:45:49 -0500684 return 0;
685}
686
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500687static void
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400688drm_output_set_cursor(struct weston_output *output_base,
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400689 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500690{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400691 struct drm_output *output = (struct drm_output *) output_base;
692 struct drm_compositor *c =
693 (struct drm_compositor *) output->base.compositor;
694 EGLint handle, stride;
695 struct gbm_bo *bo;
696 uint32_t buf[64 * 64];
697 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400698 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500699
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400700 if (!output->cursor_free)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500701 return;
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400702 if (es->output_mask != (1u << output_base->id))
703 return;
704 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
705 es->geometry.width > 64 || es->geometry.height > 64)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400706 return;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500707
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400708 if (es->buffer && pixman_region32_not_empty(&es->damage)) {
709 output->current_cursor ^= 1;
710 bo = output->cursor_bo[output->current_cursor];
711 memset(buf, 0, sizeof buf);
712 stride = wl_shm_buffer_get_stride(es->buffer);
713 s = wl_shm_buffer_get_data(es->buffer);
714 for (i = 0; i < es->geometry.height; i++)
715 memcpy(buf + i * 64, s + i * stride,
716 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500717
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400718 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
719 return;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400720
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400721 handle = gbm_bo_get_handle(bo).s32;
722 if (drmModeSetCursor(c->drm.fd,
723 output->crtc_id, handle, 64, 64)) {
724 weston_log("failed to set cursor: %n\n");
725 return;
726 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400727 }
728
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400729 x = es->geometry.x - output->base.x;
730 y = es->geometry.y - output->base.y;
731 if (output->cursor_x != x || output->cursor_y != y) {
732 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
733 weston_log("failed to move cursor: %m\n");
734 return;
735 }
736 output->cursor_x = x;
737 output->cursor_y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400738 }
739
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400740 es->plane = WESTON_PLANE_DRM_CURSOR;
741 output->cursor_free = 0;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500742}
743
Jesse Barnes58ef3792012-02-23 09:45:49 -0500744static void
745drm_assign_planes(struct weston_output *output)
746{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400747 struct drm_compositor *c =
748 (struct drm_compositor *) output->compositor;
749 struct drm_output *drm_output = (struct drm_output *) output;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400750 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500751 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400752 int prev_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500753
754 /*
755 * Find a surface for each sprite in the output using some heuristics:
756 * 1) size
757 * 2) frequency of update
758 * 3) opacity (though some hw might support alpha blending)
759 * 4) clipping (this can be fixed with color keys)
760 *
761 * The idea is to save on blitting since this should save power.
762 * If we can get a large video surface on the sprite for example,
763 * the main display surface may not need to update at all, and
764 * the client buffer can be used directly for the sprite surface
765 * as we do for flipping full screen surfaces.
766 */
767 pixman_region32_init(&overlap);
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400768 drm_output->cursor_free = 1;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400769 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770 pixman_region32_init(&surface_overlap);
771 pixman_region32_intersect(&surface_overlap, &overlap,
772 &es->transform.boundingbox);
773
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400774 prev_plane = es->plane;
775 es->plane = WESTON_PLANE_PRIMARY;
776 if (pixman_region32_not_empty(&surface_overlap))
777 goto bail;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500778
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400779 if (es->plane == WESTON_PLANE_PRIMARY)
780 drm_output_set_cursor(output, es);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400781 if (es->plane == WESTON_PLANE_PRIMARY)
782 drm_output_prepare_scanout_surface(output, es);
783 if (es->plane == WESTON_PLANE_PRIMARY)
784 drm_output_prepare_overlay_surface(output, es);
785
786 bail:
787 if (es->plane == WESTON_PLANE_PRIMARY)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500788 pixman_region32_union(&overlap, &overlap,
789 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400790
791 if (prev_plane != WESTON_PLANE_PRIMARY &&
792 es->plane == WESTON_PLANE_PRIMARY)
793 weston_surface_damage(es);
794 else if (prev_plane == WESTON_PLANE_PRIMARY &&
795 es->plane != WESTON_PLANE_PRIMARY)
796 weston_surface_damage_below(es);
797
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798 pixman_region32_fini(&surface_overlap);
799 }
800 pixman_region32_fini(&overlap);
801
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400802 if (drm_output->cursor_free)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400803 drmModeSetCursor(c->drm.fd, drm_output->crtc_id, 0, 0, 0);
Kristian Høgsbergf2735ea2012-06-20 23:03:53 -0400804
Jesse Barnes58ef3792012-02-23 09:45:49 -0500805 drm_disable_unused_sprites(output);
806}
807
Matt Roper361d2ad2011-08-29 13:52:23 -0700808static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500809drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700810{
811 struct drm_output *output = (struct drm_output *) output_base;
812 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200813 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700814 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700815
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200816 if (output->backlight)
817 backlight_destroy(output->backlight);
818
Matt Roper361d2ad2011-08-29 13:52:23 -0700819 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400820 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700821
822 /* Restore original CRTC state */
823 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200824 origcrtc->x, origcrtc->y,
825 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700826 drmModeFreeCrtc(origcrtc);
827
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200828 c->crtc_allocator &= ~(1 << output->crtc_id);
829 c->connector_allocator &= ~(1 << output->connector_id);
830
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400831 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400832 gbm_surface_destroy(output->surface);
833
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500834 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200835 wl_list_remove(&output->base.link);
836
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400837 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700838 free(output);
839}
840
Alex Wub7b8bda2012-04-17 17:20:48 +0800841static struct drm_mode *
842choose_mode (struct drm_output *output, struct weston_mode *target_mode)
843{
844 struct drm_mode *tmp_mode = NULL, *mode;
845
846 if (output->base.current->width == target_mode->width &&
847 output->base.current->height == target_mode->height &&
848 (output->base.current->refresh == target_mode->refresh ||
849 target_mode->refresh == 0))
850 return (struct drm_mode *)output->base.current;
851
852 wl_list_for_each(mode, &output->base.mode_list, base.link) {
853 if (mode->mode_info.hdisplay == target_mode->width &&
854 mode->mode_info.vdisplay == target_mode->height) {
855 if (mode->mode_info.vrefresh == target_mode->refresh ||
856 target_mode->refresh == 0) {
857 return mode;
858 } else if (!tmp_mode)
859 tmp_mode = mode;
860 }
861 }
862
863 return tmp_mode;
864}
865
866static int
867drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
868{
869 struct drm_output *output;
870 struct drm_mode *drm_mode;
871 int ret;
872 struct drm_compositor *ec;
873 struct gbm_surface *surface;
874 EGLSurface egl_surface;
875
876 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200877 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800878 return -1;
879 }
880
881 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200882 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800883 return -1;
884 }
885
886 ec = (struct drm_compositor *)output_base->compositor;
887 output = (struct drm_output *)output_base;
888 drm_mode = choose_mode (output, mode);
889
890 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200891 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800892 return -1;
893 } else if (&drm_mode->base == output->base.current) {
894 return 0;
895 } else if (drm_mode->base.width == output->base.current->width &&
896 drm_mode->base.height == output->base.current->height) {
897 /* only change refresh value */
898 ret = drmModeSetCrtc(ec->drm.fd,
899 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300900 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800901 &output->connector_id, 1, &drm_mode->mode_info);
902
903 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200904 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800905 drm_mode->base.width,
906 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400907 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800908 ret = -1;
909 } else {
910 output->base.current->flags = 0;
911 output->base.current = &drm_mode->base;
912 drm_mode->base.flags =
913 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
914 ret = 0;
915 }
916
917 return ret;
918 }
919
920 drm_mode->base.flags =
921 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
922
923 surface = gbm_surface_create(ec->gbm,
924 drm_mode->base.width,
925 drm_mode->base.height,
926 GBM_FORMAT_XRGB8888,
927 GBM_BO_USE_SCANOUT |
928 GBM_BO_USE_RENDERING);
929 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200930 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800931 return -1;
932 }
933
934 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400935 eglCreateWindowSurface(ec->base.egl_display,
936 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800937 surface, NULL);
938
939 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200940 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800941 goto err;
942 }
943
944 ret = drmModeSetCrtc(ec->drm.fd,
945 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300946 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800947 &output->connector_id, 1, &drm_mode->mode_info);
948 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200949 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800950 goto err;
951 }
952
953 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300954 if (output->current) {
955 if (output->current->is_client_buffer)
956 gbm_bo_destroy(output->current->bo);
957 else
958 gbm_surface_release_buffer(output->surface,
959 output->current->bo);
960 }
961 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800962
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300963 if (output->next) {
964 if (output->next->is_client_buffer)
965 gbm_bo_destroy(output->next->bo);
966 else
967 gbm_surface_release_buffer(output->surface,
968 output->next->bo);
969 }
970 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800971
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400972 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800973 gbm_surface_destroy(output->surface);
974 output->egl_surface = egl_surface;
975 output->surface = surface;
976
977 /*update output*/
978 output->base.current = &drm_mode->base;
979 output->base.dirty = 1;
980 weston_output_move(&output->base, output->base.x, output->base.y);
981 return 0;
982
983err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400984 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800985 gbm_surface_destroy(surface);
986 return -1;
987}
988
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400989static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400990on_drm_input(int fd, uint32_t mask, void *data)
991{
992 drmEventContext evctx;
993
994 memset(&evctx, 0, sizeof evctx);
995 evctx.version = DRM_EVENT_CONTEXT_VERSION;
996 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500997 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400998 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400999
1000 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001001}
1002
1003static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001004init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001005{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001006 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001007 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001008 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001009 static const EGLint context_attribs[] = {
1010 EGL_CONTEXT_CLIENT_VERSION, 2,
1011 EGL_NONE
1012 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001013
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001014 static const EGLint config_attribs[] = {
1015 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1016 EGL_RED_SIZE, 1,
1017 EGL_GREEN_SIZE, 1,
1018 EGL_BLUE_SIZE, 1,
1019 EGL_ALPHA_SIZE, 0,
1020 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1021 EGL_NONE
1022 };
1023
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001024 sysnum = udev_device_get_sysnum(device);
1025 if (sysnum)
1026 ec->drm.id = atoi(sysnum);
1027 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001028 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001029 return -1;
1030 }
1031
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001032 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001033 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001034 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001035 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001036 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001037 udev_device_get_devnode(device));
1038 return -1;
1039 }
1040
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001041 weston_log("using %s\n", filename);
1042
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001043 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001044 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001045 ec->base.egl_display = eglGetDisplay(ec->gbm);
1046 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001047 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001048 return -1;
1049 }
1050
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001051 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001052 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001053 return -1;
1054 }
1055
Darxus55973f22010-11-22 21:24:39 -05001056 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001057 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001058 return -1;
1059 }
1060
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001061 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1062 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001063 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001064 return -1;
1065 }
1066
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001067 ec->base.egl_context =
1068 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1069 EGL_NO_CONTEXT, context_attribs);
1070 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001071 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001072 return -1;
1073 }
1074
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001075 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1076 GBM_FORMAT_XRGB8888,
1077 GBM_BO_USE_RENDERING);
1078 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001079 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001080 return -1;
1081 }
1082
1083 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001084 eglCreateWindowSurface(ec->base.egl_display,
1085 ec->base.egl_config,
1086 ec->dummy_surface,
1087 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001088 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001089 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001090 return -1;
1091 }
1092
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001093 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1094 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001095 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001096 return -1;
1097 }
1098
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001099 return 0;
1100}
1101
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001102static int
1103drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1104{
1105 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001106 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001107
1108 mode = malloc(sizeof *mode);
1109 if (mode == NULL)
1110 return -1;
1111
1112 mode->base.flags = 0;
1113 mode->base.width = info->hdisplay;
1114 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001115
1116 /* Calculate higher precision (mHz) refresh rate */
1117 refresh = (info->clock * 1000000LL / info->htotal +
1118 info->vtotal / 2) / info->vtotal;
1119
1120 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1121 refresh *= 2;
1122 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1123 refresh /= 2;
1124 if (info->vscan > 1)
1125 refresh /= info->vscan;
1126
1127 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001128 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001129
1130 if (info->type & DRM_MODE_TYPE_PREFERRED)
1131 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1132
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001133 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1134
1135 return 0;
1136}
1137
1138static int
1139drm_subpixel_to_wayland(int drm_value)
1140{
1141 switch (drm_value) {
1142 default:
1143 case DRM_MODE_SUBPIXEL_UNKNOWN:
1144 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1145 case DRM_MODE_SUBPIXEL_NONE:
1146 return WL_OUTPUT_SUBPIXEL_NONE;
1147 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1148 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1149 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1150 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1151 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1152 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1153 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1154 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1155 }
1156}
1157
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001158static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001159sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001160{
1161 struct drm_sprite *sprite =
1162 container_of(listener, struct drm_sprite,
1163 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001164 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001165
1166 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001167 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1168 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001169}
1170
1171static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001172sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001173{
1174 struct drm_sprite *sprite =
1175 container_of(listener, struct drm_sprite,
1176 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001177 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001178
1179 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001180 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1181 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001182}
1183
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001184/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001185static uint32_t
1186drm_get_backlight(struct drm_output *output)
1187{
1188 long brightness, max_brightness, norm;
1189
1190 brightness = backlight_get_brightness(output->backlight);
1191 max_brightness = backlight_get_max_brightness(output->backlight);
1192
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001193 /* convert it on a scale of 0 to 255 */
1194 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001195
1196 return (uint32_t) norm;
1197}
1198
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001199/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001200static void
1201drm_set_backlight(struct weston_output *output_base, uint32_t value)
1202{
1203 struct drm_output *output = (struct drm_output *) output_base;
1204 long max_brightness, new_brightness;
1205
1206 if (!output->backlight)
1207 return;
1208
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001209 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001210 return;
1211
1212 max_brightness = backlight_get_max_brightness(output->backlight);
1213
1214 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001215 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001216
1217 backlight_set_brightness(output->backlight, new_brightness);
1218}
1219
1220static drmModePropertyPtr
1221drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1222{
1223 drmModePropertyPtr props;
1224 int i;
1225
1226 for (i = 0; i < connector->count_props; i++) {
1227 props = drmModeGetProperty(fd, connector->props[i]);
1228 if (!props)
1229 continue;
1230
1231 if (!strcmp(props->name, name))
1232 return props;
1233
1234 drmModeFreeProperty(props);
1235 }
1236
1237 return NULL;
1238}
1239
1240static void
1241drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1242{
1243 struct drm_output *output = (struct drm_output *) output_base;
1244 struct weston_compositor *ec = output_base->compositor;
1245 struct drm_compositor *c = (struct drm_compositor *) ec;
1246 drmModeConnectorPtr connector;
1247 drmModePropertyPtr prop;
1248
1249 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1250 if (!connector)
1251 return;
1252
1253 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1254 if (!prop) {
1255 drmModeFreeConnector(connector);
1256 return;
1257 }
1258
1259 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1260 prop->prop_id, level);
1261 drmModeFreeProperty(prop);
1262 drmModeFreeConnector(connector);
1263}
1264
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001265static const char *connector_type_names[] = {
1266 "None",
1267 "VGA",
1268 "DVI",
1269 "DVI",
1270 "DVI",
1271 "Composite",
1272 "TV",
1273 "LVDS",
1274 "CTV",
1275 "DIN",
1276 "DP",
1277 "HDMI",
1278 "HDMI",
1279 "TV",
1280 "eDP",
1281};
1282
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001283static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001284find_crtc_for_connector(struct drm_compositor *ec,
1285 drmModeRes *resources, drmModeConnector *connector)
1286{
1287 drmModeEncoder *encoder;
1288 uint32_t possible_crtcs;
1289 int i, j;
1290
1291 for (j = 0; j < connector->count_encoders; j++) {
1292 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1293 if (encoder == NULL) {
1294 weston_log("Failed to get encoder.\n");
1295 return -1;
1296 }
1297 possible_crtcs = encoder->possible_crtcs;
1298 drmModeFreeEncoder(encoder);
1299
1300 for (i = 0; i < resources->count_crtcs; i++) {
1301 if (possible_crtcs & (1 << i) &&
1302 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1303 return i;
1304 }
1305 }
1306
1307 return -1;
1308}
1309
1310static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001311create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001312 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001313 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001314 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001315{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001316 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001317 struct drm_mode *drm_mode, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001318 struct weston_mode *m, *preferred, *current, *configured;
1319 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001320 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001321 drmModeModeInfo crtc_mode;
1322 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001323 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001324 char name[32];
1325 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001326
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001327 i = find_crtc_for_connector(ec, resources, connector);
1328 if (i < 0) {
1329 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001330 return -1;
1331 }
1332
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001333 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001334 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001335 return -1;
1336
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001337 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001338 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1339 output->base.make = "unknown";
1340 output->base.model = "unknown";
1341 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001342
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001343 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1344 type_name = connector_type_names[connector->connector_type];
1345 else
1346 type_name = "UNKNOWN";
1347 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1348 output->name = strdup(name);
1349
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001350 output->crtc_id = resources->crtcs[i];
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001351 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001352 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001353 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001354
Matt Roper361d2ad2011-08-29 13:52:23 -07001355 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1356
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001357 /* Get the current mode on the crtc that's currently driving
1358 * this connector. */
1359 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001360 memset(&crtc_mode, 0, sizeof crtc_mode);
1361 if (encoder != NULL) {
1362 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1363 drmModeFreeEncoder(encoder);
1364 if (crtc == NULL)
1365 goto err_free;
1366 if (crtc->mode_valid)
1367 crtc_mode = crtc->mode;
1368 drmModeFreeCrtc(crtc);
1369 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001370
David Herrmann0f0d54e2011-12-08 17:05:45 +01001371 for (i = 0; i < connector->count_modes; i++) {
1372 ret = drm_output_add_mode(output, &connector->modes[i]);
1373 if (ret)
1374 goto err_free;
1375 }
1376
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001377 preferred = NULL;
1378 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001379 configured = NULL;
1380
1381 wl_list_for_each(temp, &configured_output_list, link) {
1382 if (strcmp(temp->name, output->name) == 0) {
1383 weston_log("%s mode \"%s\" in config\n",
1384 temp->name, temp->mode);
1385 o = temp;
1386 break;
1387 }
1388 }
1389
1390 if (o && strcmp("off", o->mode) == 0) {
1391 weston_log("Disabling output %s\n", o->name);
1392
1393 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1394 0, 0, 0, 0, 0, NULL);
1395 goto err_free;
1396 }
1397
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001398 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001399 if (o && o->width == drm_mode->base.width &&
1400 o->height == drm_mode->base.height)
1401 configured = &drm_mode->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001402 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001403 current = &drm_mode->base;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001404 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1405 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001406 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001407
Wang Quanxianacb805a2012-07-30 18:09:46 -04001408 if (current == NULL && crtc_mode.clock != 0) {
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001409 ret = drm_output_add_mode(output, &crtc_mode);
1410 if (ret)
1411 goto err_free;
1412 current = container_of(output->base.mode_list.prev,
1413 struct weston_mode, link);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001414 }
1415
Scott Moreau8ab5d452012-07-30 19:51:08 -06001416 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1417 configured = current;
1418
Wang Quanxianacb805a2012-07-30 18:09:46 -04001419 if (option_current_mode && current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 output->base.current = current;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001421 else if (configured)
1422 output->base.current = configured;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001423 else if (preferred)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001424 output->base.current = preferred;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001425 else if (current)
1426 output->base.current = current;
1427
1428 if (output->base.current == NULL) {
1429 weston_log("no available modes for %s\n", output->name);
1430 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001431 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001432
Wang Quanxianacb805a2012-07-30 18:09:46 -04001433 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1434
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001435 output->surface = gbm_surface_create(ec->gbm,
1436 output->base.current->width,
1437 output->base.current->height,
1438 GBM_FORMAT_XRGB8888,
1439 GBM_BO_USE_SCANOUT |
1440 GBM_BO_USE_RENDERING);
1441 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001442 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001443 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001444 }
1445
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001446 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001447 eglCreateWindowSurface(ec->base.egl_display,
1448 ec->base.egl_config,
1449 output->surface,
1450 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001451 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001452 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001453 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001454 }
1455
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001456 output->cursor_bo[0] =
1457 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1458 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1459 output->cursor_bo[1] =
1460 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1461 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1462
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001463 output->backlight = backlight_init(drm_device,
1464 connector->connector_type);
1465 if (output->backlight) {
1466 output->base.set_backlight = drm_set_backlight;
1467 output->base.backlight_current = drm_get_backlight(output);
1468 }
1469
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001470 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001471 connector->mmWidth, connector->mmHeight,
1472 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001473
1474 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1475
Alex Wubd3354b2012-04-17 17:20:49 +08001476 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001477 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001478 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001479 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001480 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001481 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001482
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001483 weston_log("Output %s, (connector %d, crtc %d)\n",
1484 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001485 wl_list_for_each(m, &output->base.mode_list, link)
1486 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1487 m->width, m->height, m->refresh / 1000.0,
1488 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1489 ", preferred" : "",
1490 m->flags & WL_OUTPUT_MODE_CURRENT ?
1491 ", current" : "",
1492 connector->count_modes == 0 ?
1493 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001494
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001495 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001496
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001497err_surface:
1498 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001499err_free:
1500 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1501 base.link) {
1502 wl_list_remove(&drm_mode->base.link);
1503 free(drm_mode);
1504 }
1505
1506 drmModeFreeCrtc(output->original_crtc);
1507 ec->crtc_allocator &= ~(1 << output->crtc_id);
1508 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001509 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001510 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001511
David Herrmann0f0d54e2011-12-08 17:05:45 +01001512 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001513}
1514
Jesse Barnes58ef3792012-02-23 09:45:49 -05001515static void
1516create_sprites(struct drm_compositor *ec)
1517{
1518 struct drm_sprite *sprite;
1519 drmModePlaneRes *plane_res;
1520 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001521 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001522
1523 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1524 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001525 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001526 strerror(errno));
1527 return;
1528 }
1529
1530 for (i = 0; i < plane_res->count_planes; i++) {
1531 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1532 if (!plane)
1533 continue;
1534
1535 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1536 plane->count_formats));
1537 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001538 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001539 __func__);
1540 free(plane);
1541 continue;
1542 }
1543
1544 memset(sprite, 0, sizeof *sprite);
1545
1546 sprite->possible_crtcs = plane->possible_crtcs;
1547 sprite->plane_id = plane->plane_id;
1548 sprite->surface = NULL;
1549 sprite->pending_surface = NULL;
1550 sprite->fb_id = 0;
1551 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001552 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1553 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001554 sprite_handle_pending_buffer_destroy;
1555 sprite->compositor = ec;
1556 sprite->count_formats = plane->count_formats;
1557 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001558 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001559 drmModeFreePlane(plane);
1560
1561 wl_list_insert(&ec->sprite_list, &sprite->link);
1562 }
1563
1564 free(plane_res->planes);
1565 free(plane_res);
1566}
1567
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001568static void
1569destroy_sprites(struct drm_compositor *compositor)
1570{
1571 struct drm_sprite *sprite, *next;
1572 struct drm_output *output;
1573
1574 output = container_of(compositor->base.output_list.next,
1575 struct drm_output, base.link);
1576
1577 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1578 drmModeSetPlane(compositor->drm.fd,
1579 sprite->plane_id,
1580 output->crtc_id, 0, 0,
1581 0, 0, 0, 0, 0, 0, 0, 0);
1582 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1583 free(sprite);
1584 }
1585}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001586
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001587static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001588create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001589 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001590{
1591 drmModeConnector *connector;
1592 drmModeRes *resources;
1593 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001594 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001595
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001596 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001597 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001598 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001599 return -1;
1600 }
1601
Jesse Barnes58ef3792012-02-23 09:45:49 -05001602 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001603 if (!ec->crtcs) {
1604 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001605 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001606 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001607
1608 ec->num_crtcs = resources->count_crtcs;
1609 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1610
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001611 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001612 connector = drmModeGetConnector(ec->drm.fd,
1613 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001614 if (connector == NULL)
1615 continue;
1616
1617 if (connector->connection == DRM_MODE_CONNECTED &&
1618 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001619 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001620 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001621 connector, x, y,
1622 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001623 drmModeFreeConnector(connector);
1624 continue;
1625 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001626
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001627 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001628 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001629 link)->current->width;
1630 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001631
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001632 drmModeFreeConnector(connector);
1633 }
1634
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001635 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001636 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001637 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001638 return -1;
1639 }
1640
1641 drmModeFreeResources(resources);
1642
1643 return 0;
1644}
1645
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001646static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001647update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001648{
1649 drmModeConnector *connector;
1650 drmModeRes *resources;
1651 struct drm_output *output, *next;
1652 int x = 0, y = 0;
1653 int x_offset = 0, y_offset = 0;
1654 uint32_t connected = 0, disconnects = 0;
1655 int i;
1656
1657 resources = drmModeGetResources(ec->drm.fd);
1658 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001659 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001660 return;
1661 }
1662
1663 /* collect new connects */
1664 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001665 int connector_id = resources->connectors[i];
1666
1667 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001668 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001669 continue;
1670
David Herrmann7551cff2011-12-08 17:05:43 +01001671 if (connector->connection != DRM_MODE_CONNECTED) {
1672 drmModeFreeConnector(connector);
1673 continue;
1674 }
1675
Benjamin Franzke117483d2011-08-30 11:38:26 +02001676 connected |= (1 << connector_id);
1677
1678 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001679 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001680 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001681 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001682
1683 /* XXX: not yet needed, we die with 0 outputs */
1684 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001685 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001686 else
1687 x = 0;
1688 y = 0;
1689 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001690 connector, x, y,
1691 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001692 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001693
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001694 }
1695 drmModeFreeConnector(connector);
1696 }
1697 drmModeFreeResources(resources);
1698
1699 disconnects = ec->connector_allocator & ~connected;
1700 if (disconnects) {
1701 wl_list_for_each_safe(output, next, &ec->base.output_list,
1702 base.link) {
1703 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001704 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001705 output->base.x - x_offset,
1706 output->base.y - y_offset);
1707 }
1708
1709 if (disconnects & (1 << output->connector_id)) {
1710 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001711 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001712 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001713 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001714 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001715 }
1716 }
1717 }
1718
1719 /* FIXME: handle zero outputs, without terminating */
1720 if (ec->connector_allocator == 0)
1721 wl_display_terminate(ec->base.wl_display);
1722}
1723
1724static int
David Herrmannd7488c22012-03-11 20:05:21 +01001725udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001726{
David Herrmannd7488c22012-03-11 20:05:21 +01001727 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001728 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001729
1730 sysnum = udev_device_get_sysnum(device);
1731 if (!sysnum || atoi(sysnum) != ec->drm.id)
1732 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001733
David Herrmann6ac52db2012-03-11 20:05:22 +01001734 val = udev_device_get_property_value(device, "HOTPLUG");
1735 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001736 return 0;
1737
David Herrmann6ac52db2012-03-11 20:05:22 +01001738 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001739}
1740
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001741static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001742udev_drm_event(int fd, uint32_t mask, void *data)
1743{
1744 struct drm_compositor *ec = data;
1745 struct udev_device *event;
1746
1747 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001748
David Herrmannd7488c22012-03-11 20:05:21 +01001749 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001750 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001751
1752 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001753
1754 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001755}
1756
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001757static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001758drm_restore(struct weston_compositor *ec)
1759{
1760 struct drm_compositor *d = (struct drm_compositor *) ec;
1761
1762 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1763 weston_log("failed to drop master: %m\n");
1764 tty_reset(d->tty);
1765}
1766
1767static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001768drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001769{
1770 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001771 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001772 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001773
Daniel Stone37816df2012-05-16 18:45:18 +01001774 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1775 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001776 wl_list_for_each_safe(o, n, &configured_output_list, link)
1777 free(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001778
1779 wl_event_source_remove(d->udev_drm_source);
1780 wl_event_source_remove(d->drm_source);
1781
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001782 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001783
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001784 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001785 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001786 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001787 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001788 eglReleaseThread();
1789
Matt Roper361d2ad2011-08-29 13:52:23 -07001790 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001791 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001792 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001793 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001794 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001795
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001796 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001797}
1798
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001799static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001800drm_compositor_set_modes(struct drm_compositor *compositor)
1801{
1802 struct drm_output *output;
1803 struct drm_mode *drm_mode;
1804 int ret;
1805
1806 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1807 drm_mode = (struct drm_mode *) output->base.current;
1808 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001809 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001810 &output->connector_id, 1,
1811 &drm_mode->mode_info);
1812 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001813 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001814 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001815 drm_mode->base.width, drm_mode->base.height,
1816 output->base.x, output->base.y);
1817 }
1818 }
1819}
1820
1821static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001822vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001823{
1824 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001825 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001826 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001827 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001828
1829 switch (event) {
1830 case TTY_ENTER_VT:
1831 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001832 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001833 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001834 wl_display_terminate(compositor->wl_display);
1835 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001836 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001837 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001838 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01001839 wl_list_for_each(seat, &compositor->seat_list, link) {
1840 evdev_add_devices(ec->udev, seat);
1841 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02001842 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001843 break;
1844 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01001845 wl_list_for_each(seat, &compositor->seat_list, link) {
1846 evdev_disable_udev_monitor(seat);
1847 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04001848 }
1849
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001850 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001851 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001852 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04001853
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001854 /* If we have a repaint scheduled (either from a
1855 * pending pageflip or the idle handler), make sure we
1856 * cancel that so we don't try to pageflip when we're
1857 * vt switched away. The SLEEPING state will prevent
1858 * further attemps at repainting. When we switch
1859 * back, we schedule a repaint, which will process
1860 * pending frame callbacks. */
1861
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001862 wl_list_for_each(output, &ec->base.output_list, base.link) {
1863 output->base.repaint_needed = 0;
1864 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001865 }
1866
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001867 output = container_of(ec->base.output_list.next,
1868 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001869
1870 wl_list_for_each(sprite, &ec->sprite_list, link)
1871 drmModeSetPlane(ec->drm.fd,
1872 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001873 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001874 0, 0, 0, 0, 0, 0, 0, 0);
1875
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001876 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001877 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001878
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001879 break;
1880 };
1881}
1882
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001883static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01001884switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001885{
1886 struct drm_compositor *ec = data;
1887
Daniel Stone325fc2d2012-05-30 16:31:58 +01001888 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001889}
1890
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001891static const char default_seat[] = "seat0";
1892
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001893static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001894drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04001895 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04001896 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001897{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001898 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001899 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001900 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001901 struct udev_device *device, *drm_device;
1902 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001903 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001904 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001905 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001906
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001907 weston_log("initializing drm backend\n");
1908
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001909 ec = malloc(sizeof *ec);
1910 if (ec == NULL)
1911 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001912 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01001913
1914 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01001915 config_file) < 0) {
1916 weston_log("weston_compositor_init failed\n");
1917 goto err_base;
1918 }
Daniel Stone725c2c32012-06-22 14:04:36 +01001919
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001920 ec->udev = udev_new();
1921 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001922 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001923 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001924 }
1925
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001926 ec->base.wl_display = display;
1927 ec->tty = tty_create(&ec->base, vt_func, tty);
1928 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02001929 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001930 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001931 }
1932
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001933 e = udev_enumerate_new(ec->udev);
1934 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02001935 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001936
Benjamin Franzke117483d2011-08-30 11:38:26 +02001937 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001938 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001939 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001940 path = udev_list_entry_get_name(entry);
1941 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001942 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001943 udev_device_get_property_value(device, "ID_SEAT");
1944 if (!device_seat)
1945 device_seat = default_seat;
1946 if (strcmp(device_seat, seat) == 0) {
1947 drm_device = device;
1948 break;
1949 }
1950 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001951 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001952
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001953 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001954 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001955 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001956 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001957
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001958 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001959 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001960 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001961 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001962
1963 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001964 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02001965
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001966 ec->base.focus = 1;
1967
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001968 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001969
Daniel Stone725c2c32012-06-22 14:04:36 +01001970 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01001971 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02001972
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001973 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01001974 weston_compositor_add_key_binding(&ec->base, key,
1975 MODIFIER_CTRL | MODIFIER_ALT,
1976 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001977
Jesse Barnes58ef3792012-02-23 09:45:49 -05001978 wl_list_init(&ec->sprite_list);
1979 create_sprites(ec);
1980
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001981 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001982 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01001983 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001984 }
1985
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02001986 path = NULL;
1987
Tiago Vignattice03ec32011-12-19 01:14:03 +02001988 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001989
1990 loop = wl_display_get_event_loop(ec->base.wl_display);
1991 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001992 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001993 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001994
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001995 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
1996 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001997 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001998 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001999 }
2000 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2001 "drm", NULL);
2002 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002003 wl_event_loop_add_fd(loop,
2004 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002005 WL_EVENT_READABLE, udev_drm_event, ec);
2006
2007 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002008 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002009 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002010 }
2011
Daniel Stonea96b93c2012-06-22 14:04:37 +01002012 udev_device_unref(drm_device);
2013 udev_enumerate_unref(e);
2014
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002015 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002016
2017err_udev_monitor:
2018 wl_event_source_remove(ec->udev_drm_source);
2019 udev_monitor_unref(ec->udev_monitor);
2020err_drm_source:
2021 wl_event_source_remove(ec->drm_source);
2022 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2023 evdev_input_destroy(weston_seat);
2024err_sprite:
2025 destroy_sprites(ec);
2026err_egl:
2027 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2028 EGL_NO_CONTEXT);
2029 eglTerminate(ec->base.egl_display);
2030 eglReleaseThread();
2031 gbm_device_destroy(ec->gbm);
2032err_udev_dev:
2033 udev_device_unref(drm_device);
2034err_udev_enum:
2035 udev_enumerate_unref(e);
2036 tty_destroy(ec->tty);
2037err_udev:
2038 udev_unref(ec->udev);
2039err_compositor:
2040 weston_compositor_shutdown(&ec->base);
2041err_base:
2042 free(ec);
2043 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002044}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002045
Scott Moreau8ab5d452012-07-30 19:51:08 -06002046static void
2047output_section_done(void *data)
2048{
2049 struct drm_configured_output *output;
2050
2051 output = malloc(sizeof *output);
2052
2053 if (!output)
2054 return;
2055
2056 output->config = OUTPUT_CONFIG_INVALID;
2057 output->name = output_name;
2058 output->mode = output_mode;
2059
2060 if (strcmp(output_mode, "off") == 0)
2061 output->config = OUTPUT_CONFIG_OFF;
2062 else if (strcmp(output_mode, "preferred") == 0)
2063 output->config = OUTPUT_CONFIG_PREFERRED;
2064 else if (strcmp(output_mode, "current") == 0)
2065 output->config = OUTPUT_CONFIG_CURRENT;
2066 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2067 output->config = OUTPUT_CONFIG_MODE;
2068
2069 if (output->config != OUTPUT_CONFIG_INVALID)
2070 wl_list_insert(&configured_output_list, &output->link);
2071 else {
2072 free(output);
2073 weston_log("Invalid mode \"%s\" for output %s\n",
2074 output_mode, output_name);
2075 }
2076}
2077
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002078WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002079backend_init(struct wl_display *display, int argc, char *argv[],
2080 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002081{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002082 int connector = 0, tty = 0;
2083 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002084
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002085 const struct weston_option drm_options[] = {
2086 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2087 { WESTON_OPTION_STRING, "seat", 0, &seat },
2088 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002089 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002090 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002091
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002092 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002093
Scott Moreau8ab5d452012-07-30 19:51:08 -06002094 wl_list_init(&configured_output_list);
2095
2096 const struct config_key drm_config_keys[] = {
2097 { "name", CONFIG_KEY_STRING, &output_name },
2098 { "mode", CONFIG_KEY_STRING, &output_mode },
2099 };
2100
2101 const struct config_section config_section[] = {
2102 { "output", drm_config_keys,
2103 ARRAY_LENGTH(drm_config_keys), output_section_done },
2104 };
2105
2106 parse_config_file(config_file, config_section,
2107 ARRAY_LENGTH(config_section), NULL);
2108
Daniel Stonec1be8e52012-06-01 11:14:02 -04002109 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2110 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002111}