blob: 0c864ef3068adb62243f0169f11799446c5bbf5d [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øgsbergcbcd0472012-03-11 18:27:41 -04001531 connector->mmWidth, connector->mmHeight,
1532 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001533
1534 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1535
Alex Wubd3354b2012-04-17 17:20:49 +08001536 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001537 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001538 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001539 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001540 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001541 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001542
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001543 weston_plane_init(&output->cursor_plane, 0, 0);
1544 weston_plane_init(&output->fb_plane, 0, 0);
1545
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001546 weston_log("Output %s, (connector %d, crtc %d)\n",
1547 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001548 wl_list_for_each(m, &output->base.mode_list, link)
1549 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1550 m->width, m->height, m->refresh / 1000.0,
1551 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1552 ", preferred" : "",
1553 m->flags & WL_OUTPUT_MODE_CURRENT ?
1554 ", current" : "",
1555 connector->count_modes == 0 ?
1556 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001557
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001558 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001559
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001560err_surface:
1561 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001562err_free:
1563 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1564 base.link) {
1565 wl_list_remove(&drm_mode->base.link);
1566 free(drm_mode);
1567 }
1568
1569 drmModeFreeCrtc(output->original_crtc);
1570 ec->crtc_allocator &= ~(1 << output->crtc_id);
1571 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001572 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001573 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001574
David Herrmann0f0d54e2011-12-08 17:05:45 +01001575 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001576}
1577
Jesse Barnes58ef3792012-02-23 09:45:49 -05001578static void
1579create_sprites(struct drm_compositor *ec)
1580{
1581 struct drm_sprite *sprite;
1582 drmModePlaneRes *plane_res;
1583 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001584 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001585
1586 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1587 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001588 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001589 strerror(errno));
1590 return;
1591 }
1592
1593 for (i = 0; i < plane_res->count_planes; i++) {
1594 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1595 if (!plane)
1596 continue;
1597
1598 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1599 plane->count_formats));
1600 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001601 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001602 __func__);
1603 free(plane);
1604 continue;
1605 }
1606
1607 memset(sprite, 0, sizeof *sprite);
1608
1609 sprite->possible_crtcs = plane->possible_crtcs;
1610 sprite->plane_id = plane->plane_id;
1611 sprite->surface = NULL;
1612 sprite->pending_surface = NULL;
1613 sprite->fb_id = 0;
1614 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001615 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1616 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001617 sprite_handle_pending_buffer_destroy;
1618 sprite->compositor = ec;
1619 sprite->count_formats = plane->count_formats;
1620 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001621 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001622 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001623 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001624
1625 wl_list_insert(&ec->sprite_list, &sprite->link);
1626 }
1627
1628 free(plane_res->planes);
1629 free(plane_res);
1630}
1631
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001632static void
1633destroy_sprites(struct drm_compositor *compositor)
1634{
1635 struct drm_sprite *sprite, *next;
1636 struct drm_output *output;
1637
1638 output = container_of(compositor->base.output_list.next,
1639 struct drm_output, base.link);
1640
1641 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1642 drmModeSetPlane(compositor->drm.fd,
1643 sprite->plane_id,
1644 output->crtc_id, 0, 0,
1645 0, 0, 0, 0, 0, 0, 0, 0);
1646 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001647 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001648 free(sprite);
1649 }
1650}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001651
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001652static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001653create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001654 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001655{
1656 drmModeConnector *connector;
1657 drmModeRes *resources;
1658 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001659 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001660
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001661 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001662 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001663 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001664 return -1;
1665 }
1666
Jesse Barnes58ef3792012-02-23 09:45:49 -05001667 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001668 if (!ec->crtcs) {
1669 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001670 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001671 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001672
Rob Clark4339add2012-08-09 14:18:28 -05001673 ec->min_width = resources->min_width;
1674 ec->max_width = resources->max_width;
1675 ec->min_height = resources->min_height;
1676 ec->max_height = resources->max_height;
1677
Jesse Barnes58ef3792012-02-23 09:45:49 -05001678 ec->num_crtcs = resources->count_crtcs;
1679 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1680
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001681 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001682 connector = drmModeGetConnector(ec->drm.fd,
1683 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001684 if (connector == NULL)
1685 continue;
1686
1687 if (connector->connection == DRM_MODE_CONNECTED &&
1688 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001689 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001690 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001691 connector, x, y,
1692 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001693 drmModeFreeConnector(connector);
1694 continue;
1695 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001696
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001697 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001698 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001699 link)->current->width;
1700 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001701
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001702 drmModeFreeConnector(connector);
1703 }
1704
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001705 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001706 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001707 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001708 return -1;
1709 }
1710
1711 drmModeFreeResources(resources);
1712
1713 return 0;
1714}
1715
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001716static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001717update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718{
1719 drmModeConnector *connector;
1720 drmModeRes *resources;
1721 struct drm_output *output, *next;
1722 int x = 0, y = 0;
1723 int x_offset = 0, y_offset = 0;
1724 uint32_t connected = 0, disconnects = 0;
1725 int i;
1726
1727 resources = drmModeGetResources(ec->drm.fd);
1728 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001729 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001730 return;
1731 }
1732
1733 /* collect new connects */
1734 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001735 int connector_id = resources->connectors[i];
1736
1737 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001738 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001739 continue;
1740
David Herrmann7551cff2011-12-08 17:05:43 +01001741 if (connector->connection != DRM_MODE_CONNECTED) {
1742 drmModeFreeConnector(connector);
1743 continue;
1744 }
1745
Benjamin Franzke117483d2011-08-30 11:38:26 +02001746 connected |= (1 << connector_id);
1747
1748 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001749 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001750 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001751 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001752
1753 /* XXX: not yet needed, we die with 0 outputs */
1754 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001755 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001756 else
1757 x = 0;
1758 y = 0;
1759 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001760 connector, x, y,
1761 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001762 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001763
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001764 }
1765 drmModeFreeConnector(connector);
1766 }
1767 drmModeFreeResources(resources);
1768
1769 disconnects = ec->connector_allocator & ~connected;
1770 if (disconnects) {
1771 wl_list_for_each_safe(output, next, &ec->base.output_list,
1772 base.link) {
1773 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001774 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001775 output->base.x - x_offset,
1776 output->base.y - y_offset);
1777 }
1778
1779 if (disconnects & (1 << output->connector_id)) {
1780 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001781 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001782 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001783 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001784 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001785 }
1786 }
1787 }
1788
1789 /* FIXME: handle zero outputs, without terminating */
1790 if (ec->connector_allocator == 0)
1791 wl_display_terminate(ec->base.wl_display);
1792}
1793
1794static int
David Herrmannd7488c22012-03-11 20:05:21 +01001795udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001796{
David Herrmannd7488c22012-03-11 20:05:21 +01001797 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001798 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001799
1800 sysnum = udev_device_get_sysnum(device);
1801 if (!sysnum || atoi(sysnum) != ec->drm.id)
1802 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001803
David Herrmann6ac52db2012-03-11 20:05:22 +01001804 val = udev_device_get_property_value(device, "HOTPLUG");
1805 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001806 return 0;
1807
David Herrmann6ac52db2012-03-11 20:05:22 +01001808 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001809}
1810
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001811static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001812udev_drm_event(int fd, uint32_t mask, void *data)
1813{
1814 struct drm_compositor *ec = data;
1815 struct udev_device *event;
1816
1817 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001818
David Herrmannd7488c22012-03-11 20:05:21 +01001819 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001820 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001821
1822 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001823
1824 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001825}
1826
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001827static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001828drm_restore(struct weston_compositor *ec)
1829{
1830 struct drm_compositor *d = (struct drm_compositor *) ec;
1831
1832 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1833 weston_log("failed to drop master: %m\n");
1834 tty_reset(d->tty);
1835}
1836
Pekka Paalanen33156972012-08-03 13:30:30 -04001837static const char default_seat[] = "seat0";
1838
1839static void
1840device_added(struct udev_device *udev_device, struct drm_seat *master)
1841{
1842 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001843 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001844 const char *devnode;
1845 const char *device_seat;
1846 int fd;
1847
1848 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1849 if (!device_seat)
1850 device_seat = default_seat;
1851
1852 if (strcmp(device_seat, master->seat_id))
1853 return;
1854
1855 c = master->base.compositor;
1856 devnode = udev_device_get_devnode(udev_device);
1857
1858 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001859 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001860 * read. mtdev_get() also expects this. */
1861 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1862 if (fd < 0) {
1863 weston_log("opening input device '%s' failed.\n", devnode);
1864 return;
1865 }
1866
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001867 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001868 if (!device) {
1869 close(fd);
1870 weston_log("not using input device '%s'.\n", devnode);
1871 return;
1872 }
1873
1874 wl_list_insert(master->devices_list.prev, &device->link);
1875}
1876
1877static void
1878evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1879{
1880 struct drm_seat *seat = (struct drm_seat *) seat_base;
1881 struct udev_enumerate *e;
1882 struct udev_list_entry *entry;
1883 struct udev_device *device;
1884 const char *path, *sysname;
1885
1886 e = udev_enumerate_new(udev);
1887 udev_enumerate_add_match_subsystem(e, "input");
1888 udev_enumerate_scan_devices(e);
1889 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1890 path = udev_list_entry_get_name(entry);
1891 device = udev_device_new_from_syspath(udev, path);
1892
1893 sysname = udev_device_get_sysname(device);
1894 if (strncmp("event", sysname, 5) != 0) {
1895 udev_device_unref(device);
1896 continue;
1897 }
1898
1899 device_added(device, seat);
1900
1901 udev_device_unref(device);
1902 }
1903 udev_enumerate_unref(e);
1904
1905 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1906
1907 if (wl_list_empty(&seat->devices_list)) {
1908 weston_log(
1909 "warning: no input devices on entering Weston. "
1910 "Possible causes:\n"
1911 "\t- no permissions to read /dev/input/event*\n"
1912 "\t- seats misconfigured "
1913 "(Weston backend option 'seat', "
1914 "udev device property ID_SEAT)\n");
1915 }
1916}
1917
1918static int
1919evdev_udev_handler(int fd, uint32_t mask, void *data)
1920{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001921 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001922 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001923 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001924 const char *action;
1925 const char *devnode;
1926
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001927 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001928 if (!udev_device)
1929 return 1;
1930
1931 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001932 if (!action)
1933 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001934
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001935 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1936 goto out;
1937
1938 if (!strcmp(action, "add")) {
1939 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001940 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001941 else if (!strcmp(action, "remove")) {
1942 devnode = udev_device_get_devnode(udev_device);
1943 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1944 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001945 weston_log("input device %s, %s removed\n",
1946 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001947 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001948 break;
1949 }
1950 }
1951
1952out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001953 udev_device_unref(udev_device);
1954
1955 return 0;
1956}
1957
1958static int
1959evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1960{
1961 struct drm_seat *master = (struct drm_seat *) seat_base;
1962 struct wl_event_loop *loop;
1963 struct weston_compositor *c = master->base.compositor;
1964 int fd;
1965
1966 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1967 if (!master->udev_monitor) {
1968 weston_log("udev: failed to create the udev monitor\n");
1969 return 0;
1970 }
1971
1972 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1973 "input", NULL);
1974
1975 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1976 weston_log("udev: failed to bind the udev monitor\n");
1977 udev_monitor_unref(master->udev_monitor);
1978 return 0;
1979 }
1980
1981 loop = wl_display_get_event_loop(c->wl_display);
1982 fd = udev_monitor_get_fd(master->udev_monitor);
1983 master->udev_monitor_source =
1984 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1985 evdev_udev_handler, master);
1986 if (!master->udev_monitor_source) {
1987 udev_monitor_unref(master->udev_monitor);
1988 return 0;
1989 }
1990
1991 return 1;
1992}
1993
1994static void
1995evdev_disable_udev_monitor(struct weston_seat *seat_base)
1996{
1997 struct drm_seat *seat = (struct drm_seat *) seat_base;
1998
1999 if (!seat->udev_monitor)
2000 return;
2001
2002 udev_monitor_unref(seat->udev_monitor);
2003 seat->udev_monitor = NULL;
2004 wl_event_source_remove(seat->udev_monitor_source);
2005 seat->udev_monitor_source = NULL;
2006}
2007
2008static void
2009drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
2010{
2011 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002012 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002013
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002014 wl_list_for_each(device, &seat->devices_list, link)
2015 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002016}
2017
2018static void
2019evdev_input_create(struct weston_compositor *c, struct udev *udev,
2020 const char *seat_id)
2021{
2022 struct drm_seat *seat;
2023
2024 seat = malloc(sizeof *seat);
2025 if (seat == NULL)
2026 return;
2027
2028 memset(seat, 0, sizeof *seat);
2029 weston_seat_init(&seat->base, c);
2030 seat->base.led_update = drm_led_update;
2031
2032 wl_list_init(&seat->devices_list);
2033 seat->seat_id = strdup(seat_id);
2034 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2035 free(seat->seat_id);
2036 free(seat);
2037 return;
2038 }
2039
2040 evdev_add_devices(udev, &seat->base);
2041
2042 c->seat = &seat->base;
2043}
2044
2045static void
2046evdev_remove_devices(struct weston_seat *seat_base)
2047{
2048 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002049 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002050
2051 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002052 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002053
Pekka Paalanend8583512012-08-03 14:39:11 +03002054 if (seat->base.seat.keyboard)
2055 notify_keyboard_focus_out(&seat->base.seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002056}
2057
2058static void
2059evdev_input_destroy(struct weston_seat *seat_base)
2060{
2061 struct drm_seat *seat = (struct drm_seat *) seat_base;
2062
2063 evdev_remove_devices(seat_base);
2064 evdev_disable_udev_monitor(&seat->base);
2065
2066 weston_seat_release(seat_base);
2067 free(seat->seat_id);
2068 free(seat);
2069}
2070
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002071static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002072drm_free_configured_output(struct drm_configured_output *output)
2073{
2074 free(output->name);
2075 free(output->mode);
2076 free(output);
2077}
2078
2079static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002080drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002081{
2082 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002083 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002084 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002085
Daniel Stone37816df2012-05-16 18:45:18 +01002086 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2087 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002088 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002089 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002090
2091 wl_event_source_remove(d->udev_drm_source);
2092 wl_event_source_remove(d->drm_source);
2093
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002094 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002095
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002096 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002097 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002098 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002099 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002100 eglReleaseThread();
2101
Matt Roper361d2ad2011-08-29 13:52:23 -07002102 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002103 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002104 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002105 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002106 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002107
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002108 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002109}
2110
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002111static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002112drm_compositor_set_modes(struct drm_compositor *compositor)
2113{
2114 struct drm_output *output;
2115 struct drm_mode *drm_mode;
2116 int ret;
2117
2118 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2119 drm_mode = (struct drm_mode *) output->base.current;
2120 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002121 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002122 &output->connector_id, 1,
2123 &drm_mode->mode_info);
2124 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002125 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002126 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002127 drm_mode->base.width, drm_mode->base.height,
2128 output->base.x, output->base.y);
2129 }
2130 }
2131}
2132
2133static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002134vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002135{
2136 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002137 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002138 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002139 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002140
2141 switch (event) {
2142 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002143 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002144 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002145 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002146 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002147 wl_display_terminate(compositor->wl_display);
2148 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002149 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002150 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002151 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002152 wl_list_for_each(seat, &compositor->seat_list, link) {
2153 evdev_add_devices(ec->udev, seat);
2154 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002155 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002156 break;
2157 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002158 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002159 wl_list_for_each(seat, &compositor->seat_list, link) {
2160 evdev_disable_udev_monitor(seat);
2161 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002162 }
2163
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002164 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002165 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002166 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002167
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002168 /* If we have a repaint scheduled (either from a
2169 * pending pageflip or the idle handler), make sure we
2170 * cancel that so we don't try to pageflip when we're
2171 * vt switched away. The SLEEPING state will prevent
2172 * further attemps at repainting. When we switch
2173 * back, we schedule a repaint, which will process
2174 * pending frame callbacks. */
2175
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002176 wl_list_for_each(output, &ec->base.output_list, base.link) {
2177 output->base.repaint_needed = 0;
2178 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002179 }
2180
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002181 output = container_of(ec->base.output_list.next,
2182 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002183
2184 wl_list_for_each(sprite, &ec->sprite_list, link)
2185 drmModeSetPlane(ec->drm.fd,
2186 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002187 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002188 0, 0, 0, 0, 0, 0, 0, 0);
2189
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002190 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002191 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002192
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002193 break;
2194 };
2195}
2196
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002197static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002198switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002199{
2200 struct drm_compositor *ec = data;
2201
Daniel Stone325fc2d2012-05-30 16:31:58 +01002202 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002203}
2204
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002205static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002206drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002207 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002208 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002209{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002210 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002212 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002213 struct udev_device *device, *drm_device;
2214 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002215 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002216 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002217 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002218
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002219 weston_log("initializing drm backend\n");
2220
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002221 ec = malloc(sizeof *ec);
2222 if (ec == NULL)
2223 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002224 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002225
2226 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002227 config_file) < 0) {
2228 weston_log("weston_compositor_init failed\n");
2229 goto err_base;
2230 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002231
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002232 ec->udev = udev_new();
2233 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002234 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002235 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002236 }
2237
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002238 ec->base.wl_display = display;
2239 ec->tty = tty_create(&ec->base, vt_func, tty);
2240 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002241 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002242 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002243 }
2244
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002245 e = udev_enumerate_new(ec->udev);
2246 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002247 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002248
Benjamin Franzke117483d2011-08-30 11:38:26 +02002249 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002250 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002251 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002252 path = udev_list_entry_get_name(entry);
2253 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002254 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002255 udev_device_get_property_value(device, "ID_SEAT");
2256 if (!device_seat)
2257 device_seat = default_seat;
2258 if (strcmp(device_seat, seat) == 0) {
2259 drm_device = device;
2260 break;
2261 }
2262 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002263 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002264
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002265 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002266 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002267 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002268 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002269
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002270 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002271 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002272 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002273 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002274
2275 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002276 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002277
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002278 ec->base.focus = 1;
2279
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002280 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002281
Daniel Stone725c2c32012-06-22 14:04:36 +01002282 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002283 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002284
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002285 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002286 weston_compositor_add_key_binding(&ec->base, key,
2287 MODIFIER_CTRL | MODIFIER_ALT,
2288 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002289
Jesse Barnes58ef3792012-02-23 09:45:49 -05002290 wl_list_init(&ec->sprite_list);
2291 create_sprites(ec);
2292
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002293 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002294 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002295 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002296 }
2297
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002298 path = NULL;
2299
Tiago Vignattice03ec32011-12-19 01:14:03 +02002300 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002301
2302 loop = wl_display_get_event_loop(ec->base.wl_display);
2303 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002304 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002305 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002306
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002307 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2308 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002309 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002310 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002311 }
2312 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2313 "drm", NULL);
2314 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002315 wl_event_loop_add_fd(loop,
2316 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002317 WL_EVENT_READABLE, udev_drm_event, ec);
2318
2319 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002320 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002321 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002322 }
2323
Daniel Stonea96b93c2012-06-22 14:04:37 +01002324 udev_device_unref(drm_device);
2325 udev_enumerate_unref(e);
2326
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002327 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002328
2329err_udev_monitor:
2330 wl_event_source_remove(ec->udev_drm_source);
2331 udev_monitor_unref(ec->udev_monitor);
2332err_drm_source:
2333 wl_event_source_remove(ec->drm_source);
2334 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2335 evdev_input_destroy(weston_seat);
2336err_sprite:
2337 destroy_sprites(ec);
2338err_egl:
2339 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2340 EGL_NO_CONTEXT);
2341 eglTerminate(ec->base.egl_display);
2342 eglReleaseThread();
2343 gbm_device_destroy(ec->gbm);
2344err_udev_dev:
2345 udev_device_unref(drm_device);
2346err_udev_enum:
2347 udev_enumerate_unref(e);
2348 tty_destroy(ec->tty);
2349err_udev:
2350 udev_unref(ec->udev);
2351err_compositor:
2352 weston_compositor_shutdown(&ec->base);
2353err_base:
2354 free(ec);
2355 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002356}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002357
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002358static int
2359set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2360{
2361 mode->flags = 0;
2362
2363 if (strcmp(hsync, "+hsync") == 0)
2364 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2365 else if (strcmp(hsync, "-hsync") == 0)
2366 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2367 else
2368 return -1;
2369
2370 if (strcmp(vsync, "+vsync") == 0)
2371 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2372 else if (strcmp(vsync, "-vsync") == 0)
2373 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2374 else
2375 return -1;
2376
2377 return 0;
2378}
2379
2380static int
2381check_for_modeline(struct drm_configured_output *output)
2382{
2383 drmModeModeInfo mode;
2384 char hsync[16];
2385 char vsync[16];
2386 char mode_name[16];
2387 float fclock;
2388
2389 mode.type = DRM_MODE_TYPE_USERDEF;
2390 mode.hskew = 0;
2391 mode.vscan = 0;
2392 mode.vrefresh = 0;
2393
2394 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2395 &fclock, &mode.hdisplay,
2396 &mode.hsync_start,
2397 &mode.hsync_end, &mode.htotal,
2398 &mode.vdisplay,
2399 &mode.vsync_start,
2400 &mode.vsync_end, &mode.vtotal,
2401 hsync, vsync) == 11) {
2402 if (set_sync_flags(&mode, hsync, vsync))
2403 return -1;
2404
2405 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2406 strcpy(mode.name, mode_name);
2407
2408 mode.clock = fclock * 1000;
2409 } else
2410 return -1;
2411
2412 output->crtc_mode = mode;
2413
2414 return 0;
2415}
2416
Scott Moreau8ab5d452012-07-30 19:51:08 -06002417static void
2418output_section_done(void *data)
2419{
2420 struct drm_configured_output *output;
2421
2422 output = malloc(sizeof *output);
2423
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002424 if (!output || !output_name || !output_mode) {
2425 free(output_name);
2426 output_name = NULL;
2427 free(output_mode);
2428 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002429 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002430 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002431
2432 output->config = OUTPUT_CONFIG_INVALID;
2433 output->name = output_name;
2434 output->mode = output_mode;
2435
2436 if (strcmp(output_mode, "off") == 0)
2437 output->config = OUTPUT_CONFIG_OFF;
2438 else if (strcmp(output_mode, "preferred") == 0)
2439 output->config = OUTPUT_CONFIG_PREFERRED;
2440 else if (strcmp(output_mode, "current") == 0)
2441 output->config = OUTPUT_CONFIG_CURRENT;
2442 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2443 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002444 else if (check_for_modeline(output) == 0)
2445 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002446
2447 if (output->config != OUTPUT_CONFIG_INVALID)
2448 wl_list_insert(&configured_output_list, &output->link);
2449 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002450 weston_log("Invalid mode \"%s\" for output %s\n",
2451 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002452 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002453 }
2454}
2455
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002456WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002457backend_init(struct wl_display *display, int argc, char *argv[],
2458 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002459{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002460 int connector = 0, tty = 0;
2461 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002462
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002463 const struct weston_option drm_options[] = {
2464 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2465 { WESTON_OPTION_STRING, "seat", 0, &seat },
2466 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002467 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002468 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002469
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002470 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002471
Scott Moreau8ab5d452012-07-30 19:51:08 -06002472 wl_list_init(&configured_output_list);
2473
2474 const struct config_key drm_config_keys[] = {
2475 { "name", CONFIG_KEY_STRING, &output_name },
2476 { "mode", CONFIG_KEY_STRING, &output_mode },
2477 };
2478
2479 const struct config_section config_section[] = {
2480 { "output", drm_config_keys,
2481 ARRAY_LENGTH(drm_config_keys), output_section_done },
2482 };
2483
2484 parse_config_file(config_file, config_section,
2485 ARRAY_LENGTH(config_section), NULL);
2486
Daniel Stonec1be8e52012-06-01 11:14:02 -04002487 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2488 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002489}