blob: 7ed544b59e300a878ef836cdd58a9976d34d39b5 [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;
47
Kristian Høgsbergd553bfc2012-06-18 22:37:35 -040048enum {
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -040049 WESTON_PLANE_DRM_CURSOR = 0x100,
50 WESTON_PLANE_DRM_PLANE = 0x101,
51 WESTON_PLANE_DRM_FB = 0x102
Kristian Høgsbergd553bfc2012-06-18 22:37:35 -040052};
53
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040054struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050055 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040056
57 struct udev *udev;
58 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040059
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010060 struct udev_monitor *udev_monitor;
61 struct wl_event_source *udev_drm_source;
62
Benjamin Franzke2af7f102011-03-02 11:14:59 +010063 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010064 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010065 int fd;
66 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020067 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050068 uint32_t *crtcs;
69 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050070 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010071 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050072 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020073
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040074 struct gbm_surface *dummy_surface;
75 EGLSurface dummy_egl_surface;
76
Jesse Barnes58ef3792012-02-23 09:45:49 -050077 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050078 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -050079
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020080 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040081};
82
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040083struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050084 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040085 drmModeModeInfo mode_info;
86};
87
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +030088struct drm_output;
89
90struct drm_fb {
91 struct gbm_bo *bo;
92 struct drm_output *output;
93 uint32_t fb_id;
94 int is_client_buffer;
95 struct wl_buffer *buffer;
96 struct wl_listener buffer_destroy_listener;
97};
98
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040099struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500100 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400101
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400102 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400103 uint32_t crtc_id;
104 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700105 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200106
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300107 int vblank_pending;
108 int page_flip_pending;
109
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400110 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400111 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400112 int current_cursor, cursor_free, cursor_x, cursor_y;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400113 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200115 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400116};
117
Jesse Barnes58ef3792012-02-23 09:45:49 -0500118/*
119 * An output has a primary display plane plus zero or more sprites for
120 * blending display contents.
121 */
122struct drm_sprite {
123 struct wl_list link;
124
125 uint32_t fb_id;
126 uint32_t pending_fb_id;
127 struct weston_surface *surface;
128 struct weston_surface *pending_surface;
129
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300130 struct drm_output *output;
131
Jesse Barnes58ef3792012-02-23 09:45:49 -0500132 struct drm_compositor *compositor;
133
134 struct wl_listener destroy_listener;
135 struct wl_listener pending_destroy_listener;
136
137 uint32_t possible_crtcs;
138 uint32_t plane_id;
139 uint32_t count_formats;
140
141 int32_t src_x, src_y;
142 uint32_t src_w, src_h;
143 uint32_t dest_x, dest_y;
144 uint32_t dest_w, dest_h;
145
146 uint32_t formats[];
147};
148
149static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500150drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
151{
152 struct weston_compositor *ec = output_base->compositor;
153 struct drm_compositor *c =(struct drm_compositor *) ec;
154 struct drm_output *output = (struct drm_output *) output_base;
155 int crtc;
156
157 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
158 if (c->crtcs[crtc] != output->crtc_id)
159 continue;
160
161 if (supported & (1 << crtc))
162 return -1;
163 }
164
165 return 0;
166}
167
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300168static void
169drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
170{
171 struct drm_fb *fb = data;
172 struct gbm_device *gbm = gbm_bo_get_device(bo);
173
174 if (fb->fb_id)
175 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
176
177 if (fb->buffer) {
178 weston_buffer_post_release(fb->buffer);
179 wl_list_remove(&fb->buffer_destroy_listener.link);
180 }
181
182 free(data);
183}
184
185static struct drm_fb *
186drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
187{
188 struct drm_fb *fb = gbm_bo_get_user_data(bo);
189 struct drm_compositor *compositor =
190 (struct drm_compositor *) output->base.compositor;
191 uint32_t width, height, stride, handle;
192 int ret;
193
194 if (fb)
195 return fb;
196
197 fb = malloc(sizeof *fb);
198
199 fb->bo = bo;
200 fb->output = output;
201 fb->is_client_buffer = 0;
202 fb->buffer = NULL;
203
204 width = gbm_bo_get_width(bo);
205 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400206 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300207 handle = gbm_bo_get_handle(bo).u32;
208
209 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
210 stride, handle, &fb->fb_id);
211 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200212 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300213 free(fb);
214 return NULL;
215 }
216
217 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
218
219 return fb;
220}
221
222static void
223fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
224{
225 struct drm_fb *fb = container_of(listener, struct drm_fb,
226 buffer_destroy_listener);
227
228 fb->buffer = NULL;
229
230 if (fb == fb->output->next ||
231 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400232 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300233}
234
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500235static int
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400236drm_output_prepare_scanout_surface(struct weston_output *_output,
237 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500238{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400239 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500240 struct drm_compositor *c =
241 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300242 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500243
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500244 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200245 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200246 es->geometry.width != output->base.current->width ||
247 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200248 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400249 es->buffer == NULL)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500250 return -1;
251
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400252 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
253 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500254
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300255 /* Need to verify output->region contained in surface opaque
256 * region. Or maybe just that format doesn't have alpha.
257 * For now, scanout only if format is XRGB8888. */
258 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
259 gbm_bo_destroy(bo);
260 return -1;
261 }
262
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300263 output->next = drm_fb_get_from_bo(bo, output);
264 if (!output->next) {
265 gbm_bo_destroy(bo);
266 return -1;
267 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500268
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300269 output->next->is_client_buffer = 1;
270 output->next->buffer = es->buffer;
271 output->next->buffer->busy_count++;
272 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
273
274 wl_signal_add(&output->next->buffer->resource.destroy_signal,
275 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500276
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400277 es->plane = WESTON_PLANE_DRM_FB;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500278
279 return 0;
280}
281
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500282static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400283drm_output_render(struct drm_output *output, pixman_region32_t *damage)
284{
285 struct drm_compositor *compositor =
286 (struct drm_compositor *) output->base.compositor;
287 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300288 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400289
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400290 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
291 output->egl_surface,
292 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200293 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400294 return;
295 }
296
297 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400298 if (surface->plane == WESTON_PLANE_PRIMARY)
299 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400300
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400301 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600302
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400303 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300304 bo = gbm_surface_lock_front_buffer(output->surface);
305 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200306 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400307 return;
308 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300309
310 output->next = drm_fb_get_from_bo(bo, output);
311 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200312 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300313 gbm_surface_release_buffer(output->surface, bo);
314 return;
315 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400316}
317
318static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500319drm_output_repaint(struct weston_output *output_base,
320 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100321{
322 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500323 struct drm_compositor *compositor =
324 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500325 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400326 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500327 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100328
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400330 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400332 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100333
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400334 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300335 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400336 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300337 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400338 &output->connector_id, 1,
339 &mode->mode_info);
340 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200341 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400342 return;
343 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200344 }
345
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500346 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300347 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500348 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200349 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500350 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500351 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100352
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300353 output->page_flip_pending = 1;
354
Jesse Barnes58ef3792012-02-23 09:45:49 -0500355 /*
356 * Now, update all the sprite surfaces
357 */
358 wl_list_for_each(s, &compositor->sprite_list, link) {
359 uint32_t flags = 0;
360 drmVBlank vbl = {
361 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
362 .request.sequence = 1,
363 };
364
365 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
366 continue;
367
368 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
369 output->crtc_id, s->pending_fb_id, flags,
370 s->dest_x, s->dest_y,
371 s->dest_w, s->dest_h,
372 s->src_x, s->src_y,
373 s->src_w, s->src_h);
374 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200375 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500376 ret, strerror(errno));
377
378 /*
379 * Queue a vblank signal so we know when the surface
380 * becomes active on the display or has been replaced.
381 */
382 vbl.request.signal = (unsigned long)s;
383 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
384 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200385 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500386 ret, strerror(errno));
387 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300388
389 s->output = output;
390 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500391 }
392
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500393 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400394}
395
396static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500397vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
398 void *data)
399{
400 struct drm_sprite *s = (struct drm_sprite *)data;
401 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300402 struct drm_output *output = s->output;
403 uint32_t msecs;
404
405 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500406
407 if (s->surface) {
408 weston_buffer_post_release(s->surface->buffer);
409 wl_list_remove(&s->destroy_listener.link);
410 s->surface = NULL;
411 drmModeRmFB(c->drm.fd, s->fb_id);
412 s->fb_id = 0;
413 }
414
415 if (s->pending_surface) {
416 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400417 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
418 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500419 s->surface = s->pending_surface;
420 s->pending_surface = NULL;
421 s->fb_id = s->pending_fb_id;
422 s->pending_fb_id = 0;
423 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300424
425 if (!output->page_flip_pending) {
426 msecs = sec * 1000 + usec / 1000;
427 weston_output_finish_frame(&output->base, msecs);
428 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500429}
430
431static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400432page_flip_handler(int fd, unsigned int frame,
433 unsigned int sec, unsigned int usec, void *data)
434{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200435 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400436 uint32_t msecs;
437
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300438 output->page_flip_pending = 0;
439
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300440 if (output->current) {
441 if (output->current->is_client_buffer)
442 gbm_bo_destroy(output->current->bo);
443 else
444 gbm_surface_release_buffer(output->surface,
445 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200446 }
447
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300448 output->current = output->next;
449 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400450
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300451 if (!output->vblank_pending) {
452 msecs = sec * 1000 + usec / 1000;
453 weston_output_finish_frame(&output->base, msecs);
454 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200455}
456
457static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500458drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
459{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400460 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500461
462 for (i = 0; i < s->count_formats; i++)
463 if (s->formats[i] == format)
464 return 1;
465
466 return 0;
467}
468
469static int
470drm_surface_transform_supported(struct weston_surface *es)
471{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400472 struct weston_matrix *matrix = &es->transform.matrix;
473 int i;
474
475 if (!es->transform.enabled)
476 return 1;
477
478 for (i = 0; i < 16; i++) {
479 switch (i) {
480 case 10:
481 case 15:
482 if (matrix->d[i] != 1.0)
483 return 0;
484 break;
485 case 0:
486 case 5:
487 case 12:
488 case 13:
489 break;
490 default:
491 if (matrix->d[i] != 0.0)
492 return 0;
493 break;
494 }
495 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500496
497 return 1;
498}
499
Jesse Barnes58ef3792012-02-23 09:45:49 -0500500static void
501drm_disable_unused_sprites(struct weston_output *output_base)
502{
503 struct weston_compositor *ec = output_base->compositor;
504 struct drm_compositor *c =(struct drm_compositor *) ec;
505 struct drm_output *output = (struct drm_output *) output_base;
506 struct drm_sprite *s;
507 int ret;
508
509 wl_list_for_each(s, &c->sprite_list, link) {
510 if (s->pending_fb_id)
511 continue;
512
513 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
514 output->crtc_id, 0, 0,
515 0, 0, 0, 0, 0, 0, 0, 0);
516 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200517 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500518 ret, strerror(errno));
519 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300520
521 if (s->surface) {
522 s->surface = NULL;
523 wl_list_remove(&s->destroy_listener.link);
524 }
525
526 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500527 s->fb_id = 0;
528 s->pending_fb_id = 0;
529 }
530}
531
532/*
533 * This function must take care to damage any previously assigned surface
534 * if the sprite ends up binding to a different surface than in the
535 * previous frame.
536 */
537static int
538drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400539 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500540{
541 struct weston_compositor *ec = output_base->compositor;
542 struct drm_compositor *c =(struct drm_compositor *) ec;
543 struct drm_sprite *s;
544 int found = 0;
545 EGLint handle, stride;
546 struct gbm_bo *bo;
547 uint32_t fb_id = 0;
548 uint32_t handles[4], pitches[4], offsets[4];
549 int ret = 0;
550 pixman_region32_t dest_rect, src_rect;
551 pixman_box32_t *box;
552 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400553 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500554
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500555 if (c->sprites_are_broken)
556 return -1;
557
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300558 if (es->output_mask != (1u << output_base->id))
559 return -1;
560
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400561 if (es->buffer == NULL)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500562 return -1;
563
564 if (!drm_surface_transform_supported(es))
565 return -1;
566
Jesse Barnes58ef3792012-02-23 09:45:49 -0500567 wl_list_for_each(s, &c->sprite_list, link) {
568 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
569 continue;
570
571 if (!s->pending_fb_id) {
572 found = 1;
573 break;
574 }
575 }
576
577 /* No sprites available */
578 if (!found)
579 return -1;
580
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400581 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
582 es->buffer, GBM_BO_USE_SCANOUT);
583 if (!bo)
584 return -1;
585
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 format = gbm_bo_get_format(bo);
587 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400588 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589
590 gbm_bo_destroy(bo);
591
592 if (!drm_surface_format_supported(s, format))
593 return -1;
594
595 if (!handle)
596 return -1;
597
598 handles[0] = handle;
599 pitches[0] = stride;
600 offsets[0] = 0;
601
602 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
603 format, handles, pitches, offsets,
604 &fb_id, 0);
605 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200606 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500607 c->sprites_are_broken = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 return -1;
609 }
610
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611 s->pending_fb_id = fb_id;
612 s->pending_surface = es;
613 es->buffer->busy_count++;
614
615 /*
616 * Calculate the source & dest rects properly based on actual
617 * postion (note the caller has called weston_surface_update_transform()
618 * for us already).
619 */
620 pixman_region32_init(&dest_rect);
621 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
622 &output_base->region);
623 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
624 box = pixman_region32_extents(&dest_rect);
625 s->dest_x = box->x1;
626 s->dest_y = box->y1;
627 s->dest_w = box->x2 - box->x1;
628 s->dest_h = box->y2 - box->y1;
629 pixman_region32_fini(&dest_rect);
630
631 pixman_region32_init(&src_rect);
632 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
633 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400635
636 weston_surface_from_global_fixed(es,
637 wl_fixed_from_int(box->x1),
638 wl_fixed_from_int(box->y1),
639 &sx1, &sy1);
640 weston_surface_from_global_fixed(es,
641 wl_fixed_from_int(box->x2),
642 wl_fixed_from_int(box->y2),
643 &sx2, &sy2);
644
645 if (sx1 < 0)
646 sx1 = 0;
647 if (sy1 < 0)
648 sy1 = 0;
649 if (sx2 > wl_fixed_from_int(es->geometry.width))
650 sx2 = wl_fixed_from_int(es->geometry.width);
651 if (sy2 > wl_fixed_from_int(es->geometry.height))
652 sy2 = wl_fixed_from_int(es->geometry.height);
653
654 s->src_x = sx1 << 8;
655 s->src_y = sy1 << 8;
656 s->src_w = (sx2 - sx1) << 8;
657 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 pixman_region32_fini(&src_rect);
659
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400660 es->plane = WESTON_PLANE_DRM_PLANE;
661
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400662 wl_signal_add(&es->buffer->resource.destroy_signal,
663 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400664
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665 return 0;
666}
667
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500668static void
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400669drm_output_set_cursor(struct weston_output *output_base,
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400670 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500671{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400672 struct drm_output *output = (struct drm_output *) output_base;
673 struct drm_compositor *c =
674 (struct drm_compositor *) output->base.compositor;
675 EGLint handle, stride;
676 struct gbm_bo *bo;
677 uint32_t buf[64 * 64];
678 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400679 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500680
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400681 if (!output->cursor_free)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500682 return;
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400683 if (es->output_mask != (1u << output_base->id))
684 return;
685 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
686 es->geometry.width > 64 || es->geometry.height > 64)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400687 return;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500688
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400689 if (es->buffer && pixman_region32_not_empty(&es->damage)) {
690 output->current_cursor ^= 1;
691 bo = output->cursor_bo[output->current_cursor];
692 memset(buf, 0, sizeof buf);
693 stride = wl_shm_buffer_get_stride(es->buffer);
694 s = wl_shm_buffer_get_data(es->buffer);
695 for (i = 0; i < es->geometry.height; i++)
696 memcpy(buf + i * 64, s + i * stride,
697 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500698
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400699 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
700 return;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400701
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400702 handle = gbm_bo_get_handle(bo).s32;
703 if (drmModeSetCursor(c->drm.fd,
704 output->crtc_id, handle, 64, 64)) {
705 weston_log("failed to set cursor: %n\n");
706 return;
707 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400708 }
709
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400710 x = es->geometry.x - output->base.x;
711 y = es->geometry.y - output->base.y;
712 if (output->cursor_x != x || output->cursor_y != y) {
713 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
714 weston_log("failed to move cursor: %m\n");
715 return;
716 }
717 output->cursor_x = x;
718 output->cursor_y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400719 }
720
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400721 es->plane = WESTON_PLANE_DRM_CURSOR;
722 output->cursor_free = 0;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500723}
724
Jesse Barnes58ef3792012-02-23 09:45:49 -0500725static void
726drm_assign_planes(struct weston_output *output)
727{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400728 struct drm_compositor *c =
729 (struct drm_compositor *) output->compositor;
730 struct drm_output *drm_output = (struct drm_output *) output;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400731 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500732 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400733 int prev_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500734
735 /*
736 * Find a surface for each sprite in the output using some heuristics:
737 * 1) size
738 * 2) frequency of update
739 * 3) opacity (though some hw might support alpha blending)
740 * 4) clipping (this can be fixed with color keys)
741 *
742 * The idea is to save on blitting since this should save power.
743 * If we can get a large video surface on the sprite for example,
744 * the main display surface may not need to update at all, and
745 * the client buffer can be used directly for the sprite surface
746 * as we do for flipping full screen surfaces.
747 */
748 pixman_region32_init(&overlap);
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400749 drm_output->cursor_free = 1;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400750 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500751 pixman_region32_init(&surface_overlap);
752 pixman_region32_intersect(&surface_overlap, &overlap,
753 &es->transform.boundingbox);
754
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400755 prev_plane = es->plane;
756 es->plane = WESTON_PLANE_PRIMARY;
757 if (pixman_region32_not_empty(&surface_overlap))
758 goto bail;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500759
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400760 if (es->plane == WESTON_PLANE_PRIMARY)
761 drm_output_set_cursor(output, es);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400762 if (es->plane == WESTON_PLANE_PRIMARY)
763 drm_output_prepare_scanout_surface(output, es);
764 if (es->plane == WESTON_PLANE_PRIMARY)
765 drm_output_prepare_overlay_surface(output, es);
766
767 bail:
768 if (es->plane == WESTON_PLANE_PRIMARY)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 pixman_region32_union(&overlap, &overlap,
770 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400771
772 if (prev_plane != WESTON_PLANE_PRIMARY &&
773 es->plane == WESTON_PLANE_PRIMARY)
774 weston_surface_damage(es);
775 else if (prev_plane == WESTON_PLANE_PRIMARY &&
776 es->plane != WESTON_PLANE_PRIMARY)
777 weston_surface_damage_below(es);
778
Jesse Barnes58ef3792012-02-23 09:45:49 -0500779 pixman_region32_fini(&surface_overlap);
780 }
781 pixman_region32_fini(&overlap);
782
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400783 if (drm_output->cursor_free)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400784 drmModeSetCursor(c->drm.fd, drm_output->crtc_id, 0, 0, 0);
Kristian Høgsbergf2735ea2012-06-20 23:03:53 -0400785
Jesse Barnes58ef3792012-02-23 09:45:49 -0500786 drm_disable_unused_sprites(output);
787}
788
Matt Roper361d2ad2011-08-29 13:52:23 -0700789static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500790drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700791{
792 struct drm_output *output = (struct drm_output *) output_base;
793 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200794 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700795 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700796
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200797 if (output->backlight)
798 backlight_destroy(output->backlight);
799
Matt Roper361d2ad2011-08-29 13:52:23 -0700800 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400801 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700802
803 /* Restore original CRTC state */
804 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200805 origcrtc->x, origcrtc->y,
806 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700807 drmModeFreeCrtc(origcrtc);
808
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200809 c->crtc_allocator &= ~(1 << output->crtc_id);
810 c->connector_allocator &= ~(1 << output->connector_id);
811
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400812 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400813 gbm_surface_destroy(output->surface);
814
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500815 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200816 wl_list_remove(&output->base.link);
817
Matt Roper361d2ad2011-08-29 13:52:23 -0700818 free(output);
819}
820
Alex Wub7b8bda2012-04-17 17:20:48 +0800821static struct drm_mode *
822choose_mode (struct drm_output *output, struct weston_mode *target_mode)
823{
824 struct drm_mode *tmp_mode = NULL, *mode;
825
826 if (output->base.current->width == target_mode->width &&
827 output->base.current->height == target_mode->height &&
828 (output->base.current->refresh == target_mode->refresh ||
829 target_mode->refresh == 0))
830 return (struct drm_mode *)output->base.current;
831
832 wl_list_for_each(mode, &output->base.mode_list, base.link) {
833 if (mode->mode_info.hdisplay == target_mode->width &&
834 mode->mode_info.vdisplay == target_mode->height) {
835 if (mode->mode_info.vrefresh == target_mode->refresh ||
836 target_mode->refresh == 0) {
837 return mode;
838 } else if (!tmp_mode)
839 tmp_mode = mode;
840 }
841 }
842
843 return tmp_mode;
844}
845
846static int
847drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
848{
849 struct drm_output *output;
850 struct drm_mode *drm_mode;
851 int ret;
852 struct drm_compositor *ec;
853 struct gbm_surface *surface;
854 EGLSurface egl_surface;
855
856 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200857 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800858 return -1;
859 }
860
861 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200862 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800863 return -1;
864 }
865
866 ec = (struct drm_compositor *)output_base->compositor;
867 output = (struct drm_output *)output_base;
868 drm_mode = choose_mode (output, mode);
869
870 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200871 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800872 return -1;
873 } else if (&drm_mode->base == output->base.current) {
874 return 0;
875 } else if (drm_mode->base.width == output->base.current->width &&
876 drm_mode->base.height == output->base.current->height) {
877 /* only change refresh value */
878 ret = drmModeSetCrtc(ec->drm.fd,
879 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300880 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800881 &output->connector_id, 1, &drm_mode->mode_info);
882
883 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200884 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800885 drm_mode->base.width,
886 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400887 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800888 ret = -1;
889 } else {
890 output->base.current->flags = 0;
891 output->base.current = &drm_mode->base;
892 drm_mode->base.flags =
893 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
894 ret = 0;
895 }
896
897 return ret;
898 }
899
900 drm_mode->base.flags =
901 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
902
903 surface = gbm_surface_create(ec->gbm,
904 drm_mode->base.width,
905 drm_mode->base.height,
906 GBM_FORMAT_XRGB8888,
907 GBM_BO_USE_SCANOUT |
908 GBM_BO_USE_RENDERING);
909 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200910 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800911 return -1;
912 }
913
914 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400915 eglCreateWindowSurface(ec->base.egl_display,
916 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800917 surface, NULL);
918
919 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200920 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800921 goto err;
922 }
923
924 ret = drmModeSetCrtc(ec->drm.fd,
925 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300926 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800927 &output->connector_id, 1, &drm_mode->mode_info);
928 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200929 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800930 goto err;
931 }
932
933 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300934 if (output->current) {
935 if (output->current->is_client_buffer)
936 gbm_bo_destroy(output->current->bo);
937 else
938 gbm_surface_release_buffer(output->surface,
939 output->current->bo);
940 }
941 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800942
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300943 if (output->next) {
944 if (output->next->is_client_buffer)
945 gbm_bo_destroy(output->next->bo);
946 else
947 gbm_surface_release_buffer(output->surface,
948 output->next->bo);
949 }
950 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800951
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400952 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800953 gbm_surface_destroy(output->surface);
954 output->egl_surface = egl_surface;
955 output->surface = surface;
956
957 /*update output*/
958 output->base.current = &drm_mode->base;
959 output->base.dirty = 1;
960 weston_output_move(&output->base, output->base.x, output->base.y);
961 return 0;
962
963err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400964 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800965 gbm_surface_destroy(surface);
966 return -1;
967}
968
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400969static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400970on_drm_input(int fd, uint32_t mask, void *data)
971{
972 drmEventContext evctx;
973
974 memset(&evctx, 0, sizeof evctx);
975 evctx.version = DRM_EVENT_CONTEXT_VERSION;
976 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500977 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400978 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400979
980 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400981}
982
983static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400984init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400985{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400986 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -0400987 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400988 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400989 static const EGLint context_attribs[] = {
990 EGL_CONTEXT_CLIENT_VERSION, 2,
991 EGL_NONE
992 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400993
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400994 static const EGLint config_attribs[] = {
995 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
996 EGL_RED_SIZE, 1,
997 EGL_GREEN_SIZE, 1,
998 EGL_BLUE_SIZE, 1,
999 EGL_ALPHA_SIZE, 0,
1000 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1001 EGL_NONE
1002 };
1003
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001004 sysnum = udev_device_get_sysnum(device);
1005 if (sysnum)
1006 ec->drm.id = atoi(sysnum);
1007 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001008 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001009 return -1;
1010 }
1011
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001012 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001013 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001014 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001015 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001016 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001017 udev_device_get_devnode(device));
1018 return -1;
1019 }
1020
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001021 weston_log("using %s\n", filename);
1022
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001023 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001024 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001025 ec->base.egl_display = eglGetDisplay(ec->gbm);
1026 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001027 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001028 return -1;
1029 }
1030
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001031 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001032 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001033 return -1;
1034 }
1035
Darxus55973f22010-11-22 21:24:39 -05001036 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001037 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001038 return -1;
1039 }
1040
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001041 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1042 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001043 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001044 return -1;
1045 }
1046
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001047 ec->base.egl_context =
1048 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1049 EGL_NO_CONTEXT, context_attribs);
1050 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001051 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001052 return -1;
1053 }
1054
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001055 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1056 GBM_FORMAT_XRGB8888,
1057 GBM_BO_USE_RENDERING);
1058 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001059 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001060 return -1;
1061 }
1062
1063 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001064 eglCreateWindowSurface(ec->base.egl_display,
1065 ec->base.egl_config,
1066 ec->dummy_surface,
1067 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001068 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001069 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001070 return -1;
1071 }
1072
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001073 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1074 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001075 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001076 return -1;
1077 }
1078
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001079 return 0;
1080}
1081
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001082static int
1083drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1084{
1085 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001086 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001087
1088 mode = malloc(sizeof *mode);
1089 if (mode == NULL)
1090 return -1;
1091
1092 mode->base.flags = 0;
1093 mode->base.width = info->hdisplay;
1094 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001095
1096 /* Calculate higher precision (mHz) refresh rate */
1097 refresh = (info->clock * 1000000LL / info->htotal +
1098 info->vtotal / 2) / info->vtotal;
1099
1100 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1101 refresh *= 2;
1102 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1103 refresh /= 2;
1104 if (info->vscan > 1)
1105 refresh /= info->vscan;
1106
1107 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001108 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001109
1110 if (info->type & DRM_MODE_TYPE_PREFERRED)
1111 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001113 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1114
1115 return 0;
1116}
1117
1118static int
1119drm_subpixel_to_wayland(int drm_value)
1120{
1121 switch (drm_value) {
1122 default:
1123 case DRM_MODE_SUBPIXEL_UNKNOWN:
1124 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1125 case DRM_MODE_SUBPIXEL_NONE:
1126 return WL_OUTPUT_SUBPIXEL_NONE;
1127 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1128 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1129 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1130 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1131 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1132 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1133 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1134 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1135 }
1136}
1137
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001138static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001139sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001140{
1141 struct drm_sprite *sprite =
1142 container_of(listener, struct drm_sprite,
1143 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001144 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001145
1146 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001147 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1148 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001149}
1150
1151static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001152sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001153{
1154 struct drm_sprite *sprite =
1155 container_of(listener, struct drm_sprite,
1156 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001157 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001158
1159 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001160 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1161 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001162}
1163
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001164/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001165static uint32_t
1166drm_get_backlight(struct drm_output *output)
1167{
1168 long brightness, max_brightness, norm;
1169
1170 brightness = backlight_get_brightness(output->backlight);
1171 max_brightness = backlight_get_max_brightness(output->backlight);
1172
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001173 /* convert it on a scale of 0 to 255 */
1174 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001175
1176 return (uint32_t) norm;
1177}
1178
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001179/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001180static void
1181drm_set_backlight(struct weston_output *output_base, uint32_t value)
1182{
1183 struct drm_output *output = (struct drm_output *) output_base;
1184 long max_brightness, new_brightness;
1185
1186 if (!output->backlight)
1187 return;
1188
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001189 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001190 return;
1191
1192 max_brightness = backlight_get_max_brightness(output->backlight);
1193
1194 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001195 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001196
1197 backlight_set_brightness(output->backlight, new_brightness);
1198}
1199
1200static drmModePropertyPtr
1201drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1202{
1203 drmModePropertyPtr props;
1204 int i;
1205
1206 for (i = 0; i < connector->count_props; i++) {
1207 props = drmModeGetProperty(fd, connector->props[i]);
1208 if (!props)
1209 continue;
1210
1211 if (!strcmp(props->name, name))
1212 return props;
1213
1214 drmModeFreeProperty(props);
1215 }
1216
1217 return NULL;
1218}
1219
1220static void
1221drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1222{
1223 struct drm_output *output = (struct drm_output *) output_base;
1224 struct weston_compositor *ec = output_base->compositor;
1225 struct drm_compositor *c = (struct drm_compositor *) ec;
1226 drmModeConnectorPtr connector;
1227 drmModePropertyPtr prop;
1228
1229 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1230 if (!connector)
1231 return;
1232
1233 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1234 if (!prop) {
1235 drmModeFreeConnector(connector);
1236 return;
1237 }
1238
1239 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1240 prop->prop_id, level);
1241 drmModeFreeProperty(prop);
1242 drmModeFreeConnector(connector);
1243}
1244
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001245static const char *connector_type_names[] = {
1246 "None",
1247 "VGA",
1248 "DVI",
1249 "DVI",
1250 "DVI",
1251 "Composite",
1252 "TV",
1253 "LVDS",
1254 "CTV",
1255 "DIN",
1256 "DP",
1257 "HDMI",
1258 "HDMI",
1259 "TV",
1260 "eDP",
1261};
1262
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001263static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001264find_crtc_for_connector(struct drm_compositor *ec,
1265 drmModeRes *resources, drmModeConnector *connector)
1266{
1267 drmModeEncoder *encoder;
1268 uint32_t possible_crtcs;
1269 int i, j;
1270
1271 for (j = 0; j < connector->count_encoders; j++) {
1272 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1273 if (encoder == NULL) {
1274 weston_log("Failed to get encoder.\n");
1275 return -1;
1276 }
1277 possible_crtcs = encoder->possible_crtcs;
1278 drmModeFreeEncoder(encoder);
1279
1280 for (i = 0; i < resources->count_crtcs; i++) {
1281 if (possible_crtcs & (1 << i) &&
1282 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1283 return i;
1284 }
1285 }
1286
1287 return -1;
1288}
1289
1290static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001291create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001292 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001293 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001294 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001295{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001296 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001297 struct drm_mode *drm_mode, *next;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001298 struct weston_mode *m, *preferred, *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001299 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001300 drmModeModeInfo crtc_mode;
1301 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001302 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001303 char name[32];
1304 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001305
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001306 i = find_crtc_for_connector(ec, resources, connector);
1307 if (i < 0) {
1308 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001309 return -1;
1310 }
1311
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001313 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001314 return -1;
1315
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001316 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001317 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1318 output->base.make = "unknown";
1319 output->base.model = "unknown";
1320 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001321
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001322 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1323 type_name = connector_type_names[connector->connector_type];
1324 else
1325 type_name = "UNKNOWN";
1326 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1327 output->name = strdup(name);
1328
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001329 output->crtc_id = resources->crtcs[i];
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001330 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001331 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001332 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001333
Matt Roper361d2ad2011-08-29 13:52:23 -07001334 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1335
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001336 /* Get the current mode on the crtc that's currently driving
1337 * this connector. */
1338 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
1339 if (encoder == NULL)
1340 goto err_free;
1341 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1342 drmModeFreeEncoder(encoder);
1343 if (crtc == NULL)
1344 goto err_free;
1345 crtc_mode = crtc->mode;
1346 drmModeFreeCrtc(crtc);
1347
David Herrmann0f0d54e2011-12-08 17:05:45 +01001348 for (i = 0; i < connector->count_modes; i++) {
1349 ret = drm_output_add_mode(output, &connector->modes[i]);
1350 if (ret)
1351 goto err_free;
1352 }
1353
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001354 preferred = NULL;
1355 current = NULL;
1356 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
1357 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode)) {
1358 drm_mode->base.flags |= WL_OUTPUT_MODE_CURRENT;
1359 current = &drm_mode->base;
1360 }
1361 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1362 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001363 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001364
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001365 if (current == NULL) {
1366 ret = drm_output_add_mode(output, &crtc_mode);
1367 if (ret)
1368 goto err_free;
1369 current = container_of(output->base.mode_list.prev,
1370 struct weston_mode, link);
1371 current->flags |= WL_OUTPUT_MODE_CURRENT;
1372 }
1373
1374 if (preferred == NULL)
1375 preferred = current;
1376
1377 if (option_current_mode) {
1378 output->base.current = current;
1379 } else {
1380 output->base.current = preferred;
1381 current->flags &= ~WL_OUTPUT_MODE_CURRENT;
1382 preferred->flags |= WL_OUTPUT_MODE_CURRENT;
1383 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001384
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001385 output->surface = gbm_surface_create(ec->gbm,
1386 output->base.current->width,
1387 output->base.current->height,
1388 GBM_FORMAT_XRGB8888,
1389 GBM_BO_USE_SCANOUT |
1390 GBM_BO_USE_RENDERING);
1391 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001392 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001393 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001394 }
1395
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001396 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001397 eglCreateWindowSurface(ec->base.egl_display,
1398 ec->base.egl_config,
1399 output->surface,
1400 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001401 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001402 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001403 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001404 }
1405
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001406 output->cursor_bo[0] =
1407 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1408 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1409 output->cursor_bo[1] =
1410 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1411 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1412
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001413 output->backlight = backlight_init(drm_device,
1414 connector->connector_type);
1415 if (output->backlight) {
1416 output->base.set_backlight = drm_set_backlight;
1417 output->base.backlight_current = drm_get_backlight(output);
1418 }
1419
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001420 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001421 connector->mmWidth, connector->mmHeight,
1422 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001423
1424 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1425
Alex Wubd3354b2012-04-17 17:20:49 +08001426 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001427 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001428 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001429 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001430 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001431 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001432
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001433 weston_log("Output %s, (connector %d, crtc %d)\n",
1434 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001435 wl_list_for_each(m, &output->base.mode_list, link)
1436 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1437 m->width, m->height, m->refresh / 1000.0,
1438 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1439 ", preferred" : "",
1440 m->flags & WL_OUTPUT_MODE_CURRENT ?
1441 ", current" : "",
1442 connector->count_modes == 0 ?
1443 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001444
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001445 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001446
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001447err_surface:
1448 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001449err_free:
1450 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1451 base.link) {
1452 wl_list_remove(&drm_mode->base.link);
1453 free(drm_mode);
1454 }
1455
1456 drmModeFreeCrtc(output->original_crtc);
1457 ec->crtc_allocator &= ~(1 << output->crtc_id);
1458 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001459 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001460
David Herrmann0f0d54e2011-12-08 17:05:45 +01001461 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001462}
1463
Jesse Barnes58ef3792012-02-23 09:45:49 -05001464static void
1465create_sprites(struct drm_compositor *ec)
1466{
1467 struct drm_sprite *sprite;
1468 drmModePlaneRes *plane_res;
1469 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001470 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001471
1472 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1473 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001474 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001475 strerror(errno));
1476 return;
1477 }
1478
1479 for (i = 0; i < plane_res->count_planes; i++) {
1480 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1481 if (!plane)
1482 continue;
1483
1484 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1485 plane->count_formats));
1486 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001487 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001488 __func__);
1489 free(plane);
1490 continue;
1491 }
1492
1493 memset(sprite, 0, sizeof *sprite);
1494
1495 sprite->possible_crtcs = plane->possible_crtcs;
1496 sprite->plane_id = plane->plane_id;
1497 sprite->surface = NULL;
1498 sprite->pending_surface = NULL;
1499 sprite->fb_id = 0;
1500 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001501 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1502 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001503 sprite_handle_pending_buffer_destroy;
1504 sprite->compositor = ec;
1505 sprite->count_formats = plane->count_formats;
1506 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001507 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001508 drmModeFreePlane(plane);
1509
1510 wl_list_insert(&ec->sprite_list, &sprite->link);
1511 }
1512
1513 free(plane_res->planes);
1514 free(plane_res);
1515}
1516
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001517static void
1518destroy_sprites(struct drm_compositor *compositor)
1519{
1520 struct drm_sprite *sprite, *next;
1521 struct drm_output *output;
1522
1523 output = container_of(compositor->base.output_list.next,
1524 struct drm_output, base.link);
1525
1526 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1527 drmModeSetPlane(compositor->drm.fd,
1528 sprite->plane_id,
1529 output->crtc_id, 0, 0,
1530 0, 0, 0, 0, 0, 0, 0, 0);
1531 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1532 free(sprite);
1533 }
1534}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001535
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001536static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001537create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001538 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001539{
1540 drmModeConnector *connector;
1541 drmModeRes *resources;
1542 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001543 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001544
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001545 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001546 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001547 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001548 return -1;
1549 }
1550
Jesse Barnes58ef3792012-02-23 09:45:49 -05001551 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001552 if (!ec->crtcs) {
1553 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001554 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001555 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001556
1557 ec->num_crtcs = resources->count_crtcs;
1558 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1559
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001560 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001561 connector = drmModeGetConnector(ec->drm.fd,
1562 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001563 if (connector == NULL)
1564 continue;
1565
1566 if (connector->connection == DRM_MODE_CONNECTED &&
1567 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001568 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001569 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001570 connector, x, y,
1571 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001572 drmModeFreeConnector(connector);
1573 continue;
1574 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001575
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001576 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001577 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001578 link)->current->width;
1579 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001580
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001581 drmModeFreeConnector(connector);
1582 }
1583
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001584 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001585 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001586 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001587 return -1;
1588 }
1589
1590 drmModeFreeResources(resources);
1591
1592 return 0;
1593}
1594
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001595static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001596update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001597{
1598 drmModeConnector *connector;
1599 drmModeRes *resources;
1600 struct drm_output *output, *next;
1601 int x = 0, y = 0;
1602 int x_offset = 0, y_offset = 0;
1603 uint32_t connected = 0, disconnects = 0;
1604 int i;
1605
1606 resources = drmModeGetResources(ec->drm.fd);
1607 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001608 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001609 return;
1610 }
1611
1612 /* collect new connects */
1613 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001614 int connector_id = resources->connectors[i];
1615
1616 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001617 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001618 continue;
1619
David Herrmann7551cff2011-12-08 17:05:43 +01001620 if (connector->connection != DRM_MODE_CONNECTED) {
1621 drmModeFreeConnector(connector);
1622 continue;
1623 }
1624
Benjamin Franzke117483d2011-08-30 11:38:26 +02001625 connected |= (1 << connector_id);
1626
1627 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001628 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001629 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001630 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001631
1632 /* XXX: not yet needed, we die with 0 outputs */
1633 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001634 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001635 else
1636 x = 0;
1637 y = 0;
1638 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001639 connector, x, y,
1640 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001641 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001642
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001643 }
1644 drmModeFreeConnector(connector);
1645 }
1646 drmModeFreeResources(resources);
1647
1648 disconnects = ec->connector_allocator & ~connected;
1649 if (disconnects) {
1650 wl_list_for_each_safe(output, next, &ec->base.output_list,
1651 base.link) {
1652 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001653 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001654 output->base.x - x_offset,
1655 output->base.y - y_offset);
1656 }
1657
1658 if (disconnects & (1 << output->connector_id)) {
1659 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001660 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001661 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001662 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001663 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001664 }
1665 }
1666 }
1667
1668 /* FIXME: handle zero outputs, without terminating */
1669 if (ec->connector_allocator == 0)
1670 wl_display_terminate(ec->base.wl_display);
1671}
1672
1673static int
David Herrmannd7488c22012-03-11 20:05:21 +01001674udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001675{
David Herrmannd7488c22012-03-11 20:05:21 +01001676 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001677 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001678
1679 sysnum = udev_device_get_sysnum(device);
1680 if (!sysnum || atoi(sysnum) != ec->drm.id)
1681 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001682
David Herrmann6ac52db2012-03-11 20:05:22 +01001683 val = udev_device_get_property_value(device, "HOTPLUG");
1684 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001685 return 0;
1686
David Herrmann6ac52db2012-03-11 20:05:22 +01001687 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001688}
1689
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001690static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001691udev_drm_event(int fd, uint32_t mask, void *data)
1692{
1693 struct drm_compositor *ec = data;
1694 struct udev_device *event;
1695
1696 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001697
David Herrmannd7488c22012-03-11 20:05:21 +01001698 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001699 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001700
1701 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001702
1703 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001704}
1705
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001706static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001707drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001708{
1709 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001710 struct weston_seat *seat, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001711
Daniel Stone37816df2012-05-16 18:45:18 +01001712 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1713 evdev_input_destroy(seat);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001714
1715 wl_event_source_remove(d->udev_drm_source);
1716 wl_event_source_remove(d->drm_source);
1717
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001718 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001719
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001720 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001721 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001722 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001723 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001724 eglReleaseThread();
1725
Matt Roper361d2ad2011-08-29 13:52:23 -07001726 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001727 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001728 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001729 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001730 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001731
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001732 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001733}
1734
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001735static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001736drm_compositor_set_modes(struct drm_compositor *compositor)
1737{
1738 struct drm_output *output;
1739 struct drm_mode *drm_mode;
1740 int ret;
1741
1742 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1743 drm_mode = (struct drm_mode *) output->base.current;
1744 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001745 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001746 &output->connector_id, 1,
1747 &drm_mode->mode_info);
1748 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001749 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001750 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001751 drm_mode->base.width, drm_mode->base.height,
1752 output->base.x, output->base.y);
1753 }
1754 }
1755}
1756
1757static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001758vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001759{
1760 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001761 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001762 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001763 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001764
1765 switch (event) {
1766 case TTY_ENTER_VT:
1767 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001768 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001769 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001770 wl_display_terminate(compositor->wl_display);
1771 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001772 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001773 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001774 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01001775 wl_list_for_each(seat, &compositor->seat_list, link) {
1776 evdev_add_devices(ec->udev, seat);
1777 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02001778 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001779 break;
1780 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01001781 wl_list_for_each(seat, &compositor->seat_list, link) {
1782 evdev_disable_udev_monitor(seat);
1783 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04001784 }
1785
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001786 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001787 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001788 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04001789
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001790 /* If we have a repaint scheduled (either from a
1791 * pending pageflip or the idle handler), make sure we
1792 * cancel that so we don't try to pageflip when we're
1793 * vt switched away. The SLEEPING state will prevent
1794 * further attemps at repainting. When we switch
1795 * back, we schedule a repaint, which will process
1796 * pending frame callbacks. */
1797
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001798 wl_list_for_each(output, &ec->base.output_list, base.link) {
1799 output->base.repaint_needed = 0;
1800 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001801 }
1802
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001803 output = container_of(ec->base.output_list.next,
1804 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001805
1806 wl_list_for_each(sprite, &ec->sprite_list, link)
1807 drmModeSetPlane(ec->drm.fd,
1808 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001809 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001810 0, 0, 0, 0, 0, 0, 0, 0);
1811
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001812 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001813 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001814
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001815 break;
1816 };
1817}
1818
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001819static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01001820switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001821{
1822 struct drm_compositor *ec = data;
1823
Daniel Stone325fc2d2012-05-30 16:31:58 +01001824 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001825}
1826
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001827static const char default_seat[] = "seat0";
1828
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001829static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001830drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04001831 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04001832 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001833{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001834 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001835 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001836 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001837 struct udev_device *device, *drm_device;
1838 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001839 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001840 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001841 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001842
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001843 weston_log("initializing drm backend\n");
1844
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001845 ec = malloc(sizeof *ec);
1846 if (ec == NULL)
1847 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001848 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01001849
1850 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01001851 config_file) < 0) {
1852 weston_log("weston_compositor_init failed\n");
1853 goto err_base;
1854 }
Daniel Stone725c2c32012-06-22 14:04:36 +01001855
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001856 ec->udev = udev_new();
1857 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001858 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001859 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001860 }
1861
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001862 ec->base.wl_display = display;
1863 ec->tty = tty_create(&ec->base, vt_func, tty);
1864 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02001865 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001866 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001867 }
1868
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001869 e = udev_enumerate_new(ec->udev);
1870 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02001871 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001872
Benjamin Franzke117483d2011-08-30 11:38:26 +02001873 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001874 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001875 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001876 path = udev_list_entry_get_name(entry);
1877 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001878 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001879 udev_device_get_property_value(device, "ID_SEAT");
1880 if (!device_seat)
1881 device_seat = default_seat;
1882 if (strcmp(device_seat, seat) == 0) {
1883 drm_device = device;
1884 break;
1885 }
1886 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001887 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001888
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001889 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001890 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001891 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001892 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001893
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001894 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001895 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001896 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001897 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001898
1899 ec->base.destroy = drm_destroy;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02001900
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001901 ec->base.focus = 1;
1902
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001903 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001904
Daniel Stone725c2c32012-06-22 14:04:36 +01001905 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01001906 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02001907
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001908 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01001909 weston_compositor_add_key_binding(&ec->base, key,
1910 MODIFIER_CTRL | MODIFIER_ALT,
1911 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001912
Jesse Barnes58ef3792012-02-23 09:45:49 -05001913 wl_list_init(&ec->sprite_list);
1914 create_sprites(ec);
1915
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001916 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001917 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01001918 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001919 }
1920
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02001921 path = NULL;
1922
Tiago Vignattice03ec32011-12-19 01:14:03 +02001923 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001924
1925 loop = wl_display_get_event_loop(ec->base.wl_display);
1926 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001927 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001928 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001929
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001930 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
1931 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001932 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001933 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001934 }
1935 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
1936 "drm", NULL);
1937 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001938 wl_event_loop_add_fd(loop,
1939 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001940 WL_EVENT_READABLE, udev_drm_event, ec);
1941
1942 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001943 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001944 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001945 }
1946
Daniel Stonea96b93c2012-06-22 14:04:37 +01001947 udev_device_unref(drm_device);
1948 udev_enumerate_unref(e);
1949
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001950 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001951
1952err_udev_monitor:
1953 wl_event_source_remove(ec->udev_drm_source);
1954 udev_monitor_unref(ec->udev_monitor);
1955err_drm_source:
1956 wl_event_source_remove(ec->drm_source);
1957 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
1958 evdev_input_destroy(weston_seat);
1959err_sprite:
1960 destroy_sprites(ec);
1961err_egl:
1962 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
1963 EGL_NO_CONTEXT);
1964 eglTerminate(ec->base.egl_display);
1965 eglReleaseThread();
1966 gbm_device_destroy(ec->gbm);
1967err_udev_dev:
1968 udev_device_unref(drm_device);
1969err_udev_enum:
1970 udev_enumerate_unref(e);
1971 tty_destroy(ec->tty);
1972err_udev:
1973 udev_unref(ec->udev);
1974err_compositor:
1975 weston_compositor_shutdown(&ec->base);
1976err_base:
1977 free(ec);
1978 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001979}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001980
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001981WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04001982backend_init(struct wl_display *display, int argc, char *argv[],
1983 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001984{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001985 int connector = 0, tty = 0;
1986 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001987
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001988 const struct weston_option drm_options[] = {
1989 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
1990 { WESTON_OPTION_STRING, "seat", 0, &seat },
1991 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001992 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001993 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02001994
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001995 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001996
Daniel Stonec1be8e52012-06-01 11:14:02 -04001997 return drm_compositor_create(display, connector, seat, tty, argc, argv,
1998 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001999}