blob: 7c5ba6e01a60c60e9f9adfff1ead4866dabf79c5 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040024#define _GNU_SOURCE
25
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
28#include <string.h>
29#include <fcntl.h>
30#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040031#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030032#include <assert.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033
Benjamin Franzkec649a922011-03-02 11:56:04 +010034#include <xf86drm.h>
35#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050036#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010037
Benjamin Franzke060cf802011-04-30 09:32:11 +020038#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020039#include <libbacklight.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020040
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040041#include "compositor.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020042#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010043#include "launcher-util.h"
Martin Minarik6d118362012-06-07 18:01:59 +020044#include "log.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Kristian Høgsberg061c4252012-06-28 11:28:15 -040046static int option_current_mode = 0;
47
Kristian Høgsbergd553bfc2012-06-18 22:37:35 -040048enum {
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -040049 WESTON_PLANE_DRM_CURSOR = 0x100,
50 WESTON_PLANE_DRM_PLANE = 0x101,
51 WESTON_PLANE_DRM_FB = 0x102
Kristian Høgsbergd553bfc2012-06-18 22:37:35 -040052};
53
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040054struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050055 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040056
57 struct udev *udev;
58 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040059
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010060 struct udev_monitor *udev_monitor;
61 struct wl_event_source *udev_drm_source;
62
Benjamin Franzke2af7f102011-03-02 11:14:59 +010063 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010064 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010065 int fd;
66 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020067 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050068 uint32_t *crtcs;
69 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050070 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010071 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050072 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020073
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040074 struct gbm_surface *dummy_surface;
75 EGLSurface dummy_egl_surface;
76
Jesse Barnes58ef3792012-02-23 09:45:49 -050077 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050078 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -050079
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020080 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040081};
82
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040083struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050084 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040085 drmModeModeInfo mode_info;
86};
87
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +030088struct drm_output;
89
90struct drm_fb {
91 struct gbm_bo *bo;
92 struct drm_output *output;
93 uint32_t fb_id;
94 int is_client_buffer;
95 struct wl_buffer *buffer;
96 struct wl_listener buffer_destroy_listener;
97};
98
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040099struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500100 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400101
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400102 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400103 uint32_t crtc_id;
104 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700105 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200106
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300107 int vblank_pending;
108 int page_flip_pending;
109
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400110 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400111 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400112 int current_cursor, cursor_free, cursor_x, cursor_y;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400113 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200115 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400116};
117
Jesse Barnes58ef3792012-02-23 09:45:49 -0500118/*
119 * An output has a primary display plane plus zero or more sprites for
120 * blending display contents.
121 */
122struct drm_sprite {
123 struct wl_list link;
124
125 uint32_t fb_id;
126 uint32_t pending_fb_id;
127 struct weston_surface *surface;
128 struct weston_surface *pending_surface;
129
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300130 struct drm_output *output;
131
Jesse Barnes58ef3792012-02-23 09:45:49 -0500132 struct drm_compositor *compositor;
133
134 struct wl_listener destroy_listener;
135 struct wl_listener pending_destroy_listener;
136
137 uint32_t possible_crtcs;
138 uint32_t plane_id;
139 uint32_t count_formats;
140
141 int32_t src_x, src_y;
142 uint32_t src_w, src_h;
143 uint32_t dest_x, dest_y;
144 uint32_t dest_w, dest_h;
145
146 uint32_t formats[];
147};
148
149static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500150drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
151{
152 struct weston_compositor *ec = output_base->compositor;
153 struct drm_compositor *c =(struct drm_compositor *) ec;
154 struct drm_output *output = (struct drm_output *) output_base;
155 int crtc;
156
157 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
158 if (c->crtcs[crtc] != output->crtc_id)
159 continue;
160
161 if (supported & (1 << crtc))
162 return -1;
163 }
164
165 return 0;
166}
167
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300168static void
169drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
170{
171 struct drm_fb *fb = data;
172 struct gbm_device *gbm = gbm_bo_get_device(bo);
173
174 if (fb->fb_id)
175 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
176
177 if (fb->buffer) {
178 weston_buffer_post_release(fb->buffer);
179 wl_list_remove(&fb->buffer_destroy_listener.link);
180 }
181
182 free(data);
183}
184
185static struct drm_fb *
186drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
187{
188 struct drm_fb *fb = gbm_bo_get_user_data(bo);
189 struct drm_compositor *compositor =
190 (struct drm_compositor *) output->base.compositor;
191 uint32_t width, height, stride, handle;
192 int ret;
193
194 if (fb)
195 return fb;
196
197 fb = malloc(sizeof *fb);
198
199 fb->bo = bo;
200 fb->output = output;
201 fb->is_client_buffer = 0;
202 fb->buffer = NULL;
203
204 width = gbm_bo_get_width(bo);
205 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400206 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300207 handle = gbm_bo_get_handle(bo).u32;
208
209 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
210 stride, handle, &fb->fb_id);
211 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200212 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300213 free(fb);
214 return NULL;
215 }
216
217 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
218
219 return fb;
220}
221
222static void
223fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
224{
225 struct drm_fb *fb = container_of(listener, struct drm_fb,
226 buffer_destroy_listener);
227
228 fb->buffer = NULL;
229
230 if (fb == fb->output->next ||
231 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400232 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300233}
234
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500235static int
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400236drm_output_prepare_scanout_surface(struct weston_output *_output,
237 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500238{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400239 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500240 struct drm_compositor *c =
241 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300242 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500243
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500244 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200245 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200246 es->geometry.width != output->base.current->width ||
247 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200248 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400249 es->buffer == NULL)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500250 return -1;
251
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400252 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
253 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500254
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300255 /* Need to verify output->region contained in surface opaque
256 * region. Or maybe just that format doesn't have alpha.
257 * For now, scanout only if format is XRGB8888. */
258 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
259 gbm_bo_destroy(bo);
260 return -1;
261 }
262
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300263 output->next = drm_fb_get_from_bo(bo, output);
264 if (!output->next) {
265 gbm_bo_destroy(bo);
266 return -1;
267 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500268
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300269 output->next->is_client_buffer = 1;
270 output->next->buffer = es->buffer;
271 output->next->buffer->busy_count++;
272 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
273
274 wl_signal_add(&output->next->buffer->resource.destroy_signal,
275 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500276
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400277 es->plane = WESTON_PLANE_DRM_FB;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500278
279 return 0;
280}
281
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500282static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400283drm_output_render(struct drm_output *output, pixman_region32_t *damage)
284{
285 struct drm_compositor *compositor =
286 (struct drm_compositor *) output->base.compositor;
287 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300288 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400289
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400290 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
291 output->egl_surface,
292 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200293 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400294 return;
295 }
296
297 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400298 if (surface->plane == WESTON_PLANE_PRIMARY)
299 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400300
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400301 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600302
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400303 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300304 bo = gbm_surface_lock_front_buffer(output->surface);
305 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200306 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400307 return;
308 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300309
310 output->next = drm_fb_get_from_bo(bo, output);
311 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200312 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300313 gbm_surface_release_buffer(output->surface, bo);
314 return;
315 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400316}
317
318static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500319drm_output_repaint(struct weston_output *output_base,
320 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100321{
322 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500323 struct drm_compositor *compositor =
324 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500325 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400326 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500327 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100328
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400330 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400332 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100333
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400334 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300335 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400336 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300337 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400338 &output->connector_id, 1,
339 &mode->mode_info);
340 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200341 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400342 return;
343 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200344 }
345
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500346 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300347 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500348 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200349 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500350 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500351 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100352
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300353 output->page_flip_pending = 1;
354
Jesse Barnes58ef3792012-02-23 09:45:49 -0500355 /*
356 * Now, update all the sprite surfaces
357 */
358 wl_list_for_each(s, &compositor->sprite_list, link) {
359 uint32_t flags = 0;
360 drmVBlank vbl = {
361 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
362 .request.sequence = 1,
363 };
364
365 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
366 continue;
367
368 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
369 output->crtc_id, s->pending_fb_id, flags,
370 s->dest_x, s->dest_y,
371 s->dest_w, s->dest_h,
372 s->src_x, s->src_y,
373 s->src_w, s->src_h);
374 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200375 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500376 ret, strerror(errno));
377
378 /*
379 * Queue a vblank signal so we know when the surface
380 * becomes active on the display or has been replaced.
381 */
382 vbl.request.signal = (unsigned long)s;
383 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
384 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200385 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500386 ret, strerror(errno));
387 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300388
389 s->output = output;
390 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500391 }
392
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500393 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400394}
395
396static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500397vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
398 void *data)
399{
400 struct drm_sprite *s = (struct drm_sprite *)data;
401 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300402 struct drm_output *output = s->output;
403 uint32_t msecs;
404
405 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500406
407 if (s->surface) {
408 weston_buffer_post_release(s->surface->buffer);
409 wl_list_remove(&s->destroy_listener.link);
410 s->surface = NULL;
411 drmModeRmFB(c->drm.fd, s->fb_id);
412 s->fb_id = 0;
413 }
414
415 if (s->pending_surface) {
416 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400417 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
418 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500419 s->surface = s->pending_surface;
420 s->pending_surface = NULL;
421 s->fb_id = s->pending_fb_id;
422 s->pending_fb_id = 0;
423 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300424
425 if (!output->page_flip_pending) {
426 msecs = sec * 1000 + usec / 1000;
427 weston_output_finish_frame(&output->base, msecs);
428 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500429}
430
431static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400432page_flip_handler(int fd, unsigned int frame,
433 unsigned int sec, unsigned int usec, void *data)
434{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200435 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400436 uint32_t msecs;
437
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300438 output->page_flip_pending = 0;
439
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300440 if (output->current) {
441 if (output->current->is_client_buffer)
442 gbm_bo_destroy(output->current->bo);
443 else
444 gbm_surface_release_buffer(output->surface,
445 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200446 }
447
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300448 output->current = output->next;
449 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400450
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300451 if (!output->vblank_pending) {
452 msecs = sec * 1000 + usec / 1000;
453 weston_output_finish_frame(&output->base, msecs);
454 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200455}
456
457static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500458drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
459{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400460 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500461
462 for (i = 0; i < s->count_formats; i++)
463 if (s->formats[i] == format)
464 return 1;
465
466 return 0;
467}
468
469static int
470drm_surface_transform_supported(struct weston_surface *es)
471{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400472 struct weston_matrix *matrix = &es->transform.matrix;
473 int i;
474
475 if (!es->transform.enabled)
476 return 1;
477
478 for (i = 0; i < 16; i++) {
479 switch (i) {
480 case 10:
481 case 15:
482 if (matrix->d[i] != 1.0)
483 return 0;
484 break;
485 case 0:
486 case 5:
487 case 12:
488 case 13:
489 break;
490 default:
491 if (matrix->d[i] != 0.0)
492 return 0;
493 break;
494 }
495 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500496
497 return 1;
498}
499
Jesse Barnes58ef3792012-02-23 09:45:49 -0500500static void
501drm_disable_unused_sprites(struct weston_output *output_base)
502{
503 struct weston_compositor *ec = output_base->compositor;
504 struct drm_compositor *c =(struct drm_compositor *) ec;
505 struct drm_output *output = (struct drm_output *) output_base;
506 struct drm_sprite *s;
507 int ret;
508
509 wl_list_for_each(s, &c->sprite_list, link) {
510 if (s->pending_fb_id)
511 continue;
512
513 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
514 output->crtc_id, 0, 0,
515 0, 0, 0, 0, 0, 0, 0, 0);
516 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200517 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500518 ret, strerror(errno));
519 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300520
521 if (s->surface) {
522 s->surface = NULL;
523 wl_list_remove(&s->destroy_listener.link);
524 }
525
526 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500527 s->fb_id = 0;
528 s->pending_fb_id = 0;
529 }
530}
531
532/*
533 * This function must take care to damage any previously assigned surface
534 * if the sprite ends up binding to a different surface than in the
535 * previous frame.
536 */
537static int
538drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400539 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500540{
541 struct weston_compositor *ec = output_base->compositor;
542 struct drm_compositor *c =(struct drm_compositor *) ec;
543 struct drm_sprite *s;
544 int found = 0;
545 EGLint handle, stride;
546 struct gbm_bo *bo;
547 uint32_t fb_id = 0;
548 uint32_t handles[4], pitches[4], offsets[4];
549 int ret = 0;
550 pixman_region32_t dest_rect, src_rect;
551 pixman_box32_t *box;
552 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400553 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500554
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500555 if (c->sprites_are_broken)
556 return -1;
557
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300558 if (es->output_mask != (1u << output_base->id))
559 return -1;
560
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400561 if (es->buffer == NULL)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500562 return -1;
563
564 if (!drm_surface_transform_supported(es))
565 return -1;
566
Jesse Barnes58ef3792012-02-23 09:45:49 -0500567 wl_list_for_each(s, &c->sprite_list, link) {
568 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
569 continue;
570
571 if (!s->pending_fb_id) {
572 found = 1;
573 break;
574 }
575 }
576
577 /* No sprites available */
578 if (!found)
579 return -1;
580
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400581 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
582 es->buffer, GBM_BO_USE_SCANOUT);
583 if (!bo)
584 return -1;
585
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586 format = gbm_bo_get_format(bo);
587 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400588 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589
590 gbm_bo_destroy(bo);
591
592 if (!drm_surface_format_supported(s, format))
593 return -1;
594
595 if (!handle)
596 return -1;
597
598 handles[0] = handle;
599 pitches[0] = stride;
600 offsets[0] = 0;
601
602 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
603 format, handles, pitches, offsets,
604 &fb_id, 0);
605 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200606 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500607 c->sprites_are_broken = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500608 return -1;
609 }
610
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611 s->pending_fb_id = fb_id;
612 s->pending_surface = es;
613 es->buffer->busy_count++;
614
615 /*
616 * Calculate the source & dest rects properly based on actual
617 * postion (note the caller has called weston_surface_update_transform()
618 * for us already).
619 */
620 pixman_region32_init(&dest_rect);
621 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
622 &output_base->region);
623 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
624 box = pixman_region32_extents(&dest_rect);
625 s->dest_x = box->x1;
626 s->dest_y = box->y1;
627 s->dest_w = box->x2 - box->x1;
628 s->dest_h = box->y2 - box->y1;
629 pixman_region32_fini(&dest_rect);
630
631 pixman_region32_init(&src_rect);
632 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
633 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400635
636 weston_surface_from_global_fixed(es,
637 wl_fixed_from_int(box->x1),
638 wl_fixed_from_int(box->y1),
639 &sx1, &sy1);
640 weston_surface_from_global_fixed(es,
641 wl_fixed_from_int(box->x2),
642 wl_fixed_from_int(box->y2),
643 &sx2, &sy2);
644
645 if (sx1 < 0)
646 sx1 = 0;
647 if (sy1 < 0)
648 sy1 = 0;
649 if (sx2 > wl_fixed_from_int(es->geometry.width))
650 sx2 = wl_fixed_from_int(es->geometry.width);
651 if (sy2 > wl_fixed_from_int(es->geometry.height))
652 sy2 = wl_fixed_from_int(es->geometry.height);
653
654 s->src_x = sx1 << 8;
655 s->src_y = sy1 << 8;
656 s->src_w = (sx2 - sx1) << 8;
657 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 pixman_region32_fini(&src_rect);
659
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400660 es->plane = WESTON_PLANE_DRM_PLANE;
661
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400662 wl_signal_add(&es->buffer->resource.destroy_signal,
663 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400664
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665 return 0;
666}
667
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500668static void
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400669drm_output_set_cursor(struct weston_output *output_base,
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400670 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500671{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400672 struct drm_output *output = (struct drm_output *) output_base;
673 struct drm_compositor *c =
674 (struct drm_compositor *) output->base.compositor;
675 EGLint handle, stride;
676 struct gbm_bo *bo;
677 uint32_t buf[64 * 64];
678 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400679 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500680
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400681 if (!output->cursor_free)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500682 return;
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400683 if (es->output_mask != (1u << output_base->id))
684 return;
685 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
686 es->geometry.width > 64 || es->geometry.height > 64)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400687 return;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500688
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400689 if (es->buffer && pixman_region32_not_empty(&es->damage)) {
690 output->current_cursor ^= 1;
691 bo = output->cursor_bo[output->current_cursor];
692 memset(buf, 0, sizeof buf);
693 stride = wl_shm_buffer_get_stride(es->buffer);
694 s = wl_shm_buffer_get_data(es->buffer);
695 for (i = 0; i < es->geometry.height; i++)
696 memcpy(buf + i * 64, s + i * stride,
697 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500698
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400699 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
700 return;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400701
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400702 handle = gbm_bo_get_handle(bo).s32;
703 if (drmModeSetCursor(c->drm.fd,
704 output->crtc_id, handle, 64, 64)) {
705 weston_log("failed to set cursor: %n\n");
706 return;
707 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400708 }
709
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400710 x = es->geometry.x - output->base.x;
711 y = es->geometry.y - output->base.y;
712 if (output->cursor_x != x || output->cursor_y != y) {
713 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
714 weston_log("failed to move cursor: %m\n");
715 return;
716 }
717 output->cursor_x = x;
718 output->cursor_y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400719 }
720
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400721 es->plane = WESTON_PLANE_DRM_CURSOR;
722 output->cursor_free = 0;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500723}
724
Jesse Barnes58ef3792012-02-23 09:45:49 -0500725static void
726drm_assign_planes(struct weston_output *output)
727{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400728 struct drm_compositor *c =
729 (struct drm_compositor *) output->compositor;
730 struct drm_output *drm_output = (struct drm_output *) output;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400731 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500732 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400733 int prev_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500734
735 /*
736 * Find a surface for each sprite in the output using some heuristics:
737 * 1) size
738 * 2) frequency of update
739 * 3) opacity (though some hw might support alpha blending)
740 * 4) clipping (this can be fixed with color keys)
741 *
742 * The idea is to save on blitting since this should save power.
743 * If we can get a large video surface on the sprite for example,
744 * the main display surface may not need to update at all, and
745 * the client buffer can be used directly for the sprite surface
746 * as we do for flipping full screen surfaces.
747 */
748 pixman_region32_init(&overlap);
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400749 drm_output->cursor_free = 1;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400750 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500751 pixman_region32_init(&surface_overlap);
752 pixman_region32_intersect(&surface_overlap, &overlap,
753 &es->transform.boundingbox);
754
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400755 prev_plane = es->plane;
756 es->plane = WESTON_PLANE_PRIMARY;
757 if (pixman_region32_not_empty(&surface_overlap))
758 goto bail;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500759
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400760 if (es->plane == WESTON_PLANE_PRIMARY)
761 drm_output_set_cursor(output, es);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400762 if (es->plane == WESTON_PLANE_PRIMARY)
763 drm_output_prepare_scanout_surface(output, es);
764 if (es->plane == WESTON_PLANE_PRIMARY)
765 drm_output_prepare_overlay_surface(output, es);
766
767 bail:
768 if (es->plane == WESTON_PLANE_PRIMARY)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769 pixman_region32_union(&overlap, &overlap,
770 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400771
772 if (prev_plane != WESTON_PLANE_PRIMARY &&
773 es->plane == WESTON_PLANE_PRIMARY)
774 weston_surface_damage(es);
775 else if (prev_plane == WESTON_PLANE_PRIMARY &&
776 es->plane != WESTON_PLANE_PRIMARY)
777 weston_surface_damage_below(es);
778
Jesse Barnes58ef3792012-02-23 09:45:49 -0500779 pixman_region32_fini(&surface_overlap);
780 }
781 pixman_region32_fini(&overlap);
782
Kristian Høgsberg4901f6c2012-07-14 01:24:58 -0400783 if (drm_output->cursor_free)
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400784 drmModeSetCursor(c->drm.fd, drm_output->crtc_id, 0, 0, 0);
Kristian Høgsbergf2735ea2012-06-20 23:03:53 -0400785
Jesse Barnes58ef3792012-02-23 09:45:49 -0500786 drm_disable_unused_sprites(output);
787}
788
Matt Roper361d2ad2011-08-29 13:52:23 -0700789static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500790drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700791{
792 struct drm_output *output = (struct drm_output *) output_base;
793 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200794 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700795 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700796
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200797 if (output->backlight)
798 backlight_destroy(output->backlight);
799
Matt Roper361d2ad2011-08-29 13:52:23 -0700800 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400801 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700802
803 /* Restore original CRTC state */
804 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200805 origcrtc->x, origcrtc->y,
806 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700807 drmModeFreeCrtc(origcrtc);
808
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200809 c->crtc_allocator &= ~(1 << output->crtc_id);
810 c->connector_allocator &= ~(1 << output->connector_id);
811
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400812 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400813 gbm_surface_destroy(output->surface);
814
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500815 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200816 wl_list_remove(&output->base.link);
817
Matt Roper361d2ad2011-08-29 13:52:23 -0700818 free(output);
819}
820
Alex Wub7b8bda2012-04-17 17:20:48 +0800821static struct drm_mode *
822choose_mode (struct drm_output *output, struct weston_mode *target_mode)
823{
824 struct drm_mode *tmp_mode = NULL, *mode;
825
826 if (output->base.current->width == target_mode->width &&
827 output->base.current->height == target_mode->height &&
828 (output->base.current->refresh == target_mode->refresh ||
829 target_mode->refresh == 0))
830 return (struct drm_mode *)output->base.current;
831
832 wl_list_for_each(mode, &output->base.mode_list, base.link) {
833 if (mode->mode_info.hdisplay == target_mode->width &&
834 mode->mode_info.vdisplay == target_mode->height) {
835 if (mode->mode_info.vrefresh == target_mode->refresh ||
836 target_mode->refresh == 0) {
837 return mode;
838 } else if (!tmp_mode)
839 tmp_mode = mode;
840 }
841 }
842
843 return tmp_mode;
844}
845
846static int
847drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
848{
849 struct drm_output *output;
850 struct drm_mode *drm_mode;
851 int ret;
852 struct drm_compositor *ec;
853 struct gbm_surface *surface;
854 EGLSurface egl_surface;
855
856 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200857 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800858 return -1;
859 }
860
861 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200862 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800863 return -1;
864 }
865
866 ec = (struct drm_compositor *)output_base->compositor;
867 output = (struct drm_output *)output_base;
868 drm_mode = choose_mode (output, mode);
869
870 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200871 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800872 return -1;
873 } else if (&drm_mode->base == output->base.current) {
874 return 0;
875 } else if (drm_mode->base.width == output->base.current->width &&
876 drm_mode->base.height == output->base.current->height) {
877 /* only change refresh value */
878 ret = drmModeSetCrtc(ec->drm.fd,
879 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300880 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800881 &output->connector_id, 1, &drm_mode->mode_info);
882
883 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200884 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800885 drm_mode->base.width,
886 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400887 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800888 ret = -1;
889 } else {
890 output->base.current->flags = 0;
891 output->base.current = &drm_mode->base;
892 drm_mode->base.flags =
893 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
894 ret = 0;
895 }
896
897 return ret;
898 }
899
900 drm_mode->base.flags =
901 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
902
903 surface = gbm_surface_create(ec->gbm,
904 drm_mode->base.width,
905 drm_mode->base.height,
906 GBM_FORMAT_XRGB8888,
907 GBM_BO_USE_SCANOUT |
908 GBM_BO_USE_RENDERING);
909 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200910 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800911 return -1;
912 }
913
914 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400915 eglCreateWindowSurface(ec->base.egl_display,
916 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800917 surface, NULL);
918
919 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200920 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800921 goto err;
922 }
923
924 ret = drmModeSetCrtc(ec->drm.fd,
925 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300926 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800927 &output->connector_id, 1, &drm_mode->mode_info);
928 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200929 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800930 goto err;
931 }
932
933 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300934 if (output->current) {
935 if (output->current->is_client_buffer)
936 gbm_bo_destroy(output->current->bo);
937 else
938 gbm_surface_release_buffer(output->surface,
939 output->current->bo);
940 }
941 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800942
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300943 if (output->next) {
944 if (output->next->is_client_buffer)
945 gbm_bo_destroy(output->next->bo);
946 else
947 gbm_surface_release_buffer(output->surface,
948 output->next->bo);
949 }
950 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800951
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400952 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800953 gbm_surface_destroy(output->surface);
954 output->egl_surface = egl_surface;
955 output->surface = surface;
956
957 /*update output*/
958 output->base.current = &drm_mode->base;
959 output->base.dirty = 1;
960 weston_output_move(&output->base, output->base.x, output->base.y);
961 return 0;
962
963err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400964 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800965 gbm_surface_destroy(surface);
966 return -1;
967}
968
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400969static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400970on_drm_input(int fd, uint32_t mask, void *data)
971{
972 drmEventContext evctx;
973
974 memset(&evctx, 0, sizeof evctx);
975 evctx.version = DRM_EVENT_CONTEXT_VERSION;
976 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500977 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400978 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -0400979
980 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400981}
982
983static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400984init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400985{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400986 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -0400987 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -0400988 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -0400989 static const EGLint context_attribs[] = {
990 EGL_CONTEXT_CLIENT_VERSION, 2,
991 EGL_NONE
992 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400993
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400994 static const EGLint config_attribs[] = {
995 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
996 EGL_RED_SIZE, 1,
997 EGL_GREEN_SIZE, 1,
998 EGL_BLUE_SIZE, 1,
999 EGL_ALPHA_SIZE, 0,
1000 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1001 EGL_NONE
1002 };
1003
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001004 sysnum = udev_device_get_sysnum(device);
1005 if (sysnum)
1006 ec->drm.id = atoi(sysnum);
1007 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001008 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001009 return -1;
1010 }
1011
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001012 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001013 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001014 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001015 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001016 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001017 udev_device_get_devnode(device));
1018 return -1;
1019 }
1020
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001021 weston_log("using %s\n", filename);
1022
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001023 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001024 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001025 ec->base.egl_display = eglGetDisplay(ec->gbm);
1026 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001027 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001028 return -1;
1029 }
1030
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001031 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001032 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001033 return -1;
1034 }
1035
Darxus55973f22010-11-22 21:24:39 -05001036 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001037 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001038 return -1;
1039 }
1040
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001041 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1042 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001043 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001044 return -1;
1045 }
1046
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001047 ec->base.egl_context =
1048 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1049 EGL_NO_CONTEXT, context_attribs);
1050 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001051 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001052 return -1;
1053 }
1054
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001055 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1056 GBM_FORMAT_XRGB8888,
1057 GBM_BO_USE_RENDERING);
1058 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001059 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001060 return -1;
1061 }
1062
1063 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001064 eglCreateWindowSurface(ec->base.egl_display,
1065 ec->base.egl_config,
1066 ec->dummy_surface,
1067 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001068 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001069 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001070 return -1;
1071 }
1072
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001073 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1074 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001075 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001076 return -1;
1077 }
1078
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001079 return 0;
1080}
1081
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001082static int
1083drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1084{
1085 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001086 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001087
1088 mode = malloc(sizeof *mode);
1089 if (mode == NULL)
1090 return -1;
1091
1092 mode->base.flags = 0;
1093 mode->base.width = info->hdisplay;
1094 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001095
1096 /* Calculate higher precision (mHz) refresh rate */
1097 refresh = (info->clock * 1000000LL / info->htotal +
1098 info->vtotal / 2) / info->vtotal;
1099
1100 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1101 refresh *= 2;
1102 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1103 refresh /= 2;
1104 if (info->vscan > 1)
1105 refresh /= info->vscan;
1106
1107 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001108 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001109
1110 if (info->type & DRM_MODE_TYPE_PREFERRED)
1111 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001113 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1114
1115 return 0;
1116}
1117
1118static int
1119drm_subpixel_to_wayland(int drm_value)
1120{
1121 switch (drm_value) {
1122 default:
1123 case DRM_MODE_SUBPIXEL_UNKNOWN:
1124 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1125 case DRM_MODE_SUBPIXEL_NONE:
1126 return WL_OUTPUT_SUBPIXEL_NONE;
1127 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1128 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1129 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1130 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1131 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1132 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1133 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1134 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1135 }
1136}
1137
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001138static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001139sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001140{
1141 struct drm_sprite *sprite =
1142 container_of(listener, struct drm_sprite,
1143 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001144 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001145
1146 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001147 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1148 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001149}
1150
1151static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001152sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001153{
1154 struct drm_sprite *sprite =
1155 container_of(listener, struct drm_sprite,
1156 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001157 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001158
1159 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001160 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1161 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001162}
1163
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001164/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001165static uint32_t
1166drm_get_backlight(struct drm_output *output)
1167{
1168 long brightness, max_brightness, norm;
1169
1170 brightness = backlight_get_brightness(output->backlight);
1171 max_brightness = backlight_get_max_brightness(output->backlight);
1172
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001173 /* convert it on a scale of 0 to 255 */
1174 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001175
1176 return (uint32_t) norm;
1177}
1178
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001179/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001180static void
1181drm_set_backlight(struct weston_output *output_base, uint32_t value)
1182{
1183 struct drm_output *output = (struct drm_output *) output_base;
1184 long max_brightness, new_brightness;
1185
1186 if (!output->backlight)
1187 return;
1188
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001189 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001190 return;
1191
1192 max_brightness = backlight_get_max_brightness(output->backlight);
1193
1194 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001195 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001196
1197 backlight_set_brightness(output->backlight, new_brightness);
1198}
1199
1200static drmModePropertyPtr
1201drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1202{
1203 drmModePropertyPtr props;
1204 int i;
1205
1206 for (i = 0; i < connector->count_props; i++) {
1207 props = drmModeGetProperty(fd, connector->props[i]);
1208 if (!props)
1209 continue;
1210
1211 if (!strcmp(props->name, name))
1212 return props;
1213
1214 drmModeFreeProperty(props);
1215 }
1216
1217 return NULL;
1218}
1219
1220static void
1221drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1222{
1223 struct drm_output *output = (struct drm_output *) output_base;
1224 struct weston_compositor *ec = output_base->compositor;
1225 struct drm_compositor *c = (struct drm_compositor *) ec;
1226 drmModeConnectorPtr connector;
1227 drmModePropertyPtr prop;
1228
1229 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1230 if (!connector)
1231 return;
1232
1233 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1234 if (!prop) {
1235 drmModeFreeConnector(connector);
1236 return;
1237 }
1238
1239 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1240 prop->prop_id, level);
1241 drmModeFreeProperty(prop);
1242 drmModeFreeConnector(connector);
1243}
1244
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001245static const char *connector_type_names[] = {
1246 "None",
1247 "VGA",
1248 "DVI",
1249 "DVI",
1250 "DVI",
1251 "Composite",
1252 "TV",
1253 "LVDS",
1254 "CTV",
1255 "DIN",
1256 "DP",
1257 "HDMI",
1258 "HDMI",
1259 "TV",
1260 "eDP",
1261};
1262
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001263static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001264create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001265 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001266 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001267 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001268{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001269 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001270 struct drm_mode *drm_mode, *next;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001271 struct weston_mode *m, *preferred, *current;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001272 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001273 drmModeModeInfo crtc_mode;
1274 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001275 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001276 char name[32];
1277 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001278
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001279 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001280 if (encoder == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001281 weston_log("No encoder for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001282 return -1;
1283 }
1284
1285 for (i = 0; i < resources->count_crtcs; i++) {
Marty Jack13d9db22011-02-09 19:01:42 -05001286 if (encoder->possible_crtcs & (1 << i) &&
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001287 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001288 break;
1289 }
1290 if (i == resources->count_crtcs) {
Martin Minarik6d118362012-06-07 18:01:59 +02001291 weston_log("No usable crtc for encoder.\n");
David Herrmanneb8bed52011-12-08 17:05:44 +01001292 drmModeFreeEncoder(encoder);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001293 return -1;
1294 }
1295
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001296 output = malloc(sizeof *output);
David Herrmanneb8bed52011-12-08 17:05:44 +01001297 if (output == NULL) {
1298 drmModeFreeEncoder(encoder);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001299 return -1;
David Herrmanneb8bed52011-12-08 17:05:44 +01001300 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001301
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001302 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001303 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1304 output->base.make = "unknown";
1305 output->base.model = "unknown";
1306 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001307
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001308 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1309 type_name = connector_type_names[connector->connector_type];
1310 else
1311 type_name = "UNKNOWN";
1312 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1313 output->name = strdup(name);
1314
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001315 output->crtc_id = resources->crtcs[i];
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001316 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001317 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001318 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001319
Matt Roper361d2ad2011-08-29 13:52:23 -07001320 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001321 drmModeFreeEncoder(encoder);
Matt Roper361d2ad2011-08-29 13:52:23 -07001322
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001323 /* Get the current mode on the crtc that's currently driving
1324 * this connector. */
1325 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
1326 if (encoder == NULL)
1327 goto err_free;
1328 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1329 drmModeFreeEncoder(encoder);
1330 if (crtc == NULL)
1331 goto err_free;
1332 crtc_mode = crtc->mode;
1333 drmModeFreeCrtc(crtc);
1334
David Herrmann0f0d54e2011-12-08 17:05:45 +01001335 for (i = 0; i < connector->count_modes; i++) {
1336 ret = drm_output_add_mode(output, &connector->modes[i]);
1337 if (ret)
1338 goto err_free;
1339 }
1340
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001341 preferred = NULL;
1342 current = NULL;
1343 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
1344 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode)) {
1345 drm_mode->base.flags |= WL_OUTPUT_MODE_CURRENT;
1346 current = &drm_mode->base;
1347 }
1348 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1349 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001350 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001351
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001352 if (current == NULL) {
1353 ret = drm_output_add_mode(output, &crtc_mode);
1354 if (ret)
1355 goto err_free;
1356 current = container_of(output->base.mode_list.prev,
1357 struct weston_mode, link);
1358 current->flags |= WL_OUTPUT_MODE_CURRENT;
1359 }
1360
1361 if (preferred == NULL)
1362 preferred = current;
1363
1364 if (option_current_mode) {
1365 output->base.current = current;
1366 } else {
1367 output->base.current = preferred;
1368 current->flags &= ~WL_OUTPUT_MODE_CURRENT;
1369 preferred->flags |= WL_OUTPUT_MODE_CURRENT;
1370 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001371
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001372 output->surface = gbm_surface_create(ec->gbm,
1373 output->base.current->width,
1374 output->base.current->height,
1375 GBM_FORMAT_XRGB8888,
1376 GBM_BO_USE_SCANOUT |
1377 GBM_BO_USE_RENDERING);
1378 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001379 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001380 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001381 }
1382
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001383 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001384 eglCreateWindowSurface(ec->base.egl_display,
1385 ec->base.egl_config,
1386 output->surface,
1387 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001388 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001389 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001390 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001391 }
1392
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001393 output->cursor_bo[0] =
1394 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1395 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1396 output->cursor_bo[1] =
1397 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1398 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1399
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001400 output->backlight = backlight_init(drm_device,
1401 connector->connector_type);
1402 if (output->backlight) {
1403 output->base.set_backlight = drm_set_backlight;
1404 output->base.backlight_current = drm_get_backlight(output);
1405 }
1406
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001407 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001408 connector->mmWidth, connector->mmHeight,
1409 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001410
1411 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1412
Alex Wubd3354b2012-04-17 17:20:49 +08001413 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001414 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001415 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001416 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001417 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001418 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001419
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001420 weston_log("Output %s, (connector %d, crtc %d)\n",
1421 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001422 wl_list_for_each(m, &output->base.mode_list, link)
1423 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1424 m->width, m->height, m->refresh / 1000.0,
1425 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1426 ", preferred" : "",
1427 m->flags & WL_OUTPUT_MODE_CURRENT ?
1428 ", current" : "",
1429 connector->count_modes == 0 ?
1430 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001431
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001432 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001433
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001434err_surface:
1435 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001436err_free:
1437 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1438 base.link) {
1439 wl_list_remove(&drm_mode->base.link);
1440 free(drm_mode);
1441 }
1442
1443 drmModeFreeCrtc(output->original_crtc);
1444 ec->crtc_allocator &= ~(1 << output->crtc_id);
1445 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001446 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001447
David Herrmann0f0d54e2011-12-08 17:05:45 +01001448 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001449}
1450
Jesse Barnes58ef3792012-02-23 09:45:49 -05001451static void
1452create_sprites(struct drm_compositor *ec)
1453{
1454 struct drm_sprite *sprite;
1455 drmModePlaneRes *plane_res;
1456 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001457 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001458
1459 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1460 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001461 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001462 strerror(errno));
1463 return;
1464 }
1465
1466 for (i = 0; i < plane_res->count_planes; i++) {
1467 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1468 if (!plane)
1469 continue;
1470
1471 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1472 plane->count_formats));
1473 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001474 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001475 __func__);
1476 free(plane);
1477 continue;
1478 }
1479
1480 memset(sprite, 0, sizeof *sprite);
1481
1482 sprite->possible_crtcs = plane->possible_crtcs;
1483 sprite->plane_id = plane->plane_id;
1484 sprite->surface = NULL;
1485 sprite->pending_surface = NULL;
1486 sprite->fb_id = 0;
1487 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001488 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1489 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001490 sprite_handle_pending_buffer_destroy;
1491 sprite->compositor = ec;
1492 sprite->count_formats = plane->count_formats;
1493 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001494 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001495 drmModeFreePlane(plane);
1496
1497 wl_list_insert(&ec->sprite_list, &sprite->link);
1498 }
1499
1500 free(plane_res->planes);
1501 free(plane_res);
1502}
1503
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001504static void
1505destroy_sprites(struct drm_compositor *compositor)
1506{
1507 struct drm_sprite *sprite, *next;
1508 struct drm_output *output;
1509
1510 output = container_of(compositor->base.output_list.next,
1511 struct drm_output, base.link);
1512
1513 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1514 drmModeSetPlane(compositor->drm.fd,
1515 sprite->plane_id,
1516 output->crtc_id, 0, 0,
1517 0, 0, 0, 0, 0, 0, 0, 0);
1518 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1519 free(sprite);
1520 }
1521}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001522
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001523static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001524create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001525 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001526{
1527 drmModeConnector *connector;
1528 drmModeRes *resources;
1529 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001530 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001531
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001532 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001533 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001534 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001535 return -1;
1536 }
1537
Jesse Barnes58ef3792012-02-23 09:45:49 -05001538 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001539 if (!ec->crtcs) {
1540 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001541 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001542 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001543
1544 ec->num_crtcs = resources->count_crtcs;
1545 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1546
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001547 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001548 connector = drmModeGetConnector(ec->drm.fd,
1549 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001550 if (connector == NULL)
1551 continue;
1552
1553 if (connector->connection == DRM_MODE_CONNECTED &&
1554 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001555 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001556 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001557 connector, x, y,
1558 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001559 drmModeFreeConnector(connector);
1560 continue;
1561 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001562
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001563 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001564 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001565 link)->current->width;
1566 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001567
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001568 drmModeFreeConnector(connector);
1569 }
1570
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001571 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001572 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001573 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001574 return -1;
1575 }
1576
1577 drmModeFreeResources(resources);
1578
1579 return 0;
1580}
1581
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001582static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001583update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001584{
1585 drmModeConnector *connector;
1586 drmModeRes *resources;
1587 struct drm_output *output, *next;
1588 int x = 0, y = 0;
1589 int x_offset = 0, y_offset = 0;
1590 uint32_t connected = 0, disconnects = 0;
1591 int i;
1592
1593 resources = drmModeGetResources(ec->drm.fd);
1594 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001595 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001596 return;
1597 }
1598
1599 /* collect new connects */
1600 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001601 int connector_id = resources->connectors[i];
1602
1603 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001604 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001605 continue;
1606
David Herrmann7551cff2011-12-08 17:05:43 +01001607 if (connector->connection != DRM_MODE_CONNECTED) {
1608 drmModeFreeConnector(connector);
1609 continue;
1610 }
1611
Benjamin Franzke117483d2011-08-30 11:38:26 +02001612 connected |= (1 << connector_id);
1613
1614 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001615 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001616 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001617 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001618
1619 /* XXX: not yet needed, we die with 0 outputs */
1620 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001621 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001622 else
1623 x = 0;
1624 y = 0;
1625 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001626 connector, x, y,
1627 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001628 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001629
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001630 }
1631 drmModeFreeConnector(connector);
1632 }
1633 drmModeFreeResources(resources);
1634
1635 disconnects = ec->connector_allocator & ~connected;
1636 if (disconnects) {
1637 wl_list_for_each_safe(output, next, &ec->base.output_list,
1638 base.link) {
1639 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001640 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001641 output->base.x - x_offset,
1642 output->base.y - y_offset);
1643 }
1644
1645 if (disconnects & (1 << output->connector_id)) {
1646 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001647 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001648 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001649 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001650 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001651 }
1652 }
1653 }
1654
1655 /* FIXME: handle zero outputs, without terminating */
1656 if (ec->connector_allocator == 0)
1657 wl_display_terminate(ec->base.wl_display);
1658}
1659
1660static int
David Herrmannd7488c22012-03-11 20:05:21 +01001661udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001662{
David Herrmannd7488c22012-03-11 20:05:21 +01001663 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001664 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001665
1666 sysnum = udev_device_get_sysnum(device);
1667 if (!sysnum || atoi(sysnum) != ec->drm.id)
1668 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001669
David Herrmann6ac52db2012-03-11 20:05:22 +01001670 val = udev_device_get_property_value(device, "HOTPLUG");
1671 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001672 return 0;
1673
David Herrmann6ac52db2012-03-11 20:05:22 +01001674 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001675}
1676
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001677static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678udev_drm_event(int fd, uint32_t mask, void *data)
1679{
1680 struct drm_compositor *ec = data;
1681 struct udev_device *event;
1682
1683 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001684
David Herrmannd7488c22012-03-11 20:05:21 +01001685 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001686 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001687
1688 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001689
1690 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001691}
1692
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001693static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001694drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001695{
1696 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01001697 struct weston_seat *seat, *next;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001698
Daniel Stone37816df2012-05-16 18:45:18 +01001699 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
1700 evdev_input_destroy(seat);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001701
1702 wl_event_source_remove(d->udev_drm_source);
1703 wl_event_source_remove(d->drm_source);
1704
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001705 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02001706
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001707 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001708 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001709 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001710 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03001711 eglReleaseThread();
1712
Matt Roper361d2ad2011-08-29 13:52:23 -07001713 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001714 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001715 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001716 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001717 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001718
Kristian Høgsberge4762a62011-01-14 14:59:13 -05001719 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001720}
1721
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001722static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001723drm_compositor_set_modes(struct drm_compositor *compositor)
1724{
1725 struct drm_output *output;
1726 struct drm_mode *drm_mode;
1727 int ret;
1728
1729 wl_list_for_each(output, &compositor->base.output_list, base.link) {
1730 drm_mode = (struct drm_mode *) output->base.current;
1731 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001732 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001733 &output->connector_id, 1,
1734 &drm_mode->mode_info);
1735 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001736 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001737 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001738 drm_mode->base.width, drm_mode->base.height,
1739 output->base.x, output->base.y);
1740 }
1741 }
1742}
1743
1744static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001745vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001746{
1747 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01001748 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001749 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001750 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001751
1752 switch (event) {
1753 case TTY_ENTER_VT:
1754 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001755 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001756 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001757 wl_display_terminate(compositor->wl_display);
1758 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001759 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05001760 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001761 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01001762 wl_list_for_each(seat, &compositor->seat_list, link) {
1763 evdev_add_devices(ec->udev, seat);
1764 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02001765 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001766 break;
1767 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01001768 wl_list_for_each(seat, &compositor->seat_list, link) {
1769 evdev_disable_udev_monitor(seat);
1770 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04001771 }
1772
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001773 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001774 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001775 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04001776
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001777 /* If we have a repaint scheduled (either from a
1778 * pending pageflip or the idle handler), make sure we
1779 * cancel that so we don't try to pageflip when we're
1780 * vt switched away. The SLEEPING state will prevent
1781 * further attemps at repainting. When we switch
1782 * back, we schedule a repaint, which will process
1783 * pending frame callbacks. */
1784
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001785 wl_list_for_each(output, &ec->base.output_list, base.link) {
1786 output->base.repaint_needed = 0;
1787 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05001788 }
1789
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001790 output = container_of(ec->base.output_list.next,
1791 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001792
1793 wl_list_for_each(sprite, &ec->sprite_list, link)
1794 drmModeSetPlane(ec->drm.fd,
1795 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001796 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001797 0, 0, 0, 0, 0, 0, 0, 0);
1798
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001799 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02001800 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05001801
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04001802 break;
1803 };
1804}
1805
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001806static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01001807switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001808{
1809 struct drm_compositor *ec = data;
1810
Daniel Stone325fc2d2012-05-30 16:31:58 +01001811 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001812}
1813
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001814static const char default_seat[] = "seat0";
1815
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001816static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001817drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04001818 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04001819 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001820{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001821 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001822 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001823 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001824 struct udev_device *device, *drm_device;
1825 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001826 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001827 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001828 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001829
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001830 weston_log("initializing drm backend\n");
1831
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001832 ec = malloc(sizeof *ec);
1833 if (ec == NULL)
1834 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001835 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01001836
1837 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01001838 config_file) < 0) {
1839 weston_log("weston_compositor_init failed\n");
1840 goto err_base;
1841 }
Daniel Stone725c2c32012-06-22 14:04:36 +01001842
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001843 ec->udev = udev_new();
1844 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001845 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001846 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001847 }
1848
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001849 ec->base.wl_display = display;
1850 ec->tty = tty_create(&ec->base, vt_func, tty);
1851 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02001852 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001853 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05001854 }
1855
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001856 e = udev_enumerate_new(ec->udev);
1857 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02001858 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001859
Benjamin Franzke117483d2011-08-30 11:38:26 +02001860 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001861 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001862 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001863 path = udev_list_entry_get_name(entry);
1864 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001865 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001866 udev_device_get_property_value(device, "ID_SEAT");
1867 if (!device_seat)
1868 device_seat = default_seat;
1869 if (strcmp(device_seat, seat) == 0) {
1870 drm_device = device;
1871 break;
1872 }
1873 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001874 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001875
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001876 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001877 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001878 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001879 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001880
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04001881 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001882 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001883 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001884 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001885
1886 ec->base.destroy = drm_destroy;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02001887
Kristian Høgsberg8525a502011-01-14 16:20:21 -05001888 ec->base.focus = 1;
1889
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001890 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02001891
Daniel Stone725c2c32012-06-22 14:04:36 +01001892 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01001893 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02001894
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001895 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01001896 weston_compositor_add_key_binding(&ec->base, key,
1897 MODIFIER_CTRL | MODIFIER_ALT,
1898 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04001899
Jesse Barnes58ef3792012-02-23 09:45:49 -05001900 wl_list_init(&ec->sprite_list);
1901 create_sprites(ec);
1902
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001903 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001904 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01001905 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001906 }
1907
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02001908 path = NULL;
1909
Tiago Vignattice03ec32011-12-19 01:14:03 +02001910 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001911
1912 loop = wl_display_get_event_loop(ec->base.wl_display);
1913 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001914 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001915 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001916
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001917 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
1918 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001919 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001920 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001921 }
1922 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
1923 "drm", NULL);
1924 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001925 wl_event_loop_add_fd(loop,
1926 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001927 WL_EVENT_READABLE, udev_drm_event, ec);
1928
1929 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001930 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01001931 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001932 }
1933
Daniel Stonea96b93c2012-06-22 14:04:37 +01001934 udev_device_unref(drm_device);
1935 udev_enumerate_unref(e);
1936
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001937 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01001938
1939err_udev_monitor:
1940 wl_event_source_remove(ec->udev_drm_source);
1941 udev_monitor_unref(ec->udev_monitor);
1942err_drm_source:
1943 wl_event_source_remove(ec->drm_source);
1944 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
1945 evdev_input_destroy(weston_seat);
1946err_sprite:
1947 destroy_sprites(ec);
1948err_egl:
1949 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
1950 EGL_NO_CONTEXT);
1951 eglTerminate(ec->base.egl_display);
1952 eglReleaseThread();
1953 gbm_device_destroy(ec->gbm);
1954err_udev_dev:
1955 udev_device_unref(drm_device);
1956err_udev_enum:
1957 udev_enumerate_unref(e);
1958 tty_destroy(ec->tty);
1959err_udev:
1960 udev_unref(ec->udev);
1961err_compositor:
1962 weston_compositor_shutdown(&ec->base);
1963err_base:
1964 free(ec);
1965 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001966}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001967
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001968WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04001969backend_init(struct wl_display *display, int argc, char *argv[],
1970 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001971{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001972 int connector = 0, tty = 0;
1973 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001974
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001975 const struct weston_option drm_options[] = {
1976 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
1977 { WESTON_OPTION_STRING, "seat", 0, &seat },
1978 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001979 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001980 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02001981
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04001982 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001983
Daniel Stonec1be8e52012-06-01 11:14:02 -04001984 return drm_compositor_create(display, connector, seat, tty, argc, argv,
1985 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04001986}