blob: bc75a004cf14b2f15871c4fdd3fb9fe957c1255b [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);
1340 if (encoder == NULL)
1341 goto err_free;
1342 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1343 drmModeFreeEncoder(encoder);
1344 if (crtc == NULL)
1345 goto err_free;
1346 crtc_mode = crtc->mode;
1347 drmModeFreeCrtc(crtc);
1348
David Herrmann0f0d54e2011-12-08 17:05:45 +01001349 for (i = 0; i < connector->count_modes; i++) {
1350 ret = drm_output_add_mode(output, &connector->modes[i]);
1351 if (ret)
1352 goto err_free;
1353 }
1354
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001355 preferred = NULL;
1356 current = NULL;
1357 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
1358 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode)) {
1359 drm_mode->base.flags |= WL_OUTPUT_MODE_CURRENT;
1360 current = &drm_mode->base;
1361 }
1362 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
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001366 if (current == NULL) {
1367 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);
1372 current->flags |= WL_OUTPUT_MODE_CURRENT;
1373 }
1374
1375 if (preferred == NULL)
1376 preferred = current;
1377
1378 if (option_current_mode) {
1379 output->base.current = current;
1380 } else {
1381 output->base.current = preferred;
1382 current->flags &= ~WL_OUTPUT_MODE_CURRENT;
1383 preferred->flags |= WL_OUTPUT_MODE_CURRENT;
1384 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001385
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001386 output->surface = gbm_surface_create(ec->gbm,
1387 output->base.current->width,
1388 output->base.current->height,
1389 GBM_FORMAT_XRGB8888,
1390 GBM_BO_USE_SCANOUT |
1391 GBM_BO_USE_RENDERING);
1392 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001393 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001394 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001395 }
1396
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001397 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001398 eglCreateWindowSurface(ec->base.egl_display,
1399 ec->base.egl_config,
1400 output->surface,
1401 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001402 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001403 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001404 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001405 }
1406
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001407 output->cursor_bo[0] =
1408 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1409 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1410 output->cursor_bo[1] =
1411 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1412 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1413
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001414 output->backlight = backlight_init(drm_device,
1415 connector->connector_type);
1416 if (output->backlight) {
1417 output->base.set_backlight = drm_set_backlight;
1418 output->base.backlight_current = drm_get_backlight(output);
1419 }
1420
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001421 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001422 connector->mmWidth, connector->mmHeight,
1423 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001424
1425 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1426
Alex Wubd3354b2012-04-17 17:20:49 +08001427 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001428 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001429 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001430 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001431 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001432 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001433
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001434 weston_log("Output %s, (connector %d, crtc %d)\n",
1435 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001436 wl_list_for_each(m, &output->base.mode_list, link)
1437 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1438 m->width, m->height, m->refresh / 1000.0,
1439 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1440 ", preferred" : "",
1441 m->flags & WL_OUTPUT_MODE_CURRENT ?
1442 ", current" : "",
1443 connector->count_modes == 0 ?
1444 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001445
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001446 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001447
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001448err_surface:
1449 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001450err_free:
1451 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1452 base.link) {
1453 wl_list_remove(&drm_mode->base.link);
1454 free(drm_mode);
1455 }
1456
1457 drmModeFreeCrtc(output->original_crtc);
1458 ec->crtc_allocator &= ~(1 << output->crtc_id);
1459 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001460 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001461 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001462
David Herrmann0f0d54e2011-12-08 17:05:45 +01001463 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001464}
1465
Jesse Barnes58ef3792012-02-23 09:45:49 -05001466static void
1467create_sprites(struct drm_compositor *ec)
1468{
1469 struct drm_sprite *sprite;
1470 drmModePlaneRes *plane_res;
1471 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001472 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001473
1474 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1475 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001476 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001477 strerror(errno));
1478 return;
1479 }
1480
1481 for (i = 0; i < plane_res->count_planes; i++) {
1482 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1483 if (!plane)
1484 continue;
1485
1486 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1487 plane->count_formats));
1488 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001489 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001490 __func__);
1491 free(plane);
1492 continue;
1493 }
1494
1495 memset(sprite, 0, sizeof *sprite);
1496
1497 sprite->possible_crtcs = plane->possible_crtcs;
1498 sprite->plane_id = plane->plane_id;
1499 sprite->surface = NULL;
1500 sprite->pending_surface = NULL;
1501 sprite->fb_id = 0;
1502 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001503 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1504 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001505 sprite_handle_pending_buffer_destroy;
1506 sprite->compositor = ec;
1507 sprite->count_formats = plane->count_formats;
1508 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001509 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001510 drmModeFreePlane(plane);
1511
1512 wl_list_insert(&ec->sprite_list, &sprite->link);
1513 }
1514
1515 free(plane_res->planes);
1516 free(plane_res);
1517}
1518
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001519static void
1520destroy_sprites(struct drm_compositor *compositor)
1521{
1522 struct drm_sprite *sprite, *next;
1523 struct drm_output *output;
1524
1525 output = container_of(compositor->base.output_list.next,
1526 struct drm_output, base.link);
1527
1528 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1529 drmModeSetPlane(compositor->drm.fd,
1530 sprite->plane_id,
1531 output->crtc_id, 0, 0,
1532 0, 0, 0, 0, 0, 0, 0, 0);
1533 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1534 free(sprite);
1535 }
1536}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001537
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001538static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001539create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001540 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001541{
1542 drmModeConnector *connector;
1543 drmModeRes *resources;
1544 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001545 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001546
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001547 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001548 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001549 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001550 return -1;
1551 }
1552
Jesse Barnes58ef3792012-02-23 09:45:49 -05001553 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001554 if (!ec->crtcs) {
1555 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001556 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001557 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001558
1559 ec->num_crtcs = resources->count_crtcs;
1560 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1561
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001562 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001563 connector = drmModeGetConnector(ec->drm.fd,
1564 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001565 if (connector == NULL)
1566 continue;
1567
1568 if (connector->connection == DRM_MODE_CONNECTED &&
1569 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001570 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001571 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001572 connector, x, y,
1573 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001574 drmModeFreeConnector(connector);
1575 continue;
1576 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001577
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001578 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001579 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001580 link)->current->width;
1581 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001582
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001583 drmModeFreeConnector(connector);
1584 }
1585
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001586 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001587 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001588 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001589 return -1;
1590 }
1591
1592 drmModeFreeResources(resources);
1593
1594 return 0;
1595}
1596
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001597static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001598update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001599{
1600 drmModeConnector *connector;
1601 drmModeRes *resources;
1602 struct drm_output *output, *next;
1603 int x = 0, y = 0;
1604 int x_offset = 0, y_offset = 0;
1605 uint32_t connected = 0, disconnects = 0;
1606 int i;
1607
1608 resources = drmModeGetResources(ec->drm.fd);
1609 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001610 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001611 return;
1612 }
1613
1614 /* collect new connects */
1615 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001616 int connector_id = resources->connectors[i];
1617
1618 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001619 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001620 continue;
1621
David Herrmann7551cff2011-12-08 17:05:43 +01001622 if (connector->connection != DRM_MODE_CONNECTED) {
1623 drmModeFreeConnector(connector);
1624 continue;
1625 }
1626
Benjamin Franzke117483d2011-08-30 11:38:26 +02001627 connected |= (1 << connector_id);
1628
1629 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001630 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001631 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001632 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001633
1634 /* XXX: not yet needed, we die with 0 outputs */
1635 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001636 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001637 else
1638 x = 0;
1639 y = 0;
1640 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001641 connector, x, y,
1642 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001643 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001644
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001645 }
1646 drmModeFreeConnector(connector);
1647 }
1648 drmModeFreeResources(resources);
1649
1650 disconnects = ec->connector_allocator & ~connected;
1651 if (disconnects) {
1652 wl_list_for_each_safe(output, next, &ec->base.output_list,
1653 base.link) {
1654 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001655 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001656 output->base.x - x_offset,
1657 output->base.y - y_offset);
1658 }
1659
1660 if (disconnects & (1 << output->connector_id)) {
1661 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001662 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001663 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001664 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001665 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001666 }
1667 }
1668 }
1669
1670 /* FIXME: handle zero outputs, without terminating */
1671 if (ec->connector_allocator == 0)
1672 wl_display_terminate(ec->base.wl_display);
1673}
1674
1675static int
David Herrmannd7488c22012-03-11 20:05:21 +01001676udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001677{
David Herrmannd7488c22012-03-11 20:05:21 +01001678 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001679 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001680
1681 sysnum = udev_device_get_sysnum(device);
1682 if (!sysnum || atoi(sysnum) != ec->drm.id)
1683 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001684
David Herrmann6ac52db2012-03-11 20:05:22 +01001685 val = udev_device_get_property_value(device, "HOTPLUG");
1686 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001687 return 0;
1688
David Herrmann6ac52db2012-03-11 20:05:22 +01001689 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001690}
1691
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001692static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001693udev_drm_event(int fd, uint32_t mask, void *data)
1694{
1695 struct drm_compositor *ec = data;
1696 struct udev_device *event;
1697
1698 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001699
David Herrmannd7488c22012-03-11 20:05:21 +01001700 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001701 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001702
1703 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001704
1705 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001706}
1707
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001708static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001709drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001710{
1711 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001712 struct weston_seat *seat, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001713
Daniel Stone37816df2012-05-16 18:45:18 +01001714 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1715 evdev_input_destroy(seat);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001716
1717 wl_event_source_remove(d->udev_drm_source);
1718 wl_event_source_remove(d->drm_source);
1719
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001720 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001721
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001722 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001723 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001724 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001725 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001726 eglReleaseThread();
1727
Matt Roper361d2ad2011-08-29 13:52:23 -07001728 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001729 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001730 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001731 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001732 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001733
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001734 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001735}
1736
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001737static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001738drm_compositor_set_modes(struct drm_compositor *compositor)
1739{
1740 struct drm_output *output;
1741 struct drm_mode *drm_mode;
1742 int ret;
1743
1744 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1745 drm_mode = (struct drm_mode *) output->base.current;
1746 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001747 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001748 &output->connector_id, 1,
1749 &drm_mode->mode_info);
1750 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001751 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001752 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001753 drm_mode->base.width, drm_mode->base.height,
1754 output->base.x, output->base.y);
1755 }
1756 }
1757}
1758
1759static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001760vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001761{
1762 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001763 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001764 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001765 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001766
1767 switch (event) {
1768 case TTY_ENTER_VT:
1769 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001770 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001771 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001772 wl_display_terminate(compositor->wl_display);
1773 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001774 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001775 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001776 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01001777 wl_list_for_each(seat, &compositor->seat_list, link) {
1778 evdev_add_devices(ec->udev, seat);
1779 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02001780 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001781 break;
1782 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01001783 wl_list_for_each(seat, &compositor->seat_list, link) {
1784 evdev_disable_udev_monitor(seat);
1785 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04001786 }
1787
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001788 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001789 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001790 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04001791
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001792 /* If we have a repaint scheduled (either from a
1793 * pending pageflip or the idle handler), make sure we
1794 * cancel that so we don't try to pageflip when we're
1795 * vt switched away. The SLEEPING state will prevent
1796 * further attemps at repainting. When we switch
1797 * back, we schedule a repaint, which will process
1798 * pending frame callbacks. */
1799
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001800 wl_list_for_each(output, &ec->base.output_list, base.link) {
1801 output->base.repaint_needed = 0;
1802 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001803 }
1804
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001805 output = container_of(ec->base.output_list.next,
1806 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001807
1808 wl_list_for_each(sprite, &ec->sprite_list, link)
1809 drmModeSetPlane(ec->drm.fd,
1810 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001811 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001812 0, 0, 0, 0, 0, 0, 0, 0);
1813
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001814 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001815 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001816
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001817 break;
1818 };
1819}
1820
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001821static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01001822switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001823{
1824 struct drm_compositor *ec = data;
1825
Daniel Stone325fc2d2012-05-30 16:31:58 +01001826 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001827}
1828
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001829static const char default_seat[] = "seat0";
1830
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001831static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001832drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04001833 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04001834 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001835{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001836 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001837 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001838 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001839 struct udev_device *device, *drm_device;
1840 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001841 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001842 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001843 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001844
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001845 weston_log("initializing drm backend\n");
1846
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001847 ec = malloc(sizeof *ec);
1848 if (ec == NULL)
1849 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001850 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01001851
1852 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01001853 config_file) < 0) {
1854 weston_log("weston_compositor_init failed\n");
1855 goto err_base;
1856 }
Daniel Stone725c2c32012-06-22 14:04:36 +01001857
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001858 ec->udev = udev_new();
1859 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001860 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001861 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001862 }
1863
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001864 ec->base.wl_display = display;
1865 ec->tty = tty_create(&ec->base, vt_func, tty);
1866 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02001867 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001868 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001869 }
1870
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001871 e = udev_enumerate_new(ec->udev);
1872 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02001873 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001874
Benjamin Franzke117483d2011-08-30 11:38:26 +02001875 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001876 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001877 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001878 path = udev_list_entry_get_name(entry);
1879 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001880 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001881 udev_device_get_property_value(device, "ID_SEAT");
1882 if (!device_seat)
1883 device_seat = default_seat;
1884 if (strcmp(device_seat, seat) == 0) {
1885 drm_device = device;
1886 break;
1887 }
1888 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001889 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001890
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001891 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001892 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001893 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001894 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001895
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001896 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001897 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001898 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001899 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001900
1901 ec->base.destroy = drm_destroy;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02001902
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001903 ec->base.focus = 1;
1904
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001905 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001906
Daniel Stone725c2c32012-06-22 14:04:36 +01001907 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01001908 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02001909
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001910 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01001911 weston_compositor_add_key_binding(&ec->base, key,
1912 MODIFIER_CTRL | MODIFIER_ALT,
1913 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001914
Jesse Barnes58ef3792012-02-23 09:45:49 -05001915 wl_list_init(&ec->sprite_list);
1916 create_sprites(ec);
1917
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001918 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001919 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01001920 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001921 }
1922
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02001923 path = NULL;
1924
Tiago Vignattice03ec32011-12-19 01:14:03 +02001925 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001926
1927 loop = wl_display_get_event_loop(ec->base.wl_display);
1928 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001929 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001930 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001931
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001932 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
1933 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001934 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001935 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001936 }
1937 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
1938 "drm", NULL);
1939 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001940 wl_event_loop_add_fd(loop,
1941 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001942 WL_EVENT_READABLE, udev_drm_event, ec);
1943
1944 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001945 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001946 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001947 }
1948
Daniel Stonea96b93c2012-06-22 14:04:37 +01001949 udev_device_unref(drm_device);
1950 udev_enumerate_unref(e);
1951
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001952 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001953
1954err_udev_monitor:
1955 wl_event_source_remove(ec->udev_drm_source);
1956 udev_monitor_unref(ec->udev_monitor);
1957err_drm_source:
1958 wl_event_source_remove(ec->drm_source);
1959 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
1960 evdev_input_destroy(weston_seat);
1961err_sprite:
1962 destroy_sprites(ec);
1963err_egl:
1964 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
1965 EGL_NO_CONTEXT);
1966 eglTerminate(ec->base.egl_display);
1967 eglReleaseThread();
1968 gbm_device_destroy(ec->gbm);
1969err_udev_dev:
1970 udev_device_unref(drm_device);
1971err_udev_enum:
1972 udev_enumerate_unref(e);
1973 tty_destroy(ec->tty);
1974err_udev:
1975 udev_unref(ec->udev);
1976err_compositor:
1977 weston_compositor_shutdown(&ec->base);
1978err_base:
1979 free(ec);
1980 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001981}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001982
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001983WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04001984backend_init(struct wl_display *display, int argc, char *argv[],
1985 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001986{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001987 int connector = 0, tty = 0;
1988 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001989
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001990 const struct weston_option drm_options[] = {
1991 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
1992 { WESTON_OPTION_STRING, "seat", 0, &seat },
1993 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001994 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001995 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02001996
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001997 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001998
Daniel Stonec1be8e52012-06-01 11:14:02 -04001999 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2000 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002001}