blob: 8c8c8c0e822de9fec01275fc119fae0bced23e19 [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>
Pekka Paalanen33156972012-08-03 13:30:30 -040040#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020041
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040042#include "compositor.h"
Tiago Vignattice03ec32011-12-19 01:14:03 +020043#include "evdev.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010044#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040045
Kristian Høgsberg061c4252012-06-28 11:28:15 -040046static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060047static char *output_name;
48static char *output_mode;
49static struct wl_list configured_output_list;
50
51enum output_config {
52 OUTPUT_CONFIG_INVALID = 0,
53 OUTPUT_CONFIG_OFF,
54 OUTPUT_CONFIG_PREFERRED,
55 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060056 OUTPUT_CONFIG_MODE,
57 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060058};
59
60struct drm_configured_output {
61 char *name;
62 char *mode;
63 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060064 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065 enum output_config config;
66 struct wl_list link;
67};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040068
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050070 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
72 struct udev *udev;
73 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010075 struct udev_monitor *udev_monitor;
76 struct wl_event_source *udev_drm_source;
77
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010079 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 int fd;
81 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020082 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050083 uint32_t *crtcs;
84 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050085 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010086 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050087 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020088
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040089 struct gbm_surface *dummy_surface;
90 EGLSurface dummy_egl_surface;
91
Rob Clark4339add2012-08-09 14:18:28 -050092 /* we need these parameters in order to not fail drmModeAddFB2()
93 * due to out of bounds dimensions, and then mistakenly set
94 * sprites_are_broken:
95 */
Kristian Høgsberg8a015802012-08-09 17:19:23 -040096 int32_t min_width, max_width;
97 int32_t min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -050098
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101
Rob Clarkab5b1e32012-08-09 13:24:45 -0500102 int cursors_are_broken;
103
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200104 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400105};
106
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400107struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500108 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109 drmModeModeInfo mode_info;
110};
111
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300112struct drm_output;
113
114struct drm_fb {
115 struct gbm_bo *bo;
116 struct drm_output *output;
117 uint32_t fb_id;
118 int is_client_buffer;
119 struct wl_buffer *buffer;
120 struct wl_listener buffer_destroy_listener;
121};
122
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400123struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500124 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400126 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400127 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500128 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400129 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700130 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200131
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300132 int vblank_pending;
133 int page_flip_pending;
134
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400135 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400136 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400137 struct weston_plane cursor_plane;
138 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400139 struct weston_surface *cursor_surface;
140 int current_cursor;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400141 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300142 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200143 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144};
145
Jesse Barnes58ef3792012-02-23 09:45:49 -0500146/*
147 * An output has a primary display plane plus zero or more sprites for
148 * blending display contents.
149 */
150struct drm_sprite {
151 struct wl_list link;
152
153 uint32_t fb_id;
154 uint32_t pending_fb_id;
155 struct weston_surface *surface;
156 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400157 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500158
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300159 struct drm_output *output;
160
Jesse Barnes58ef3792012-02-23 09:45:49 -0500161 struct drm_compositor *compositor;
162
163 struct wl_listener destroy_listener;
164 struct wl_listener pending_destroy_listener;
165
166 uint32_t possible_crtcs;
167 uint32_t plane_id;
168 uint32_t count_formats;
169
170 int32_t src_x, src_y;
171 uint32_t src_w, src_h;
172 uint32_t dest_x, dest_y;
173 uint32_t dest_w, dest_h;
174
175 uint32_t formats[];
176};
177
Pekka Paalanen33156972012-08-03 13:30:30 -0400178struct drm_seat {
179 struct weston_seat base;
180 struct wl_list devices_list;
181 struct udev_monitor *udev_monitor;
182 struct wl_event_source *udev_monitor_source;
183 char *seat_id;
184};
185
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400186static void
187drm_output_set_cursor(struct drm_output *output);
188static void
189drm_disable_unused_sprites(struct weston_output *output_base);
190
Jesse Barnes58ef3792012-02-23 09:45:49 -0500191static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500192drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
193{
194 struct weston_compositor *ec = output_base->compositor;
195 struct drm_compositor *c =(struct drm_compositor *) ec;
196 struct drm_output *output = (struct drm_output *) output_base;
197 int crtc;
198
199 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
200 if (c->crtcs[crtc] != output->crtc_id)
201 continue;
202
203 if (supported & (1 << crtc))
204 return -1;
205 }
206
207 return 0;
208}
209
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300210static void
211drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
212{
213 struct drm_fb *fb = data;
214 struct gbm_device *gbm = gbm_bo_get_device(bo);
215
216 if (fb->fb_id)
217 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
218
219 if (fb->buffer) {
220 weston_buffer_post_release(fb->buffer);
221 wl_list_remove(&fb->buffer_destroy_listener.link);
222 }
223
224 free(data);
225}
226
227static struct drm_fb *
228drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
229{
230 struct drm_fb *fb = gbm_bo_get_user_data(bo);
231 struct drm_compositor *compositor =
232 (struct drm_compositor *) output->base.compositor;
233 uint32_t width, height, stride, handle;
234 int ret;
235
236 if (fb)
237 return fb;
238
239 fb = malloc(sizeof *fb);
240
241 fb->bo = bo;
242 fb->output = output;
243 fb->is_client_buffer = 0;
244 fb->buffer = NULL;
245
246 width = gbm_bo_get_width(bo);
247 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400248 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300249 handle = gbm_bo_get_handle(bo).u32;
250
251 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
252 stride, handle, &fb->fb_id);
253 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200254 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300255 free(fb);
256 return NULL;
257 }
258
259 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
260
261 return fb;
262}
263
264static void
265fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
266{
267 struct drm_fb *fb = container_of(listener, struct drm_fb,
268 buffer_destroy_listener);
269
270 fb->buffer = NULL;
271
272 if (fb == fb->output->next ||
273 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400274 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300275}
276
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400277static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400278drm_output_prepare_scanout_surface(struct weston_output *_output,
279 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500280{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400281 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500282 struct drm_compositor *c =
283 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300284 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500285
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500286 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200287 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200288 es->geometry.width != output->base.current->width ||
289 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200290 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400291 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400292 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500293
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400294 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
295 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500296
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300297 /* Need to verify output->region contained in surface opaque
298 * region. Or maybe just that format doesn't have alpha.
299 * For now, scanout only if format is XRGB8888. */
300 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
301 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400302 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300303 }
304
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300305 output->next = drm_fb_get_from_bo(bo, output);
306 if (!output->next) {
307 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400308 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300309 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500310
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300311 output->next->is_client_buffer = 1;
312 output->next->buffer = es->buffer;
313 output->next->buffer->busy_count++;
314 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
315
316 wl_signal_add(&output->next->buffer->resource.destroy_signal,
317 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500318
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400319 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500320}
321
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500322static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400323drm_output_render(struct drm_output *output, pixman_region32_t *damage)
324{
325 struct drm_compositor *compositor =
326 (struct drm_compositor *) output->base.compositor;
327 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300328 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400329
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400330 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
331 output->egl_surface,
332 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200333 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400334 return;
335 }
336
337 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400338 if (surface->plane == &compositor->base.primary_plane)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400339 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400340
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400341 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600342
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400343 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300344 bo = gbm_surface_lock_front_buffer(output->surface);
345 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200346 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400347 return;
348 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300349
350 output->next = drm_fb_get_from_bo(bo, output);
351 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200352 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300353 gbm_surface_release_buffer(output->surface, bo);
354 return;
355 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400356}
357
358static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500359drm_output_repaint(struct weston_output *output_base,
360 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100361{
362 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500363 struct drm_compositor *compositor =
364 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500365 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400366 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500367 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100368
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300369 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400370 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300371 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400372 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100373
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400374 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300375 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400376 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400378 &output->connector_id, 1,
379 &mode->mode_info);
380 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200381 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400382 return;
383 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200384 }
385
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500386 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300387 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500388 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200389 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500390 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500391 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100392
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300393 output->page_flip_pending = 1;
394
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400395 drm_output_set_cursor(output);
396
Jesse Barnes58ef3792012-02-23 09:45:49 -0500397 /*
398 * Now, update all the sprite surfaces
399 */
400 wl_list_for_each(s, &compositor->sprite_list, link) {
401 uint32_t flags = 0;
402 drmVBlank vbl = {
403 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
404 .request.sequence = 1,
405 };
406
407 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
408 continue;
409
410 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
411 output->crtc_id, s->pending_fb_id, flags,
412 s->dest_x, s->dest_y,
413 s->dest_w, s->dest_h,
414 s->src_x, s->src_y,
415 s->src_w, s->src_h);
416 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200417 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500418 ret, strerror(errno));
419
Rob Clark5ca1a472012-08-08 20:27:37 -0500420 if (output->pipe > 0)
421 vbl.request.type |= DRM_VBLANK_SECONDARY;
422
Jesse Barnes58ef3792012-02-23 09:45:49 -0500423 /*
424 * Queue a vblank signal so we know when the surface
425 * becomes active on the display or has been replaced.
426 */
427 vbl.request.signal = (unsigned long)s;
428 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
429 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200430 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431 ret, strerror(errno));
432 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300433
434 s->output = output;
435 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500436 }
437
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400438 drm_disable_unused_sprites(&output->base);
439
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500440 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400441}
442
443static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500444vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
445 void *data)
446{
447 struct drm_sprite *s = (struct drm_sprite *)data;
448 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300449 struct drm_output *output = s->output;
450 uint32_t msecs;
451
452 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500453
454 if (s->surface) {
455 weston_buffer_post_release(s->surface->buffer);
456 wl_list_remove(&s->destroy_listener.link);
457 s->surface = NULL;
458 drmModeRmFB(c->drm.fd, s->fb_id);
459 s->fb_id = 0;
460 }
461
462 if (s->pending_surface) {
463 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400464 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
465 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500466 s->surface = s->pending_surface;
467 s->pending_surface = NULL;
468 s->fb_id = s->pending_fb_id;
469 s->pending_fb_id = 0;
470 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300471
472 if (!output->page_flip_pending) {
473 msecs = sec * 1000 + usec / 1000;
474 weston_output_finish_frame(&output->base, msecs);
475 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500476}
477
478static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400479page_flip_handler(int fd, unsigned int frame,
480 unsigned int sec, unsigned int usec, void *data)
481{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200482 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400483 uint32_t msecs;
484
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300485 output->page_flip_pending = 0;
486
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300487 if (output->current) {
488 if (output->current->is_client_buffer)
489 gbm_bo_destroy(output->current->bo);
490 else
491 gbm_surface_release_buffer(output->surface,
492 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200493 }
494
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300495 output->current = output->next;
496 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400497
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300498 if (!output->vblank_pending) {
499 msecs = sec * 1000 + usec / 1000;
500 weston_output_finish_frame(&output->base, msecs);
501 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200502}
503
504static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500505drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
506{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400507 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500508
509 for (i = 0; i < s->count_formats; i++)
510 if (s->formats[i] == format)
511 return 1;
512
513 return 0;
514}
515
516static int
517drm_surface_transform_supported(struct weston_surface *es)
518{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400519 struct weston_matrix *matrix = &es->transform.matrix;
520 int i;
521
522 if (!es->transform.enabled)
523 return 1;
524
525 for (i = 0; i < 16; i++) {
526 switch (i) {
527 case 10:
528 case 15:
529 if (matrix->d[i] != 1.0)
530 return 0;
531 break;
532 case 0:
533 case 5:
534 case 12:
535 case 13:
536 break;
537 default:
538 if (matrix->d[i] != 0.0)
539 return 0;
540 break;
541 }
542 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500543
544 return 1;
545}
546
Jesse Barnes58ef3792012-02-23 09:45:49 -0500547static void
548drm_disable_unused_sprites(struct weston_output *output_base)
549{
550 struct weston_compositor *ec = output_base->compositor;
551 struct drm_compositor *c =(struct drm_compositor *) ec;
552 struct drm_output *output = (struct drm_output *) output_base;
553 struct drm_sprite *s;
554 int ret;
555
556 wl_list_for_each(s, &c->sprite_list, link) {
557 if (s->pending_fb_id)
558 continue;
559
560 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
561 output->crtc_id, 0, 0,
562 0, 0, 0, 0, 0, 0, 0, 0);
563 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200564 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500565 ret, strerror(errno));
566 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300567
568 if (s->surface) {
569 s->surface = NULL;
570 wl_list_remove(&s->destroy_listener.link);
571 }
572
573 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574 s->fb_id = 0;
575 s->pending_fb_id = 0;
576 }
577}
578
579/*
580 * This function must take care to damage any previously assigned surface
581 * if the sprite ends up binding to a different surface than in the
582 * previous frame.
583 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400584static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500585drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400586 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500587{
588 struct weston_compositor *ec = output_base->compositor;
589 struct drm_compositor *c =(struct drm_compositor *) ec;
590 struct drm_sprite *s;
591 int found = 0;
592 EGLint handle, stride;
593 struct gbm_bo *bo;
594 uint32_t fb_id = 0;
595 uint32_t handles[4], pitches[4], offsets[4];
596 int ret = 0;
597 pixman_region32_t dest_rect, src_rect;
598 pixman_box32_t *box;
599 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400600 wl_fixed_t sx1, sy1, sx2, sy2;
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400601 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500603 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400604 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500605
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300606 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400607 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300608
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400609 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400610 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611
Rob Clark702ffae2012-08-09 14:18:27 -0500612 if (wl_buffer_is_shm(es->buffer))
613 return NULL;
614
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400616 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500617
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 wl_list_for_each(s, &c->sprite_list, link) {
619 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
620 continue;
621
622 if (!s->pending_fb_id) {
623 found = 1;
624 break;
625 }
626 }
627
628 /* No sprites available */
629 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400630 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500631
Rob Clark4339add2012-08-09 14:18:28 -0500632 width = es->geometry.width;
633 height = es->geometry.height;
634
635 /* If geometry is out of bounds, don't even bother trying because
636 * we know the AddFB2() call will fail:
637 */
638 if (c->min_width > width || width > c->max_width ||
639 c->min_height > height || height > c->max_height)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400640 return NULL;
Rob Clark4339add2012-08-09 14:18:28 -0500641
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400642 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
643 es->buffer, GBM_BO_USE_SCANOUT);
644 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400645 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400646
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 format = gbm_bo_get_format(bo);
648 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400649 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500650
651 gbm_bo_destroy(bo);
652
653 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400654 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500655
656 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400657 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658
659 handles[0] = handle;
660 pitches[0] = stride;
661 offsets[0] = 0;
662
Rob Clark4339add2012-08-09 14:18:28 -0500663 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500664 format, handles, pitches, offsets,
665 &fb_id, 0);
666 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200667 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500668 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400669 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500670 }
671
Jesse Barnes58ef3792012-02-23 09:45:49 -0500672 s->pending_fb_id = fb_id;
673 s->pending_surface = es;
674 es->buffer->busy_count++;
675
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400676 box = pixman_region32_extents(&es->transform.boundingbox);
677 s->plane.x = box->x1;
678 s->plane.y = box->y1;
679
Jesse Barnes58ef3792012-02-23 09:45:49 -0500680 /*
681 * Calculate the source & dest rects properly based on actual
682 * postion (note the caller has called weston_surface_update_transform()
683 * for us already).
684 */
685 pixman_region32_init(&dest_rect);
686 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
687 &output_base->region);
688 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
689 box = pixman_region32_extents(&dest_rect);
690 s->dest_x = box->x1;
691 s->dest_y = box->y1;
692 s->dest_w = box->x2 - box->x1;
693 s->dest_h = box->y2 - box->y1;
694 pixman_region32_fini(&dest_rect);
695
696 pixman_region32_init(&src_rect);
697 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
698 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500699 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400700
701 weston_surface_from_global_fixed(es,
702 wl_fixed_from_int(box->x1),
703 wl_fixed_from_int(box->y1),
704 &sx1, &sy1);
705 weston_surface_from_global_fixed(es,
706 wl_fixed_from_int(box->x2),
707 wl_fixed_from_int(box->y2),
708 &sx2, &sy2);
709
710 if (sx1 < 0)
711 sx1 = 0;
712 if (sy1 < 0)
713 sy1 = 0;
714 if (sx2 > wl_fixed_from_int(es->geometry.width))
715 sx2 = wl_fixed_from_int(es->geometry.width);
716 if (sy2 > wl_fixed_from_int(es->geometry.height))
717 sy2 = wl_fixed_from_int(es->geometry.height);
718
719 s->src_x = sx1 << 8;
720 s->src_y = sy1 << 8;
721 s->src_w = (sx2 - sx1) << 8;
722 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500723 pixman_region32_fini(&src_rect);
724
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400725 wl_signal_add(&es->buffer->resource.destroy_signal,
726 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400727
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400728 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500729}
730
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400731static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400732drm_output_prepare_cursor_surface(struct weston_output *output_base,
733 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500734{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400735 struct drm_compositor *c =
736 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400737 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400738
739 if (output->cursor_surface)
740 return NULL;
741 if (es->output_mask != (1u << output_base->id))
742 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500743 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400744 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400745 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
746 es->geometry.width > 64 || es->geometry.height > 64)
747 return NULL;
748
749 output->cursor_surface = es;
750
751 return &output->cursor_plane;
752}
753
754static void
755drm_output_set_cursor(struct drm_output *output)
756{
757 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400758 struct drm_compositor *c =
759 (struct drm_compositor *) output->base.compositor;
760 EGLint handle, stride;
761 struct gbm_bo *bo;
762 uint32_t buf[64 * 64];
763 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400764 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500765
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400766 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400767 if (es == NULL) {
768 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
769 return;
770 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500771
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400772 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
773 pixman_region32_fini(&output->cursor_plane.damage);
774 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400775 output->current_cursor ^= 1;
776 bo = output->cursor_bo[output->current_cursor];
777 memset(buf, 0, sizeof buf);
778 stride = wl_shm_buffer_get_stride(es->buffer);
779 s = wl_shm_buffer_get_data(es->buffer);
780 for (i = 0; i < es->geometry.height; i++)
781 memcpy(buf + i * 64, s + i * stride,
782 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500783
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400784 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300785 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400786
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400787 handle = gbm_bo_get_handle(bo).s32;
788 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500789 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300790 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500791 c->cursors_are_broken = 1;
792 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400793 }
794
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400795 x = es->geometry.x - output->base.x;
796 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400797 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500798 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400799 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500800 c->cursors_are_broken = 1;
801 }
802
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400803 output->cursor_plane.x = x;
804 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400805 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500806}
807
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808static void
809drm_assign_planes(struct weston_output *output)
810{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400811 struct drm_compositor *c =
812 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400813 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400815 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816
817 /*
818 * Find a surface for each sprite in the output using some heuristics:
819 * 1) size
820 * 2) frequency of update
821 * 3) opacity (though some hw might support alpha blending)
822 * 4) clipping (this can be fixed with color keys)
823 *
824 * The idea is to save on blitting since this should save power.
825 * If we can get a large video surface on the sprite for example,
826 * the main display surface may not need to update at all, and
827 * the client buffer can be used directly for the sprite surface
828 * as we do for flipping full screen surfaces.
829 */
830 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400831 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400832 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500833 pixman_region32_init(&surface_overlap);
834 pixman_region32_intersect(&surface_overlap, &overlap,
835 &es->transform.boundingbox);
836
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400837 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400838 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400839 next_plane = primary;
840 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400841 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400842 if (next_plane == NULL)
843 next_plane = drm_output_prepare_scanout_surface(output, es);
844 if (next_plane == NULL)
845 next_plane = drm_output_prepare_overlay_surface(output, es);
846 if (next_plane == NULL)
847 next_plane = primary;
848 weston_surface_move_to_plane(es, next_plane);
849 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 pixman_region32_union(&overlap, &overlap,
851 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400852
Jesse Barnes58ef3792012-02-23 09:45:49 -0500853 pixman_region32_fini(&surface_overlap);
854 }
855 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500856}
857
Matt Roper361d2ad2011-08-29 13:52:23 -0700858static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500859drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700860{
861 struct drm_output *output = (struct drm_output *) output_base;
862 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200863 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700864 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700865
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200866 if (output->backlight)
867 backlight_destroy(output->backlight);
868
Matt Roper361d2ad2011-08-29 13:52:23 -0700869 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400870 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700871
872 /* Restore original CRTC state */
873 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200874 origcrtc->x, origcrtc->y,
875 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700876 drmModeFreeCrtc(origcrtc);
877
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200878 c->crtc_allocator &= ~(1 << output->crtc_id);
879 c->connector_allocator &= ~(1 << output->connector_id);
880
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400881 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400882 gbm_surface_destroy(output->surface);
883
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400884 weston_plane_release(&output->fb_plane);
885 weston_plane_release(&output->cursor_plane);
886
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500887 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200888 wl_list_remove(&output->base.link);
889
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400890 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700891 free(output);
892}
893
Alex Wub7b8bda2012-04-17 17:20:48 +0800894static struct drm_mode *
895choose_mode (struct drm_output *output, struct weston_mode *target_mode)
896{
897 struct drm_mode *tmp_mode = NULL, *mode;
898
899 if (output->base.current->width == target_mode->width &&
900 output->base.current->height == target_mode->height &&
901 (output->base.current->refresh == target_mode->refresh ||
902 target_mode->refresh == 0))
903 return (struct drm_mode *)output->base.current;
904
905 wl_list_for_each(mode, &output->base.mode_list, base.link) {
906 if (mode->mode_info.hdisplay == target_mode->width &&
907 mode->mode_info.vdisplay == target_mode->height) {
908 if (mode->mode_info.vrefresh == target_mode->refresh ||
909 target_mode->refresh == 0) {
910 return mode;
911 } else if (!tmp_mode)
912 tmp_mode = mode;
913 }
914 }
915
916 return tmp_mode;
917}
918
919static int
920drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
921{
922 struct drm_output *output;
923 struct drm_mode *drm_mode;
924 int ret;
925 struct drm_compositor *ec;
926 struct gbm_surface *surface;
927 EGLSurface egl_surface;
928
929 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200930 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800931 return -1;
932 }
933
934 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200935 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800936 return -1;
937 }
938
939 ec = (struct drm_compositor *)output_base->compositor;
940 output = (struct drm_output *)output_base;
941 drm_mode = choose_mode (output, mode);
942
943 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200944 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800945 return -1;
946 } else if (&drm_mode->base == output->base.current) {
947 return 0;
948 } else if (drm_mode->base.width == output->base.current->width &&
949 drm_mode->base.height == output->base.current->height) {
950 /* only change refresh value */
951 ret = drmModeSetCrtc(ec->drm.fd,
952 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300953 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800954 &output->connector_id, 1, &drm_mode->mode_info);
955
956 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200957 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800958 drm_mode->base.width,
959 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400960 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800961 ret = -1;
962 } else {
963 output->base.current->flags = 0;
964 output->base.current = &drm_mode->base;
965 drm_mode->base.flags =
966 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
967 ret = 0;
968 }
969
970 return ret;
971 }
972
973 drm_mode->base.flags =
974 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
975
976 surface = gbm_surface_create(ec->gbm,
977 drm_mode->base.width,
978 drm_mode->base.height,
979 GBM_FORMAT_XRGB8888,
980 GBM_BO_USE_SCANOUT |
981 GBM_BO_USE_RENDERING);
982 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200983 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800984 return -1;
985 }
986
987 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400988 eglCreateWindowSurface(ec->base.egl_display,
989 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800990 surface, NULL);
991
992 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200993 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800994 goto err;
995 }
996
997 ret = drmModeSetCrtc(ec->drm.fd,
998 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300999 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +08001000 &output->connector_id, 1, &drm_mode->mode_info);
1001 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001002 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001003 goto err;
1004 }
1005
1006 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001007 if (output->current) {
1008 if (output->current->is_client_buffer)
1009 gbm_bo_destroy(output->current->bo);
1010 else
1011 gbm_surface_release_buffer(output->surface,
1012 output->current->bo);
1013 }
1014 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001015
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001016 if (output->next) {
1017 if (output->next->is_client_buffer)
1018 gbm_bo_destroy(output->next->bo);
1019 else
1020 gbm_surface_release_buffer(output->surface,
1021 output->next->bo);
1022 }
1023 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001024
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001025 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001026 gbm_surface_destroy(output->surface);
1027 output->egl_surface = egl_surface;
1028 output->surface = surface;
1029
1030 /*update output*/
1031 output->base.current = &drm_mode->base;
1032 output->base.dirty = 1;
1033 weston_output_move(&output->base, output->base.x, output->base.y);
1034 return 0;
1035
1036err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001037 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001038 gbm_surface_destroy(surface);
1039 return -1;
1040}
1041
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001042static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001043on_drm_input(int fd, uint32_t mask, void *data)
1044{
1045 drmEventContext evctx;
1046
1047 memset(&evctx, 0, sizeof evctx);
1048 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1049 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001050 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001051 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001052
1053 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001054}
1055
1056static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001057init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001058{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001059 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001060 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001061 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001062 static const EGLint context_attribs[] = {
1063 EGL_CONTEXT_CLIENT_VERSION, 2,
1064 EGL_NONE
1065 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001066
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001067 static const EGLint config_attribs[] = {
1068 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1069 EGL_RED_SIZE, 1,
1070 EGL_GREEN_SIZE, 1,
1071 EGL_BLUE_SIZE, 1,
1072 EGL_ALPHA_SIZE, 0,
1073 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1074 EGL_NONE
1075 };
1076
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001077 sysnum = udev_device_get_sysnum(device);
1078 if (sysnum)
1079 ec->drm.id = atoi(sysnum);
1080 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001081 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001082 return -1;
1083 }
1084
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001085 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001086 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001087 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001088 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001089 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001090 udev_device_get_devnode(device));
1091 return -1;
1092 }
1093
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001094 weston_log("using %s\n", filename);
1095
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001096 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001097 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001098 ec->base.egl_display = eglGetDisplay(ec->gbm);
1099 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001100 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001101 return -1;
1102 }
1103
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001104 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001105 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001106 return -1;
1107 }
1108
Darxus55973f22010-11-22 21:24:39 -05001109 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001110 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001111 return -1;
1112 }
1113
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001114 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1115 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001116 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001117 return -1;
1118 }
1119
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001120 ec->base.egl_context =
1121 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1122 EGL_NO_CONTEXT, context_attribs);
1123 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001124 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001125 return -1;
1126 }
1127
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001128 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1129 GBM_FORMAT_XRGB8888,
1130 GBM_BO_USE_RENDERING);
1131 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001132 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001133 return -1;
1134 }
1135
1136 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001137 eglCreateWindowSurface(ec->base.egl_display,
1138 ec->base.egl_config,
1139 ec->dummy_surface,
1140 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001141 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001142 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001143 return -1;
1144 }
1145
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001146 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1147 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001148 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001149 return -1;
1150 }
1151
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001152 return 0;
1153}
1154
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001155static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001156drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1157{
1158 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001159 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001160
1161 mode = malloc(sizeof *mode);
1162 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001163 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001164
1165 mode->base.flags = 0;
1166 mode->base.width = info->hdisplay;
1167 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001168
1169 /* Calculate higher precision (mHz) refresh rate */
1170 refresh = (info->clock * 1000000LL / info->htotal +
1171 info->vtotal / 2) / info->vtotal;
1172
1173 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1174 refresh *= 2;
1175 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1176 refresh /= 2;
1177 if (info->vscan > 1)
1178 refresh /= info->vscan;
1179
1180 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001181 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001182
1183 if (info->type & DRM_MODE_TYPE_PREFERRED)
1184 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1185
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001186 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1187
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001188 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001189}
1190
1191static int
1192drm_subpixel_to_wayland(int drm_value)
1193{
1194 switch (drm_value) {
1195 default:
1196 case DRM_MODE_SUBPIXEL_UNKNOWN:
1197 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1198 case DRM_MODE_SUBPIXEL_NONE:
1199 return WL_OUTPUT_SUBPIXEL_NONE;
1200 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1201 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1202 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1203 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1204 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1205 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1206 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1207 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1208 }
1209}
1210
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001211static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001212sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001213{
1214 struct drm_sprite *sprite =
1215 container_of(listener, struct drm_sprite,
1216 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001217 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001218
1219 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001220 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1221 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001222}
1223
1224static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001225sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001226{
1227 struct drm_sprite *sprite =
1228 container_of(listener, struct drm_sprite,
1229 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001230 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001231
1232 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001233 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1234 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001235}
1236
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001237/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001238static uint32_t
1239drm_get_backlight(struct drm_output *output)
1240{
1241 long brightness, max_brightness, norm;
1242
1243 brightness = backlight_get_brightness(output->backlight);
1244 max_brightness = backlight_get_max_brightness(output->backlight);
1245
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001246 /* convert it on a scale of 0 to 255 */
1247 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001248
1249 return (uint32_t) norm;
1250}
1251
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001252/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001253static void
1254drm_set_backlight(struct weston_output *output_base, uint32_t value)
1255{
1256 struct drm_output *output = (struct drm_output *) output_base;
1257 long max_brightness, new_brightness;
1258
1259 if (!output->backlight)
1260 return;
1261
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001262 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001263 return;
1264
1265 max_brightness = backlight_get_max_brightness(output->backlight);
1266
1267 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001268 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001269
1270 backlight_set_brightness(output->backlight, new_brightness);
1271}
1272
1273static drmModePropertyPtr
1274drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1275{
1276 drmModePropertyPtr props;
1277 int i;
1278
1279 for (i = 0; i < connector->count_props; i++) {
1280 props = drmModeGetProperty(fd, connector->props[i]);
1281 if (!props)
1282 continue;
1283
1284 if (!strcmp(props->name, name))
1285 return props;
1286
1287 drmModeFreeProperty(props);
1288 }
1289
1290 return NULL;
1291}
1292
1293static void
1294drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1295{
1296 struct drm_output *output = (struct drm_output *) output_base;
1297 struct weston_compositor *ec = output_base->compositor;
1298 struct drm_compositor *c = (struct drm_compositor *) ec;
1299 drmModeConnectorPtr connector;
1300 drmModePropertyPtr prop;
1301
1302 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1303 if (!connector)
1304 return;
1305
1306 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1307 if (!prop) {
1308 drmModeFreeConnector(connector);
1309 return;
1310 }
1311
1312 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1313 prop->prop_id, level);
1314 drmModeFreeProperty(prop);
1315 drmModeFreeConnector(connector);
1316}
1317
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001318static const char *connector_type_names[] = {
1319 "None",
1320 "VGA",
1321 "DVI",
1322 "DVI",
1323 "DVI",
1324 "Composite",
1325 "TV",
1326 "LVDS",
1327 "CTV",
1328 "DIN",
1329 "DP",
1330 "HDMI",
1331 "HDMI",
1332 "TV",
1333 "eDP",
1334};
1335
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001336static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001337find_crtc_for_connector(struct drm_compositor *ec,
1338 drmModeRes *resources, drmModeConnector *connector)
1339{
1340 drmModeEncoder *encoder;
1341 uint32_t possible_crtcs;
1342 int i, j;
1343
1344 for (j = 0; j < connector->count_encoders; j++) {
1345 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1346 if (encoder == NULL) {
1347 weston_log("Failed to get encoder.\n");
1348 return -1;
1349 }
1350 possible_crtcs = encoder->possible_crtcs;
1351 drmModeFreeEncoder(encoder);
1352
1353 for (i = 0; i < resources->count_crtcs; i++) {
1354 if (possible_crtcs & (1 << i) &&
1355 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1356 return i;
1357 }
1358 }
1359
1360 return -1;
1361}
1362
1363static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001364create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001365 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001366 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001367 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001368{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001369 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001370 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1371 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001372 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001373 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001374 drmModeModeInfo crtc_mode;
1375 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001376 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001377 char name[32];
1378 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001379
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001380 i = find_crtc_for_connector(ec, resources, connector);
1381 if (i < 0) {
1382 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001383 return -1;
1384 }
1385
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001386 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001387 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001388 return -1;
1389
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001390 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001391 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1392 output->base.make = "unknown";
1393 output->base.model = "unknown";
1394 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001395
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001396 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1397 type_name = connector_type_names[connector->connector_type];
1398 else
1399 type_name = "UNKNOWN";
1400 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1401 output->name = strdup(name);
1402
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001403 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001404 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001405 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001406 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001407 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001408
Matt Roper361d2ad2011-08-29 13:52:23 -07001409 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1410
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001411 /* Get the current mode on the crtc that's currently driving
1412 * this connector. */
1413 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001414 memset(&crtc_mode, 0, sizeof crtc_mode);
1415 if (encoder != NULL) {
1416 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1417 drmModeFreeEncoder(encoder);
1418 if (crtc == NULL)
1419 goto err_free;
1420 if (crtc->mode_valid)
1421 crtc_mode = crtc->mode;
1422 drmModeFreeCrtc(crtc);
1423 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001424
David Herrmann0f0d54e2011-12-08 17:05:45 +01001425 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001426 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1427 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001428 goto err_free;
1429 }
1430
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001431 preferred = NULL;
1432 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001433 configured = NULL;
1434
1435 wl_list_for_each(temp, &configured_output_list, link) {
1436 if (strcmp(temp->name, output->name) == 0) {
1437 weston_log("%s mode \"%s\" in config\n",
1438 temp->name, temp->mode);
1439 o = temp;
1440 break;
1441 }
1442 }
1443
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001444 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001445 weston_log("Disabling output %s\n", o->name);
1446
1447 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1448 0, 0, 0, 0, 0, NULL);
1449 goto err_free;
1450 }
1451
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001452 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001453 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001454 o->height == drm_mode->base.height &&
1455 o->config == OUTPUT_CONFIG_MODE)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001456 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001457 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001458 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001459 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001460 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001461 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001462
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001463 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001464 configured = drm_output_add_mode(output, &o->crtc_mode);
1465 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001466 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001467 current = configured;
1468 }
1469
Wang Quanxianacb805a2012-07-30 18:09:46 -04001470 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001471 current = drm_output_add_mode(output, &crtc_mode);
1472 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001473 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001474 }
1475
Scott Moreau8ab5d452012-07-30 19:51:08 -06001476 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1477 configured = current;
1478
Wang Quanxianacb805a2012-07-30 18:09:46 -04001479 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001480 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001481 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001482 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001483 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001484 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001485 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001486 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001487
1488 if (output->base.current == NULL) {
1489 weston_log("no available modes for %s\n", output->name);
1490 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001491 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001492
Wang Quanxianacb805a2012-07-30 18:09:46 -04001493 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1494
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001495 output->surface = gbm_surface_create(ec->gbm,
1496 output->base.current->width,
1497 output->base.current->height,
1498 GBM_FORMAT_XRGB8888,
1499 GBM_BO_USE_SCANOUT |
1500 GBM_BO_USE_RENDERING);
1501 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001502 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001503 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001504 }
1505
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001506 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001507 eglCreateWindowSurface(ec->base.egl_display,
1508 ec->base.egl_config,
1509 output->surface,
1510 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001511 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001512 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001513 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001514 }
1515
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001516 output->cursor_bo[0] =
1517 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1518 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1519 output->cursor_bo[1] =
1520 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1521 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1522
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001523 output->backlight = backlight_init(drm_device,
1524 connector->connector_type);
1525 if (output->backlight) {
1526 output->base.set_backlight = drm_set_backlight;
1527 output->base.backlight_current = drm_get_backlight(output);
1528 }
1529
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001530 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsberg99fd1012012-08-10 09:57:56 -04001531 connector->mmWidth, connector->mmHeight);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001532
1533 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1534
Alex Wubd3354b2012-04-17 17:20:49 +08001535 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001536 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001537 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001538 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001539 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001540 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001541
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001542 weston_plane_init(&output->cursor_plane, 0, 0);
1543 weston_plane_init(&output->fb_plane, 0, 0);
1544
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001545 weston_log("Output %s, (connector %d, crtc %d)\n",
1546 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001547 wl_list_for_each(m, &output->base.mode_list, link)
1548 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1549 m->width, m->height, m->refresh / 1000.0,
1550 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1551 ", preferred" : "",
1552 m->flags & WL_OUTPUT_MODE_CURRENT ?
1553 ", current" : "",
1554 connector->count_modes == 0 ?
1555 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001556
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001557 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001558
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001559err_surface:
1560 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001561err_free:
1562 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1563 base.link) {
1564 wl_list_remove(&drm_mode->base.link);
1565 free(drm_mode);
1566 }
1567
1568 drmModeFreeCrtc(output->original_crtc);
1569 ec->crtc_allocator &= ~(1 << output->crtc_id);
1570 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001571 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001572 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001573
David Herrmann0f0d54e2011-12-08 17:05:45 +01001574 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001575}
1576
Jesse Barnes58ef3792012-02-23 09:45:49 -05001577static void
1578create_sprites(struct drm_compositor *ec)
1579{
1580 struct drm_sprite *sprite;
1581 drmModePlaneRes *plane_res;
1582 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001583 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001584
1585 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1586 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001587 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001588 strerror(errno));
1589 return;
1590 }
1591
1592 for (i = 0; i < plane_res->count_planes; i++) {
1593 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1594 if (!plane)
1595 continue;
1596
1597 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1598 plane->count_formats));
1599 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001600 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001601 __func__);
1602 free(plane);
1603 continue;
1604 }
1605
1606 memset(sprite, 0, sizeof *sprite);
1607
1608 sprite->possible_crtcs = plane->possible_crtcs;
1609 sprite->plane_id = plane->plane_id;
1610 sprite->surface = NULL;
1611 sprite->pending_surface = NULL;
1612 sprite->fb_id = 0;
1613 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001614 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1615 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001616 sprite_handle_pending_buffer_destroy;
1617 sprite->compositor = ec;
1618 sprite->count_formats = plane->count_formats;
1619 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001620 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001621 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001622 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001623
1624 wl_list_insert(&ec->sprite_list, &sprite->link);
1625 }
1626
1627 free(plane_res->planes);
1628 free(plane_res);
1629}
1630
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001631static void
1632destroy_sprites(struct drm_compositor *compositor)
1633{
1634 struct drm_sprite *sprite, *next;
1635 struct drm_output *output;
1636
1637 output = container_of(compositor->base.output_list.next,
1638 struct drm_output, base.link);
1639
1640 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1641 drmModeSetPlane(compositor->drm.fd,
1642 sprite->plane_id,
1643 output->crtc_id, 0, 0,
1644 0, 0, 0, 0, 0, 0, 0, 0);
1645 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001646 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001647 free(sprite);
1648 }
1649}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001650
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001651static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001652create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001653 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001654{
1655 drmModeConnector *connector;
1656 drmModeRes *resources;
1657 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001658 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001659
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001660 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001661 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001662 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001663 return -1;
1664 }
1665
Jesse Barnes58ef3792012-02-23 09:45:49 -05001666 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001667 if (!ec->crtcs) {
1668 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001669 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001670 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001671
Rob Clark4339add2012-08-09 14:18:28 -05001672 ec->min_width = resources->min_width;
1673 ec->max_width = resources->max_width;
1674 ec->min_height = resources->min_height;
1675 ec->max_height = resources->max_height;
1676
Jesse Barnes58ef3792012-02-23 09:45:49 -05001677 ec->num_crtcs = resources->count_crtcs;
1678 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1679
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001680 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001681 connector = drmModeGetConnector(ec->drm.fd,
1682 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001683 if (connector == NULL)
1684 continue;
1685
1686 if (connector->connection == DRM_MODE_CONNECTED &&
1687 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001688 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001689 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001690 connector, x, y,
1691 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001692 drmModeFreeConnector(connector);
1693 continue;
1694 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001695
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001696 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001697 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001698 link)->current->width;
1699 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001700
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001701 drmModeFreeConnector(connector);
1702 }
1703
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001704 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001705 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001706 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001707 return -1;
1708 }
1709
1710 drmModeFreeResources(resources);
1711
1712 return 0;
1713}
1714
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001715static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001716update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001717{
1718 drmModeConnector *connector;
1719 drmModeRes *resources;
1720 struct drm_output *output, *next;
1721 int x = 0, y = 0;
1722 int x_offset = 0, y_offset = 0;
1723 uint32_t connected = 0, disconnects = 0;
1724 int i;
1725
1726 resources = drmModeGetResources(ec->drm.fd);
1727 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001728 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001729 return;
1730 }
1731
1732 /* collect new connects */
1733 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001734 int connector_id = resources->connectors[i];
1735
1736 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001737 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001738 continue;
1739
David Herrmann7551cff2011-12-08 17:05:43 +01001740 if (connector->connection != DRM_MODE_CONNECTED) {
1741 drmModeFreeConnector(connector);
1742 continue;
1743 }
1744
Benjamin Franzke117483d2011-08-30 11:38:26 +02001745 connected |= (1 << connector_id);
1746
1747 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001748 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001749 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001750 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001751
1752 /* XXX: not yet needed, we die with 0 outputs */
1753 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001754 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001755 else
1756 x = 0;
1757 y = 0;
1758 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001759 connector, x, y,
1760 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001761 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001762
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001763 }
1764 drmModeFreeConnector(connector);
1765 }
1766 drmModeFreeResources(resources);
1767
1768 disconnects = ec->connector_allocator & ~connected;
1769 if (disconnects) {
1770 wl_list_for_each_safe(output, next, &ec->base.output_list,
1771 base.link) {
1772 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001773 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001774 output->base.x - x_offset,
1775 output->base.y - y_offset);
1776 }
1777
1778 if (disconnects & (1 << output->connector_id)) {
1779 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001780 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001781 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001782 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001783 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001784 }
1785 }
1786 }
1787
1788 /* FIXME: handle zero outputs, without terminating */
1789 if (ec->connector_allocator == 0)
1790 wl_display_terminate(ec->base.wl_display);
1791}
1792
1793static int
David Herrmannd7488c22012-03-11 20:05:21 +01001794udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001795{
David Herrmannd7488c22012-03-11 20:05:21 +01001796 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001797 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001798
1799 sysnum = udev_device_get_sysnum(device);
1800 if (!sysnum || atoi(sysnum) != ec->drm.id)
1801 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001802
David Herrmann6ac52db2012-03-11 20:05:22 +01001803 val = udev_device_get_property_value(device, "HOTPLUG");
1804 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001805 return 0;
1806
David Herrmann6ac52db2012-03-11 20:05:22 +01001807 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001808}
1809
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001810static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001811udev_drm_event(int fd, uint32_t mask, void *data)
1812{
1813 struct drm_compositor *ec = data;
1814 struct udev_device *event;
1815
1816 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001817
David Herrmannd7488c22012-03-11 20:05:21 +01001818 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001819 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001820
1821 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001822
1823 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001824}
1825
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001826static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001827drm_restore(struct weston_compositor *ec)
1828{
1829 struct drm_compositor *d = (struct drm_compositor *) ec;
1830
1831 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1832 weston_log("failed to drop master: %m\n");
1833 tty_reset(d->tty);
1834}
1835
Pekka Paalanen33156972012-08-03 13:30:30 -04001836static const char default_seat[] = "seat0";
1837
1838static void
1839device_added(struct udev_device *udev_device, struct drm_seat *master)
1840{
1841 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001842 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001843 const char *devnode;
1844 const char *device_seat;
1845 int fd;
1846
1847 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1848 if (!device_seat)
1849 device_seat = default_seat;
1850
1851 if (strcmp(device_seat, master->seat_id))
1852 return;
1853
1854 c = master->base.compositor;
1855 devnode = udev_device_get_devnode(udev_device);
1856
1857 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001858 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001859 * read. mtdev_get() also expects this. */
1860 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1861 if (fd < 0) {
1862 weston_log("opening input device '%s' failed.\n", devnode);
1863 return;
1864 }
1865
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001866 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001867 if (!device) {
1868 close(fd);
1869 weston_log("not using input device '%s'.\n", devnode);
1870 return;
1871 }
1872
1873 wl_list_insert(master->devices_list.prev, &device->link);
1874}
1875
1876static void
1877evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1878{
1879 struct drm_seat *seat = (struct drm_seat *) seat_base;
1880 struct udev_enumerate *e;
1881 struct udev_list_entry *entry;
1882 struct udev_device *device;
1883 const char *path, *sysname;
1884
1885 e = udev_enumerate_new(udev);
1886 udev_enumerate_add_match_subsystem(e, "input");
1887 udev_enumerate_scan_devices(e);
1888 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1889 path = udev_list_entry_get_name(entry);
1890 device = udev_device_new_from_syspath(udev, path);
1891
1892 sysname = udev_device_get_sysname(device);
1893 if (strncmp("event", sysname, 5) != 0) {
1894 udev_device_unref(device);
1895 continue;
1896 }
1897
1898 device_added(device, seat);
1899
1900 udev_device_unref(device);
1901 }
1902 udev_enumerate_unref(e);
1903
1904 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1905
1906 if (wl_list_empty(&seat->devices_list)) {
1907 weston_log(
1908 "warning: no input devices on entering Weston. "
1909 "Possible causes:\n"
1910 "\t- no permissions to read /dev/input/event*\n"
1911 "\t- seats misconfigured "
1912 "(Weston backend option 'seat', "
1913 "udev device property ID_SEAT)\n");
1914 }
1915}
1916
1917static int
1918evdev_udev_handler(int fd, uint32_t mask, void *data)
1919{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001920 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001921 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001922 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001923 const char *action;
1924 const char *devnode;
1925
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001926 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001927 if (!udev_device)
1928 return 1;
1929
1930 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001931 if (!action)
1932 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001933
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001934 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1935 goto out;
1936
1937 if (!strcmp(action, "add")) {
1938 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001939 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001940 else if (!strcmp(action, "remove")) {
1941 devnode = udev_device_get_devnode(udev_device);
1942 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1943 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001944 weston_log("input device %s, %s removed\n",
1945 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001946 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001947 break;
1948 }
1949 }
1950
1951out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001952 udev_device_unref(udev_device);
1953
1954 return 0;
1955}
1956
1957static int
1958evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1959{
1960 struct drm_seat *master = (struct drm_seat *) seat_base;
1961 struct wl_event_loop *loop;
1962 struct weston_compositor *c = master->base.compositor;
1963 int fd;
1964
1965 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1966 if (!master->udev_monitor) {
1967 weston_log("udev: failed to create the udev monitor\n");
1968 return 0;
1969 }
1970
1971 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1972 "input", NULL);
1973
1974 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1975 weston_log("udev: failed to bind the udev monitor\n");
1976 udev_monitor_unref(master->udev_monitor);
1977 return 0;
1978 }
1979
1980 loop = wl_display_get_event_loop(c->wl_display);
1981 fd = udev_monitor_get_fd(master->udev_monitor);
1982 master->udev_monitor_source =
1983 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1984 evdev_udev_handler, master);
1985 if (!master->udev_monitor_source) {
1986 udev_monitor_unref(master->udev_monitor);
1987 return 0;
1988 }
1989
1990 return 1;
1991}
1992
1993static void
1994evdev_disable_udev_monitor(struct weston_seat *seat_base)
1995{
1996 struct drm_seat *seat = (struct drm_seat *) seat_base;
1997
1998 if (!seat->udev_monitor)
1999 return;
2000
2001 udev_monitor_unref(seat->udev_monitor);
2002 seat->udev_monitor = NULL;
2003 wl_event_source_remove(seat->udev_monitor_source);
2004 seat->udev_monitor_source = NULL;
2005}
2006
2007static void
2008drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
2009{
2010 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002011 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002012
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002013 wl_list_for_each(device, &seat->devices_list, link)
2014 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002015}
2016
2017static void
2018evdev_input_create(struct weston_compositor *c, struct udev *udev,
2019 const char *seat_id)
2020{
2021 struct drm_seat *seat;
2022
2023 seat = malloc(sizeof *seat);
2024 if (seat == NULL)
2025 return;
2026
2027 memset(seat, 0, sizeof *seat);
2028 weston_seat_init(&seat->base, c);
2029 seat->base.led_update = drm_led_update;
2030
2031 wl_list_init(&seat->devices_list);
2032 seat->seat_id = strdup(seat_id);
2033 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2034 free(seat->seat_id);
2035 free(seat);
2036 return;
2037 }
2038
2039 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002040}
2041
2042static void
2043evdev_remove_devices(struct weston_seat *seat_base)
2044{
2045 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002046 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002047
2048 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002049 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002050
Pekka Paalanend8583512012-08-03 14:39:11 +03002051 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002052 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002053}
2054
2055static void
2056evdev_input_destroy(struct weston_seat *seat_base)
2057{
2058 struct drm_seat *seat = (struct drm_seat *) seat_base;
2059
2060 evdev_remove_devices(seat_base);
2061 evdev_disable_udev_monitor(&seat->base);
2062
2063 weston_seat_release(seat_base);
2064 free(seat->seat_id);
2065 free(seat);
2066}
2067
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002068static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002069drm_free_configured_output(struct drm_configured_output *output)
2070{
2071 free(output->name);
2072 free(output->mode);
2073 free(output);
2074}
2075
2076static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002077drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002078{
2079 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002080 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002081 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002082
Daniel Stone37816df2012-05-16 18:45:18 +01002083 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2084 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002085 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002086 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002087
2088 wl_event_source_remove(d->udev_drm_source);
2089 wl_event_source_remove(d->drm_source);
2090
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002091 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002092
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002093 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002094 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002095 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002096 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002097 eglReleaseThread();
2098
Matt Roper361d2ad2011-08-29 13:52:23 -07002099 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002100 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002101 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002102 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002103 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002104
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002105 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002106}
2107
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002108static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002109drm_compositor_set_modes(struct drm_compositor *compositor)
2110{
2111 struct drm_output *output;
2112 struct drm_mode *drm_mode;
2113 int ret;
2114
2115 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2116 drm_mode = (struct drm_mode *) output->base.current;
2117 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002118 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002119 &output->connector_id, 1,
2120 &drm_mode->mode_info);
2121 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002122 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002123 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002124 drm_mode->base.width, drm_mode->base.height,
2125 output->base.x, output->base.y);
2126 }
2127 }
2128}
2129
2130static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002131vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002132{
2133 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002134 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002135 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002136 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002137
2138 switch (event) {
2139 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002140 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002141 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002142 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002143 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002144 wl_display_terminate(compositor->wl_display);
2145 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002146 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002147 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002148 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002149 wl_list_for_each(seat, &compositor->seat_list, link) {
2150 evdev_add_devices(ec->udev, seat);
2151 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002152 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002153 break;
2154 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002155 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002156 wl_list_for_each(seat, &compositor->seat_list, link) {
2157 evdev_disable_udev_monitor(seat);
2158 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002159 }
2160
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002161 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002162 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002163 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002164
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002165 /* If we have a repaint scheduled (either from a
2166 * pending pageflip or the idle handler), make sure we
2167 * cancel that so we don't try to pageflip when we're
2168 * vt switched away. The SLEEPING state will prevent
2169 * further attemps at repainting. When we switch
2170 * back, we schedule a repaint, which will process
2171 * pending frame callbacks. */
2172
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002173 wl_list_for_each(output, &ec->base.output_list, base.link) {
2174 output->base.repaint_needed = 0;
2175 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002176 }
2177
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002178 output = container_of(ec->base.output_list.next,
2179 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002180
2181 wl_list_for_each(sprite, &ec->sprite_list, link)
2182 drmModeSetPlane(ec->drm.fd,
2183 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002184 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002185 0, 0, 0, 0, 0, 0, 0, 0);
2186
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002187 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002188 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002189
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002190 break;
2191 };
2192}
2193
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002194static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002195switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002196{
2197 struct drm_compositor *ec = data;
2198
Daniel Stone325fc2d2012-05-30 16:31:58 +01002199 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002200}
2201
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002202static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002203drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002204 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002205 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002206{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002207 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002208 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002209 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002210 struct udev_device *device, *drm_device;
2211 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002212 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002213 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002214 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002215
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002216 weston_log("initializing drm backend\n");
2217
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002218 ec = malloc(sizeof *ec);
2219 if (ec == NULL)
2220 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002221 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002222
2223 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002224 config_file) < 0) {
2225 weston_log("weston_compositor_init failed\n");
2226 goto err_base;
2227 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002228
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002229 ec->udev = udev_new();
2230 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002231 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002232 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002233 }
2234
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002235 ec->base.wl_display = display;
2236 ec->tty = tty_create(&ec->base, vt_func, tty);
2237 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002238 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002239 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002240 }
2241
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002242 e = udev_enumerate_new(ec->udev);
2243 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002244 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002245
Benjamin Franzke117483d2011-08-30 11:38:26 +02002246 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002247 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002248 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002249 path = udev_list_entry_get_name(entry);
2250 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002251 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002252 udev_device_get_property_value(device, "ID_SEAT");
2253 if (!device_seat)
2254 device_seat = default_seat;
2255 if (strcmp(device_seat, seat) == 0) {
2256 drm_device = device;
2257 break;
2258 }
2259 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002260 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002261
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002262 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002263 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002264 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002265 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002266
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002267 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002268 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002269 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002270 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002271
2272 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002273 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002274
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002275 ec->base.focus = 1;
2276
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002277 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002278
Daniel Stone725c2c32012-06-22 14:04:36 +01002279 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002280 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002281
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002282 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002283 weston_compositor_add_key_binding(&ec->base, key,
2284 MODIFIER_CTRL | MODIFIER_ALT,
2285 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002286
Jesse Barnes58ef3792012-02-23 09:45:49 -05002287 wl_list_init(&ec->sprite_list);
2288 create_sprites(ec);
2289
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002290 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002291 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002292 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002293 }
2294
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002295 path = NULL;
2296
Tiago Vignattice03ec32011-12-19 01:14:03 +02002297 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002298
2299 loop = wl_display_get_event_loop(ec->base.wl_display);
2300 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002301 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002302 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002303
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002304 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2305 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002306 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002307 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002308 }
2309 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2310 "drm", NULL);
2311 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002312 wl_event_loop_add_fd(loop,
2313 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002314 WL_EVENT_READABLE, udev_drm_event, ec);
2315
2316 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002317 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002318 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002319 }
2320
Daniel Stonea96b93c2012-06-22 14:04:37 +01002321 udev_device_unref(drm_device);
2322 udev_enumerate_unref(e);
2323
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002324 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002325
2326err_udev_monitor:
2327 wl_event_source_remove(ec->udev_drm_source);
2328 udev_monitor_unref(ec->udev_monitor);
2329err_drm_source:
2330 wl_event_source_remove(ec->drm_source);
2331 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2332 evdev_input_destroy(weston_seat);
2333err_sprite:
2334 destroy_sprites(ec);
2335err_egl:
2336 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2337 EGL_NO_CONTEXT);
2338 eglTerminate(ec->base.egl_display);
2339 eglReleaseThread();
2340 gbm_device_destroy(ec->gbm);
2341err_udev_dev:
2342 udev_device_unref(drm_device);
2343err_udev_enum:
2344 udev_enumerate_unref(e);
2345 tty_destroy(ec->tty);
2346err_udev:
2347 udev_unref(ec->udev);
2348err_compositor:
2349 weston_compositor_shutdown(&ec->base);
2350err_base:
2351 free(ec);
2352 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002353}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002354
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002355static int
2356set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2357{
2358 mode->flags = 0;
2359
2360 if (strcmp(hsync, "+hsync") == 0)
2361 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2362 else if (strcmp(hsync, "-hsync") == 0)
2363 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2364 else
2365 return -1;
2366
2367 if (strcmp(vsync, "+vsync") == 0)
2368 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2369 else if (strcmp(vsync, "-vsync") == 0)
2370 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2371 else
2372 return -1;
2373
2374 return 0;
2375}
2376
2377static int
2378check_for_modeline(struct drm_configured_output *output)
2379{
2380 drmModeModeInfo mode;
2381 char hsync[16];
2382 char vsync[16];
2383 char mode_name[16];
2384 float fclock;
2385
2386 mode.type = DRM_MODE_TYPE_USERDEF;
2387 mode.hskew = 0;
2388 mode.vscan = 0;
2389 mode.vrefresh = 0;
2390
2391 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2392 &fclock, &mode.hdisplay,
2393 &mode.hsync_start,
2394 &mode.hsync_end, &mode.htotal,
2395 &mode.vdisplay,
2396 &mode.vsync_start,
2397 &mode.vsync_end, &mode.vtotal,
2398 hsync, vsync) == 11) {
2399 if (set_sync_flags(&mode, hsync, vsync))
2400 return -1;
2401
2402 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2403 strcpy(mode.name, mode_name);
2404
2405 mode.clock = fclock * 1000;
2406 } else
2407 return -1;
2408
2409 output->crtc_mode = mode;
2410
2411 return 0;
2412}
2413
Scott Moreau8ab5d452012-07-30 19:51:08 -06002414static void
2415output_section_done(void *data)
2416{
2417 struct drm_configured_output *output;
2418
2419 output = malloc(sizeof *output);
2420
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002421 if (!output || !output_name || !output_mode) {
2422 free(output_name);
2423 output_name = NULL;
2424 free(output_mode);
2425 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002426 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002427 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002428
2429 output->config = OUTPUT_CONFIG_INVALID;
2430 output->name = output_name;
2431 output->mode = output_mode;
2432
2433 if (strcmp(output_mode, "off") == 0)
2434 output->config = OUTPUT_CONFIG_OFF;
2435 else if (strcmp(output_mode, "preferred") == 0)
2436 output->config = OUTPUT_CONFIG_PREFERRED;
2437 else if (strcmp(output_mode, "current") == 0)
2438 output->config = OUTPUT_CONFIG_CURRENT;
2439 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2440 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002441 else if (check_for_modeline(output) == 0)
2442 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002443
2444 if (output->config != OUTPUT_CONFIG_INVALID)
2445 wl_list_insert(&configured_output_list, &output->link);
2446 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002447 weston_log("Invalid mode \"%s\" for output %s\n",
2448 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002449 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002450 }
2451}
2452
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002453WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002454backend_init(struct wl_display *display, int argc, char *argv[],
2455 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002456{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002457 int connector = 0, tty = 0;
2458 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002459
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002460 const struct weston_option drm_options[] = {
2461 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2462 { WESTON_OPTION_STRING, "seat", 0, &seat },
2463 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002464 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002465 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002466
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002467 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002468
Scott Moreau8ab5d452012-07-30 19:51:08 -06002469 wl_list_init(&configured_output_list);
2470
2471 const struct config_key drm_config_keys[] = {
2472 { "name", CONFIG_KEY_STRING, &output_name },
2473 { "mode", CONFIG_KEY_STRING, &output_mode },
2474 };
2475
2476 const struct config_section config_section[] = {
2477 { "output", drm_config_keys,
2478 ARRAY_LENGTH(drm_config_keys), output_section_done },
2479 };
2480
2481 parse_config_file(config_file, config_section,
2482 ARRAY_LENGTH(config_section), NULL);
2483
Daniel Stonec1be8e52012-06-01 11:14:02 -04002484 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2485 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002486}