blob: cd0395e25470874661d34cf07deecd82c303bc4c [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
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400818 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700819 free(output);
820}
821
Alex Wub7b8bda2012-04-17 17:20:48 +0800822static struct drm_mode *
823choose_mode (struct drm_output *output, struct weston_mode *target_mode)
824{
825 struct drm_mode *tmp_mode = NULL, *mode;
826
827 if (output->base.current->width == target_mode->width &&
828 output->base.current->height == target_mode->height &&
829 (output->base.current->refresh == target_mode->refresh ||
830 target_mode->refresh == 0))
831 return (struct drm_mode *)output->base.current;
832
833 wl_list_for_each(mode, &output->base.mode_list, base.link) {
834 if (mode->mode_info.hdisplay == target_mode->width &&
835 mode->mode_info.vdisplay == target_mode->height) {
836 if (mode->mode_info.vrefresh == target_mode->refresh ||
837 target_mode->refresh == 0) {
838 return mode;
839 } else if (!tmp_mode)
840 tmp_mode = mode;
841 }
842 }
843
844 return tmp_mode;
845}
846
847static int
848drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
849{
850 struct drm_output *output;
851 struct drm_mode *drm_mode;
852 int ret;
853 struct drm_compositor *ec;
854 struct gbm_surface *surface;
855 EGLSurface egl_surface;
856
857 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200858 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800859 return -1;
860 }
861
862 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200863 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800864 return -1;
865 }
866
867 ec = (struct drm_compositor *)output_base->compositor;
868 output = (struct drm_output *)output_base;
869 drm_mode = choose_mode (output, mode);
870
871 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200872 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800873 return -1;
874 } else if (&drm_mode->base == output->base.current) {
875 return 0;
876 } else if (drm_mode->base.width == output->base.current->width &&
877 drm_mode->base.height == output->base.current->height) {
878 /* only change refresh value */
879 ret = drmModeSetCrtc(ec->drm.fd,
880 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300881 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800882 &output->connector_id, 1, &drm_mode->mode_info);
883
884 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200885 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800886 drm_mode->base.width,
887 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400888 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800889 ret = -1;
890 } else {
891 output->base.current->flags = 0;
892 output->base.current = &drm_mode->base;
893 drm_mode->base.flags =
894 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
895 ret = 0;
896 }
897
898 return ret;
899 }
900
901 drm_mode->base.flags =
902 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
903
904 surface = gbm_surface_create(ec->gbm,
905 drm_mode->base.width,
906 drm_mode->base.height,
907 GBM_FORMAT_XRGB8888,
908 GBM_BO_USE_SCANOUT |
909 GBM_BO_USE_RENDERING);
910 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200911 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800912 return -1;
913 }
914
915 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400916 eglCreateWindowSurface(ec->base.egl_display,
917 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800918 surface, NULL);
919
920 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200921 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800922 goto err;
923 }
924
925 ret = drmModeSetCrtc(ec->drm.fd,
926 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300927 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800928 &output->connector_id, 1, &drm_mode->mode_info);
929 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200930 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800931 goto err;
932 }
933
934 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300935 if (output->current) {
936 if (output->current->is_client_buffer)
937 gbm_bo_destroy(output->current->bo);
938 else
939 gbm_surface_release_buffer(output->surface,
940 output->current->bo);
941 }
942 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800943
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300944 if (output->next) {
945 if (output->next->is_client_buffer)
946 gbm_bo_destroy(output->next->bo);
947 else
948 gbm_surface_release_buffer(output->surface,
949 output->next->bo);
950 }
951 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800952
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400953 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800954 gbm_surface_destroy(output->surface);
955 output->egl_surface = egl_surface;
956 output->surface = surface;
957
958 /*update output*/
959 output->base.current = &drm_mode->base;
960 output->base.dirty = 1;
961 weston_output_move(&output->base, output->base.x, output->base.y);
962 return 0;
963
964err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400965 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800966 gbm_surface_destroy(surface);
967 return -1;
968}
969
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400970static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400971on_drm_input(int fd, uint32_t mask, void *data)
972{
973 drmEventContext evctx;
974
975 memset(&evctx, 0, sizeof evctx);
976 evctx.version = DRM_EVENT_CONTEXT_VERSION;
977 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500978 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400979 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400980
981 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400982}
983
984static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400985init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400986{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400987 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -0400988 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400989 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400990 static const EGLint context_attribs[] = {
991 EGL_CONTEXT_CLIENT_VERSION, 2,
992 EGL_NONE
993 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400994
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400995 static const EGLint config_attribs[] = {
996 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
997 EGL_RED_SIZE, 1,
998 EGL_GREEN_SIZE, 1,
999 EGL_BLUE_SIZE, 1,
1000 EGL_ALPHA_SIZE, 0,
1001 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1002 EGL_NONE
1003 };
1004
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001005 sysnum = udev_device_get_sysnum(device);
1006 if (sysnum)
1007 ec->drm.id = atoi(sysnum);
1008 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001009 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001010 return -1;
1011 }
1012
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001013 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001014 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001015 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001016 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001017 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001018 udev_device_get_devnode(device));
1019 return -1;
1020 }
1021
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001022 weston_log("using %s\n", filename);
1023
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001024 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001025 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001026 ec->base.egl_display = eglGetDisplay(ec->gbm);
1027 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001028 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001029 return -1;
1030 }
1031
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001032 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001033 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001034 return -1;
1035 }
1036
Darxus55973f22010-11-22 21:24:39 -05001037 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001038 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001039 return -1;
1040 }
1041
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001042 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1043 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001044 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001045 return -1;
1046 }
1047
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001048 ec->base.egl_context =
1049 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1050 EGL_NO_CONTEXT, context_attribs);
1051 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001052 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001053 return -1;
1054 }
1055
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001056 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1057 GBM_FORMAT_XRGB8888,
1058 GBM_BO_USE_RENDERING);
1059 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001060 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001061 return -1;
1062 }
1063
1064 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001065 eglCreateWindowSurface(ec->base.egl_display,
1066 ec->base.egl_config,
1067 ec->dummy_surface,
1068 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001069 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001070 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001071 return -1;
1072 }
1073
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001074 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1075 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001076 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001077 return -1;
1078 }
1079
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001080 return 0;
1081}
1082
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001083static int
1084drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1085{
1086 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001087 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001088
1089 mode = malloc(sizeof *mode);
1090 if (mode == NULL)
1091 return -1;
1092
1093 mode->base.flags = 0;
1094 mode->base.width = info->hdisplay;
1095 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001096
1097 /* Calculate higher precision (mHz) refresh rate */
1098 refresh = (info->clock * 1000000LL / info->htotal +
1099 info->vtotal / 2) / info->vtotal;
1100
1101 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1102 refresh *= 2;
1103 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1104 refresh /= 2;
1105 if (info->vscan > 1)
1106 refresh /= info->vscan;
1107
1108 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001109 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001110
1111 if (info->type & DRM_MODE_TYPE_PREFERRED)
1112 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1113
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001114 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1115
1116 return 0;
1117}
1118
1119static int
1120drm_subpixel_to_wayland(int drm_value)
1121{
1122 switch (drm_value) {
1123 default:
1124 case DRM_MODE_SUBPIXEL_UNKNOWN:
1125 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1126 case DRM_MODE_SUBPIXEL_NONE:
1127 return WL_OUTPUT_SUBPIXEL_NONE;
1128 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1129 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1130 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1131 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1132 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1133 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1134 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1135 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1136 }
1137}
1138
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001139static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001140sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001141{
1142 struct drm_sprite *sprite =
1143 container_of(listener, struct drm_sprite,
1144 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001145 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001146
1147 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001148 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1149 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001150}
1151
1152static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001153sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001154{
1155 struct drm_sprite *sprite =
1156 container_of(listener, struct drm_sprite,
1157 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001158 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001159
1160 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001161 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1162 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001163}
1164
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001165/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001166static uint32_t
1167drm_get_backlight(struct drm_output *output)
1168{
1169 long brightness, max_brightness, norm;
1170
1171 brightness = backlight_get_brightness(output->backlight);
1172 max_brightness = backlight_get_max_brightness(output->backlight);
1173
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001174 /* convert it on a scale of 0 to 255 */
1175 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001176
1177 return (uint32_t) norm;
1178}
1179
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001180/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001181static void
1182drm_set_backlight(struct weston_output *output_base, uint32_t value)
1183{
1184 struct drm_output *output = (struct drm_output *) output_base;
1185 long max_brightness, new_brightness;
1186
1187 if (!output->backlight)
1188 return;
1189
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001190 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001191 return;
1192
1193 max_brightness = backlight_get_max_brightness(output->backlight);
1194
1195 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001196 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001197
1198 backlight_set_brightness(output->backlight, new_brightness);
1199}
1200
1201static drmModePropertyPtr
1202drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1203{
1204 drmModePropertyPtr props;
1205 int i;
1206
1207 for (i = 0; i < connector->count_props; i++) {
1208 props = drmModeGetProperty(fd, connector->props[i]);
1209 if (!props)
1210 continue;
1211
1212 if (!strcmp(props->name, name))
1213 return props;
1214
1215 drmModeFreeProperty(props);
1216 }
1217
1218 return NULL;
1219}
1220
1221static void
1222drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1223{
1224 struct drm_output *output = (struct drm_output *) output_base;
1225 struct weston_compositor *ec = output_base->compositor;
1226 struct drm_compositor *c = (struct drm_compositor *) ec;
1227 drmModeConnectorPtr connector;
1228 drmModePropertyPtr prop;
1229
1230 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1231 if (!connector)
1232 return;
1233
1234 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1235 if (!prop) {
1236 drmModeFreeConnector(connector);
1237 return;
1238 }
1239
1240 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1241 prop->prop_id, level);
1242 drmModeFreeProperty(prop);
1243 drmModeFreeConnector(connector);
1244}
1245
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001246static const char *connector_type_names[] = {
1247 "None",
1248 "VGA",
1249 "DVI",
1250 "DVI",
1251 "DVI",
1252 "Composite",
1253 "TV",
1254 "LVDS",
1255 "CTV",
1256 "DIN",
1257 "DP",
1258 "HDMI",
1259 "HDMI",
1260 "TV",
1261 "eDP",
1262};
1263
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001264static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001265find_crtc_for_connector(struct drm_compositor *ec,
1266 drmModeRes *resources, drmModeConnector *connector)
1267{
1268 drmModeEncoder *encoder;
1269 uint32_t possible_crtcs;
1270 int i, j;
1271
1272 for (j = 0; j < connector->count_encoders; j++) {
1273 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1274 if (encoder == NULL) {
1275 weston_log("Failed to get encoder.\n");
1276 return -1;
1277 }
1278 possible_crtcs = encoder->possible_crtcs;
1279 drmModeFreeEncoder(encoder);
1280
1281 for (i = 0; i < resources->count_crtcs; i++) {
1282 if (possible_crtcs & (1 << i) &&
1283 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1284 return i;
1285 }
1286 }
1287
1288 return -1;
1289}
1290
1291static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001292create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001293 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001294 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001295 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001296{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001297 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001298 struct drm_mode *drm_mode, *next;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001299 struct weston_mode *m, *preferred, *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001300 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001301 drmModeModeInfo crtc_mode;
1302 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001303 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001304 char name[32];
1305 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001306
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001307 i = find_crtc_for_connector(ec, resources, connector);
1308 if (i < 0) {
1309 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001310 return -1;
1311 }
1312
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001313 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001314 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001315 return -1;
1316
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001317 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001318 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1319 output->base.make = "unknown";
1320 output->base.model = "unknown";
1321 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001322
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001323 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1324 type_name = connector_type_names[connector->connector_type];
1325 else
1326 type_name = "UNKNOWN";
1327 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1328 output->name = strdup(name);
1329
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001330 output->crtc_id = resources->crtcs[i];
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001331 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001332 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001333 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001334
Matt Roper361d2ad2011-08-29 13:52:23 -07001335 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1336
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001337 /* Get the current mode on the crtc that's currently driving
1338 * this connector. */
1339 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001340 memset(&crtc_mode, 0, sizeof crtc_mode);
1341 if (encoder != NULL) {
1342 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1343 drmModeFreeEncoder(encoder);
1344 if (crtc == NULL)
1345 goto err_free;
1346 if (crtc->mode_valid)
1347 crtc_mode = crtc->mode;
1348 drmModeFreeCrtc(crtc);
1349 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001350
David Herrmann0f0d54e2011-12-08 17:05:45 +01001351 for (i = 0; i < connector->count_modes; i++) {
1352 ret = drm_output_add_mode(output, &connector->modes[i]);
1353 if (ret)
1354 goto err_free;
1355 }
1356
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001357 preferred = NULL;
1358 current = NULL;
1359 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Wang Quanxianacb805a2012-07-30 18:09:46 -04001360 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001361 current = &drm_mode->base;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001362 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1363 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001364 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001365
Wang Quanxianacb805a2012-07-30 18:09:46 -04001366 if (current == NULL && crtc_mode.clock != 0) {
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001367 ret = drm_output_add_mode(output, &crtc_mode);
1368 if (ret)
1369 goto err_free;
1370 current = container_of(output->base.mode_list.prev,
1371 struct weston_mode, link);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001372 }
1373
Wang Quanxianacb805a2012-07-30 18:09:46 -04001374 if (option_current_mode && current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001375 output->base.current = current;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001376 else if (preferred)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001377 output->base.current = preferred;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001378 else if (current)
1379 output->base.current = current;
1380
1381 if (output->base.current == NULL) {
1382 weston_log("no available modes for %s\n", output->name);
1383 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001384 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001385
Wang Quanxianacb805a2012-07-30 18:09:46 -04001386 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1387
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001388 output->surface = gbm_surface_create(ec->gbm,
1389 output->base.current->width,
1390 output->base.current->height,
1391 GBM_FORMAT_XRGB8888,
1392 GBM_BO_USE_SCANOUT |
1393 GBM_BO_USE_RENDERING);
1394 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001395 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001396 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001397 }
1398
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001399 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001400 eglCreateWindowSurface(ec->base.egl_display,
1401 ec->base.egl_config,
1402 output->surface,
1403 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001404 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001405 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001406 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001407 }
1408
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001409 output->cursor_bo[0] =
1410 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1411 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1412 output->cursor_bo[1] =
1413 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1414 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1415
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001416 output->backlight = backlight_init(drm_device,
1417 connector->connector_type);
1418 if (output->backlight) {
1419 output->base.set_backlight = drm_set_backlight;
1420 output->base.backlight_current = drm_get_backlight(output);
1421 }
1422
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001423 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001424 connector->mmWidth, connector->mmHeight,
1425 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001426
1427 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1428
Alex Wubd3354b2012-04-17 17:20:49 +08001429 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001430 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001431 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001432 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001433 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001434 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001435
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001436 weston_log("Output %s, (connector %d, crtc %d)\n",
1437 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001438 wl_list_for_each(m, &output->base.mode_list, link)
1439 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1440 m->width, m->height, m->refresh / 1000.0,
1441 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1442 ", preferred" : "",
1443 m->flags & WL_OUTPUT_MODE_CURRENT ?
1444 ", current" : "",
1445 connector->count_modes == 0 ?
1446 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001447
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001448 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001449
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001450err_surface:
1451 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001452err_free:
1453 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1454 base.link) {
1455 wl_list_remove(&drm_mode->base.link);
1456 free(drm_mode);
1457 }
1458
1459 drmModeFreeCrtc(output->original_crtc);
1460 ec->crtc_allocator &= ~(1 << output->crtc_id);
1461 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001462 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001463 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001464
David Herrmann0f0d54e2011-12-08 17:05:45 +01001465 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001466}
1467
Jesse Barnes58ef3792012-02-23 09:45:49 -05001468static void
1469create_sprites(struct drm_compositor *ec)
1470{
1471 struct drm_sprite *sprite;
1472 drmModePlaneRes *plane_res;
1473 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001474 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001475
1476 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1477 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001478 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001479 strerror(errno));
1480 return;
1481 }
1482
1483 for (i = 0; i < plane_res->count_planes; i++) {
1484 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1485 if (!plane)
1486 continue;
1487
1488 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1489 plane->count_formats));
1490 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001491 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001492 __func__);
1493 free(plane);
1494 continue;
1495 }
1496
1497 memset(sprite, 0, sizeof *sprite);
1498
1499 sprite->possible_crtcs = plane->possible_crtcs;
1500 sprite->plane_id = plane->plane_id;
1501 sprite->surface = NULL;
1502 sprite->pending_surface = NULL;
1503 sprite->fb_id = 0;
1504 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001505 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1506 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001507 sprite_handle_pending_buffer_destroy;
1508 sprite->compositor = ec;
1509 sprite->count_formats = plane->count_formats;
1510 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001511 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001512 drmModeFreePlane(plane);
1513
1514 wl_list_insert(&ec->sprite_list, &sprite->link);
1515 }
1516
1517 free(plane_res->planes);
1518 free(plane_res);
1519}
1520
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001521static void
1522destroy_sprites(struct drm_compositor *compositor)
1523{
1524 struct drm_sprite *sprite, *next;
1525 struct drm_output *output;
1526
1527 output = container_of(compositor->base.output_list.next,
1528 struct drm_output, base.link);
1529
1530 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1531 drmModeSetPlane(compositor->drm.fd,
1532 sprite->plane_id,
1533 output->crtc_id, 0, 0,
1534 0, 0, 0, 0, 0, 0, 0, 0);
1535 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1536 free(sprite);
1537 }
1538}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001539
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001540static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001541create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001542 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001543{
1544 drmModeConnector *connector;
1545 drmModeRes *resources;
1546 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001547 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001548
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001549 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001550 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001551 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001552 return -1;
1553 }
1554
Jesse Barnes58ef3792012-02-23 09:45:49 -05001555 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001556 if (!ec->crtcs) {
1557 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001558 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001559 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001560
1561 ec->num_crtcs = resources->count_crtcs;
1562 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1563
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001564 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001565 connector = drmModeGetConnector(ec->drm.fd,
1566 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001567 if (connector == NULL)
1568 continue;
1569
1570 if (connector->connection == DRM_MODE_CONNECTED &&
1571 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001572 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001573 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001574 connector, x, y,
1575 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001576 drmModeFreeConnector(connector);
1577 continue;
1578 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001579
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001580 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001581 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001582 link)->current->width;
1583 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001584
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001585 drmModeFreeConnector(connector);
1586 }
1587
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001588 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001589 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001590 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001591 return -1;
1592 }
1593
1594 drmModeFreeResources(resources);
1595
1596 return 0;
1597}
1598
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001599static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001600update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001601{
1602 drmModeConnector *connector;
1603 drmModeRes *resources;
1604 struct drm_output *output, *next;
1605 int x = 0, y = 0;
1606 int x_offset = 0, y_offset = 0;
1607 uint32_t connected = 0, disconnects = 0;
1608 int i;
1609
1610 resources = drmModeGetResources(ec->drm.fd);
1611 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001612 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001613 return;
1614 }
1615
1616 /* collect new connects */
1617 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001618 int connector_id = resources->connectors[i];
1619
1620 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001621 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001622 continue;
1623
David Herrmann7551cff2011-12-08 17:05:43 +01001624 if (connector->connection != DRM_MODE_CONNECTED) {
1625 drmModeFreeConnector(connector);
1626 continue;
1627 }
1628
Benjamin Franzke117483d2011-08-30 11:38:26 +02001629 connected |= (1 << connector_id);
1630
1631 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001632 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001633 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001634 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001635
1636 /* XXX: not yet needed, we die with 0 outputs */
1637 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001638 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001639 else
1640 x = 0;
1641 y = 0;
1642 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001643 connector, x, y,
1644 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001645 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001646
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001647 }
1648 drmModeFreeConnector(connector);
1649 }
1650 drmModeFreeResources(resources);
1651
1652 disconnects = ec->connector_allocator & ~connected;
1653 if (disconnects) {
1654 wl_list_for_each_safe(output, next, &ec->base.output_list,
1655 base.link) {
1656 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001657 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001658 output->base.x - x_offset,
1659 output->base.y - y_offset);
1660 }
1661
1662 if (disconnects & (1 << output->connector_id)) {
1663 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001664 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001665 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001666 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001667 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001668 }
1669 }
1670 }
1671
1672 /* FIXME: handle zero outputs, without terminating */
1673 if (ec->connector_allocator == 0)
1674 wl_display_terminate(ec->base.wl_display);
1675}
1676
1677static int
David Herrmannd7488c22012-03-11 20:05:21 +01001678udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001679{
David Herrmannd7488c22012-03-11 20:05:21 +01001680 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001681 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001682
1683 sysnum = udev_device_get_sysnum(device);
1684 if (!sysnum || atoi(sysnum) != ec->drm.id)
1685 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001686
David Herrmann6ac52db2012-03-11 20:05:22 +01001687 val = udev_device_get_property_value(device, "HOTPLUG");
1688 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001689 return 0;
1690
David Herrmann6ac52db2012-03-11 20:05:22 +01001691 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001692}
1693
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001694static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001695udev_drm_event(int fd, uint32_t mask, void *data)
1696{
1697 struct drm_compositor *ec = data;
1698 struct udev_device *event;
1699
1700 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001701
David Herrmannd7488c22012-03-11 20:05:21 +01001702 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001703 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001704
1705 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001706
1707 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001708}
1709
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001710static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001711drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001712{
1713 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001714 struct weston_seat *seat, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001715
Daniel Stone37816df2012-05-16 18:45:18 +01001716 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1717 evdev_input_destroy(seat);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001718
1719 wl_event_source_remove(d->udev_drm_source);
1720 wl_event_source_remove(d->drm_source);
1721
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001722 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001723
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001724 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001725 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001726 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001727 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001728 eglReleaseThread();
1729
Matt Roper361d2ad2011-08-29 13:52:23 -07001730 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001731 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001732 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001733 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001734 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001735
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001736 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001737}
1738
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001739static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001740drm_compositor_set_modes(struct drm_compositor *compositor)
1741{
1742 struct drm_output *output;
1743 struct drm_mode *drm_mode;
1744 int ret;
1745
1746 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1747 drm_mode = (struct drm_mode *) output->base.current;
1748 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001749 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001750 &output->connector_id, 1,
1751 &drm_mode->mode_info);
1752 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001753 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001754 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001755 drm_mode->base.width, drm_mode->base.height,
1756 output->base.x, output->base.y);
1757 }
1758 }
1759}
1760
1761static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001762vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001763{
1764 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001765 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001766 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001767 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001768
1769 switch (event) {
1770 case TTY_ENTER_VT:
1771 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001772 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001773 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001774 wl_display_terminate(compositor->wl_display);
1775 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001776 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001777 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001778 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01001779 wl_list_for_each(seat, &compositor->seat_list, link) {
1780 evdev_add_devices(ec->udev, seat);
1781 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02001782 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001783 break;
1784 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01001785 wl_list_for_each(seat, &compositor->seat_list, link) {
1786 evdev_disable_udev_monitor(seat);
1787 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04001788 }
1789
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001790 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001791 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001792 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04001793
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001794 /* If we have a repaint scheduled (either from a
1795 * pending pageflip or the idle handler), make sure we
1796 * cancel that so we don't try to pageflip when we're
1797 * vt switched away. The SLEEPING state will prevent
1798 * further attemps at repainting. When we switch
1799 * back, we schedule a repaint, which will process
1800 * pending frame callbacks. */
1801
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001802 wl_list_for_each(output, &ec->base.output_list, base.link) {
1803 output->base.repaint_needed = 0;
1804 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001805 }
1806
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001807 output = container_of(ec->base.output_list.next,
1808 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001809
1810 wl_list_for_each(sprite, &ec->sprite_list, link)
1811 drmModeSetPlane(ec->drm.fd,
1812 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001813 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001814 0, 0, 0, 0, 0, 0, 0, 0);
1815
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001816 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001817 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001818
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001819 break;
1820 };
1821}
1822
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001823static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01001824switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001825{
1826 struct drm_compositor *ec = data;
1827
Daniel Stone325fc2d2012-05-30 16:31:58 +01001828 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001829}
1830
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001831static const char default_seat[] = "seat0";
1832
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001833static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001834drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04001835 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04001836 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001837{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001838 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001839 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001840 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001841 struct udev_device *device, *drm_device;
1842 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001843 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001844 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001845 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001846
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001847 weston_log("initializing drm backend\n");
1848
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001849 ec = malloc(sizeof *ec);
1850 if (ec == NULL)
1851 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001852 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01001853
1854 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01001855 config_file) < 0) {
1856 weston_log("weston_compositor_init failed\n");
1857 goto err_base;
1858 }
Daniel Stone725c2c32012-06-22 14:04:36 +01001859
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001860 ec->udev = udev_new();
1861 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001862 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001863 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001864 }
1865
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001866 ec->base.wl_display = display;
1867 ec->tty = tty_create(&ec->base, vt_func, tty);
1868 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02001869 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001870 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001871 }
1872
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001873 e = udev_enumerate_new(ec->udev);
1874 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02001875 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001876
Benjamin Franzke117483d2011-08-30 11:38:26 +02001877 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001878 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001879 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001880 path = udev_list_entry_get_name(entry);
1881 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001882 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001883 udev_device_get_property_value(device, "ID_SEAT");
1884 if (!device_seat)
1885 device_seat = default_seat;
1886 if (strcmp(device_seat, seat) == 0) {
1887 drm_device = device;
1888 break;
1889 }
1890 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001891 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001892
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001893 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001894 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001895 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001896 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001897
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001898 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001899 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001900 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001901 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001902
1903 ec->base.destroy = drm_destroy;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02001904
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001905 ec->base.focus = 1;
1906
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001907 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001908
Daniel Stone725c2c32012-06-22 14:04:36 +01001909 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01001910 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02001911
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001912 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01001913 weston_compositor_add_key_binding(&ec->base, key,
1914 MODIFIER_CTRL | MODIFIER_ALT,
1915 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001916
Jesse Barnes58ef3792012-02-23 09:45:49 -05001917 wl_list_init(&ec->sprite_list);
1918 create_sprites(ec);
1919
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001920 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001921 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01001922 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001923 }
1924
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02001925 path = NULL;
1926
Tiago Vignattice03ec32011-12-19 01:14:03 +02001927 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001928
1929 loop = wl_display_get_event_loop(ec->base.wl_display);
1930 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001931 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001932 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001933
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001934 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
1935 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001936 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001937 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001938 }
1939 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
1940 "drm", NULL);
1941 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001942 wl_event_loop_add_fd(loop,
1943 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001944 WL_EVENT_READABLE, udev_drm_event, ec);
1945
1946 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001947 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001948 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001949 }
1950
Daniel Stonea96b93c2012-06-22 14:04:37 +01001951 udev_device_unref(drm_device);
1952 udev_enumerate_unref(e);
1953
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001954 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001955
1956err_udev_monitor:
1957 wl_event_source_remove(ec->udev_drm_source);
1958 udev_monitor_unref(ec->udev_monitor);
1959err_drm_source:
1960 wl_event_source_remove(ec->drm_source);
1961 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
1962 evdev_input_destroy(weston_seat);
1963err_sprite:
1964 destroy_sprites(ec);
1965err_egl:
1966 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
1967 EGL_NO_CONTEXT);
1968 eglTerminate(ec->base.egl_display);
1969 eglReleaseThread();
1970 gbm_device_destroy(ec->gbm);
1971err_udev_dev:
1972 udev_device_unref(drm_device);
1973err_udev_enum:
1974 udev_enumerate_unref(e);
1975 tty_destroy(ec->tty);
1976err_udev:
1977 udev_unref(ec->udev);
1978err_compositor:
1979 weston_compositor_shutdown(&ec->base);
1980err_base:
1981 free(ec);
1982 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001983}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001984
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001985WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04001986backend_init(struct wl_display *display, int argc, char *argv[],
1987 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001988{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001989 int connector = 0, tty = 0;
1990 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001991
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001992 const struct weston_option drm_options[] = {
1993 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
1994 { WESTON_OPTION_STRING, "seat", 0, &seat },
1995 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001996 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001997 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02001998
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001999 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002000
Daniel Stonec1be8e52012-06-01 11:14:02 -04002001 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2002 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002003}