blob: 48202ba70a253705cedebdb362c4d1baceec46ac [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øgsberg8334bc12012-01-03 10:29:47 -05001758drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001759{
1760 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001761 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001762 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001763
Daniel Stone37816df2012-05-16 18:45:18 +01001764 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1765 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06001766 wl_list_for_each_safe(o, n, &configured_output_list, link)
1767 free(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001768
1769 wl_event_source_remove(d->udev_drm_source);
1770 wl_event_source_remove(d->drm_source);
1771
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001772 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001773
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001774 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001775 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001776 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001777 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001778 eglReleaseThread();
1779
Matt Roper361d2ad2011-08-29 13:52:23 -07001780 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001781 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001782 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001783 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001784 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001785
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001786 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001787}
1788
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001789static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001790drm_compositor_set_modes(struct drm_compositor *compositor)
1791{
1792 struct drm_output *output;
1793 struct drm_mode *drm_mode;
1794 int ret;
1795
1796 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1797 drm_mode = (struct drm_mode *) output->base.current;
1798 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001799 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001800 &output->connector_id, 1,
1801 &drm_mode->mode_info);
1802 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001803 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001804 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001805 drm_mode->base.width, drm_mode->base.height,
1806 output->base.x, output->base.y);
1807 }
1808 }
1809}
1810
1811static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001812vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001813{
1814 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001815 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001816 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001817 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001818
1819 switch (event) {
1820 case TTY_ENTER_VT:
1821 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001822 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001823 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001824 wl_display_terminate(compositor->wl_display);
1825 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001826 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001827 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001828 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01001829 wl_list_for_each(seat, &compositor->seat_list, link) {
1830 evdev_add_devices(ec->udev, seat);
1831 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02001832 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001833 break;
1834 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01001835 wl_list_for_each(seat, &compositor->seat_list, link) {
1836 evdev_disable_udev_monitor(seat);
1837 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04001838 }
1839
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001840 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001841 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001842 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04001843
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001844 /* If we have a repaint scheduled (either from a
1845 * pending pageflip or the idle handler), make sure we
1846 * cancel that so we don't try to pageflip when we're
1847 * vt switched away. The SLEEPING state will prevent
1848 * further attemps at repainting. When we switch
1849 * back, we schedule a repaint, which will process
1850 * pending frame callbacks. */
1851
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001852 wl_list_for_each(output, &ec->base.output_list, base.link) {
1853 output->base.repaint_needed = 0;
1854 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001855 }
1856
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001857 output = container_of(ec->base.output_list.next,
1858 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001859
1860 wl_list_for_each(sprite, &ec->sprite_list, link)
1861 drmModeSetPlane(ec->drm.fd,
1862 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001863 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001864 0, 0, 0, 0, 0, 0, 0, 0);
1865
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001866 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001867 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001868
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001869 break;
1870 };
1871}
1872
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001873static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01001874switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001875{
1876 struct drm_compositor *ec = data;
1877
Daniel Stone325fc2d2012-05-30 16:31:58 +01001878 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001879}
1880
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001881static const char default_seat[] = "seat0";
1882
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001883static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001884drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04001885 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04001886 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001887{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001888 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001889 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001890 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001891 struct udev_device *device, *drm_device;
1892 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001893 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001894 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001895 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001896
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001897 weston_log("initializing drm backend\n");
1898
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001899 ec = malloc(sizeof *ec);
1900 if (ec == NULL)
1901 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001902 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01001903
1904 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01001905 config_file) < 0) {
1906 weston_log("weston_compositor_init failed\n");
1907 goto err_base;
1908 }
Daniel Stone725c2c32012-06-22 14:04:36 +01001909
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001910 ec->udev = udev_new();
1911 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001912 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001913 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001914 }
1915
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001916 ec->base.wl_display = display;
1917 ec->tty = tty_create(&ec->base, vt_func, tty);
1918 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02001919 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001920 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001921 }
1922
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001923 e = udev_enumerate_new(ec->udev);
1924 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02001925 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001926
Benjamin Franzke117483d2011-08-30 11:38:26 +02001927 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001928 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001929 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001930 path = udev_list_entry_get_name(entry);
1931 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001932 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001933 udev_device_get_property_value(device, "ID_SEAT");
1934 if (!device_seat)
1935 device_seat = default_seat;
1936 if (strcmp(device_seat, seat) == 0) {
1937 drm_device = device;
1938 break;
1939 }
1940 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001941 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001942
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001943 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001944 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001945 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001946 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001947
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001948 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001949 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001950 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001951 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001952
1953 ec->base.destroy = drm_destroy;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02001954
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001955 ec->base.focus = 1;
1956
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001957 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001958
Daniel Stone725c2c32012-06-22 14:04:36 +01001959 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01001960 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02001961
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001962 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01001963 weston_compositor_add_key_binding(&ec->base, key,
1964 MODIFIER_CTRL | MODIFIER_ALT,
1965 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001966
Jesse Barnes58ef3792012-02-23 09:45:49 -05001967 wl_list_init(&ec->sprite_list);
1968 create_sprites(ec);
1969
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001970 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001971 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01001972 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001973 }
1974
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02001975 path = NULL;
1976
Tiago Vignattice03ec32011-12-19 01:14:03 +02001977 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001978
1979 loop = wl_display_get_event_loop(ec->base.wl_display);
1980 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001981 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001982 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001983
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001984 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
1985 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001986 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001987 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001988 }
1989 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
1990 "drm", NULL);
1991 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001992 wl_event_loop_add_fd(loop,
1993 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001994 WL_EVENT_READABLE, udev_drm_event, ec);
1995
1996 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001997 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001998 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001999 }
2000
Daniel Stonea96b93c2012-06-22 14:04:37 +01002001 udev_device_unref(drm_device);
2002 udev_enumerate_unref(e);
2003
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002004 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002005
2006err_udev_monitor:
2007 wl_event_source_remove(ec->udev_drm_source);
2008 udev_monitor_unref(ec->udev_monitor);
2009err_drm_source:
2010 wl_event_source_remove(ec->drm_source);
2011 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2012 evdev_input_destroy(weston_seat);
2013err_sprite:
2014 destroy_sprites(ec);
2015err_egl:
2016 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2017 EGL_NO_CONTEXT);
2018 eglTerminate(ec->base.egl_display);
2019 eglReleaseThread();
2020 gbm_device_destroy(ec->gbm);
2021err_udev_dev:
2022 udev_device_unref(drm_device);
2023err_udev_enum:
2024 udev_enumerate_unref(e);
2025 tty_destroy(ec->tty);
2026err_udev:
2027 udev_unref(ec->udev);
2028err_compositor:
2029 weston_compositor_shutdown(&ec->base);
2030err_base:
2031 free(ec);
2032 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002033}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002034
Scott Moreau8ab5d452012-07-30 19:51:08 -06002035static void
2036output_section_done(void *data)
2037{
2038 struct drm_configured_output *output;
2039
2040 output = malloc(sizeof *output);
2041
2042 if (!output)
2043 return;
2044
2045 output->config = OUTPUT_CONFIG_INVALID;
2046 output->name = output_name;
2047 output->mode = output_mode;
2048
2049 if (strcmp(output_mode, "off") == 0)
2050 output->config = OUTPUT_CONFIG_OFF;
2051 else if (strcmp(output_mode, "preferred") == 0)
2052 output->config = OUTPUT_CONFIG_PREFERRED;
2053 else if (strcmp(output_mode, "current") == 0)
2054 output->config = OUTPUT_CONFIG_CURRENT;
2055 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2056 output->config = OUTPUT_CONFIG_MODE;
2057
2058 if (output->config != OUTPUT_CONFIG_INVALID)
2059 wl_list_insert(&configured_output_list, &output->link);
2060 else {
2061 free(output);
2062 weston_log("Invalid mode \"%s\" for output %s\n",
2063 output_mode, output_name);
2064 }
2065}
2066
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002067WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002068backend_init(struct wl_display *display, int argc, char *argv[],
2069 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002070{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002071 int connector = 0, tty = 0;
2072 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002073
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002074 const struct weston_option drm_options[] = {
2075 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2076 { WESTON_OPTION_STRING, "seat", 0, &seat },
2077 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002078 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002079 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002080
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002081 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002082
Scott Moreau8ab5d452012-07-30 19:51:08 -06002083 wl_list_init(&configured_output_list);
2084
2085 const struct config_key drm_config_keys[] = {
2086 { "name", CONFIG_KEY_STRING, &output_name },
2087 { "mode", CONFIG_KEY_STRING, &output_mode },
2088 };
2089
2090 const struct config_section config_section[] = {
2091 { "output", drm_config_keys,
2092 ARRAY_LENGTH(drm_config_keys), output_section_done },
2093 };
2094
2095 parse_config_file(config_file, config_section,
2096 ARRAY_LENGTH(config_section), NULL);
2097
Daniel Stonec1be8e52012-06-01 11:14:02 -04002098 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2099 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002100}