blob: fc216bf562eca39719d63befe4601155d2cc73b4 [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 */
96 uint32_t min_width, max_width;
97 uint32_t min_height, max_height;
98
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;
Rob Clark4339add2012-08-09 14:18:28 -0500554 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500555 int ret;
556
557 wl_list_for_each(s, &c->sprite_list, link) {
558 if (s->pending_fb_id)
559 continue;
560
561 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
562 output->crtc_id, 0, 0,
563 0, 0, 0, 0, 0, 0, 0, 0);
564 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200565 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500566 ret, strerror(errno));
567 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300568
569 if (s->surface) {
570 s->surface = NULL;
571 wl_list_remove(&s->destroy_listener.link);
572 }
573
574 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500575 s->fb_id = 0;
576 s->pending_fb_id = 0;
577 }
578}
579
580/*
581 * This function must take care to damage any previously assigned surface
582 * if the sprite ends up binding to a different surface than in the
583 * previous frame.
584 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400585static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400587 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588{
589 struct weston_compositor *ec = output_base->compositor;
590 struct drm_compositor *c =(struct drm_compositor *) ec;
591 struct drm_sprite *s;
592 int found = 0;
593 EGLint handle, stride;
594 struct gbm_bo *bo;
595 uint32_t fb_id = 0;
596 uint32_t handles[4], pitches[4], offsets[4];
597 int ret = 0;
598 pixman_region32_t dest_rect, src_rect;
599 pixman_box32_t *box;
600 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400601 wl_fixed_t sx1, sy1, sx2, sy2;
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)
640 return -1;
641
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øgsberga6edab32012-07-14 01:06:28 -0400735 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400736
737 if (output->cursor_surface)
738 return NULL;
739 if (es->output_mask != (1u << output_base->id))
740 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500741 if (c->cursors_are_broken)
742 return;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400743 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
744 es->geometry.width > 64 || es->geometry.height > 64)
745 return NULL;
746
747 output->cursor_surface = es;
748
749 return &output->cursor_plane;
750}
751
752static void
753drm_output_set_cursor(struct drm_output *output)
754{
755 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400756 struct drm_compositor *c =
757 (struct drm_compositor *) output->base.compositor;
758 EGLint handle, stride;
759 struct gbm_bo *bo;
760 uint32_t buf[64 * 64];
761 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400762 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500763
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400764 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400765 if (es == NULL) {
766 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
767 return;
768 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500769
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400770 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
771 pixman_region32_fini(&output->cursor_plane.damage);
772 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400773 output->current_cursor ^= 1;
774 bo = output->cursor_bo[output->current_cursor];
775 memset(buf, 0, sizeof buf);
776 stride = wl_shm_buffer_get_stride(es->buffer);
777 s = wl_shm_buffer_get_data(es->buffer);
778 for (i = 0; i < es->geometry.height; i++)
779 memcpy(buf + i * 64, s + i * stride,
780 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500781
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400782 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300783 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400784
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400785 handle = gbm_bo_get_handle(bo).s32;
786 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500787 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300788 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500789 c->cursors_are_broken = 1;
790 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400791 }
792
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400793 x = es->geometry.x - output->base.x;
794 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400795 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500796 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400797 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500798 c->cursors_are_broken = 1;
799 }
800
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400801 output->cursor_plane.x = x;
802 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400803 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500804}
805
Jesse Barnes58ef3792012-02-23 09:45:49 -0500806static void
807drm_assign_planes(struct weston_output *output)
808{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400809 struct drm_compositor *c =
810 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400811 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400813 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814
815 /*
816 * Find a surface for each sprite in the output using some heuristics:
817 * 1) size
818 * 2) frequency of update
819 * 3) opacity (though some hw might support alpha blending)
820 * 4) clipping (this can be fixed with color keys)
821 *
822 * The idea is to save on blitting since this should save power.
823 * If we can get a large video surface on the sprite for example,
824 * the main display surface may not need to update at all, and
825 * the client buffer can be used directly for the sprite surface
826 * as we do for flipping full screen surfaces.
827 */
828 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400829 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400830 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831 pixman_region32_init(&surface_overlap);
832 pixman_region32_intersect(&surface_overlap, &overlap,
833 &es->transform.boundingbox);
834
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400836 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400837 next_plane = primary;
838 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400839 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400840 if (next_plane == NULL)
841 next_plane = drm_output_prepare_scanout_surface(output, es);
842 if (next_plane == NULL)
843 next_plane = drm_output_prepare_overlay_surface(output, es);
844 if (next_plane == NULL)
845 next_plane = primary;
846 weston_surface_move_to_plane(es, next_plane);
847 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500848 pixman_region32_union(&overlap, &overlap,
849 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400850
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851 pixman_region32_fini(&surface_overlap);
852 }
853 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500854}
855
Matt Roper361d2ad2011-08-29 13:52:23 -0700856static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500857drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700858{
859 struct drm_output *output = (struct drm_output *) output_base;
860 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200861 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700862 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700863
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200864 if (output->backlight)
865 backlight_destroy(output->backlight);
866
Matt Roper361d2ad2011-08-29 13:52:23 -0700867 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400868 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700869
870 /* Restore original CRTC state */
871 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200872 origcrtc->x, origcrtc->y,
873 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700874 drmModeFreeCrtc(origcrtc);
875
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200876 c->crtc_allocator &= ~(1 << output->crtc_id);
877 c->connector_allocator &= ~(1 << output->connector_id);
878
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400879 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400880 gbm_surface_destroy(output->surface);
881
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400882 weston_plane_release(&output->fb_plane);
883 weston_plane_release(&output->cursor_plane);
884
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500885 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200886 wl_list_remove(&output->base.link);
887
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400888 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700889 free(output);
890}
891
Alex Wub7b8bda2012-04-17 17:20:48 +0800892static struct drm_mode *
893choose_mode (struct drm_output *output, struct weston_mode *target_mode)
894{
895 struct drm_mode *tmp_mode = NULL, *mode;
896
897 if (output->base.current->width == target_mode->width &&
898 output->base.current->height == target_mode->height &&
899 (output->base.current->refresh == target_mode->refresh ||
900 target_mode->refresh == 0))
901 return (struct drm_mode *)output->base.current;
902
903 wl_list_for_each(mode, &output->base.mode_list, base.link) {
904 if (mode->mode_info.hdisplay == target_mode->width &&
905 mode->mode_info.vdisplay == target_mode->height) {
906 if (mode->mode_info.vrefresh == target_mode->refresh ||
907 target_mode->refresh == 0) {
908 return mode;
909 } else if (!tmp_mode)
910 tmp_mode = mode;
911 }
912 }
913
914 return tmp_mode;
915}
916
917static int
918drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
919{
920 struct drm_output *output;
921 struct drm_mode *drm_mode;
922 int ret;
923 struct drm_compositor *ec;
924 struct gbm_surface *surface;
925 EGLSurface egl_surface;
926
927 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200928 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800929 return -1;
930 }
931
932 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200933 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800934 return -1;
935 }
936
937 ec = (struct drm_compositor *)output_base->compositor;
938 output = (struct drm_output *)output_base;
939 drm_mode = choose_mode (output, mode);
940
941 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200942 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800943 return -1;
944 } else if (&drm_mode->base == output->base.current) {
945 return 0;
946 } else if (drm_mode->base.width == output->base.current->width &&
947 drm_mode->base.height == output->base.current->height) {
948 /* only change refresh value */
949 ret = drmModeSetCrtc(ec->drm.fd,
950 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300951 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800952 &output->connector_id, 1, &drm_mode->mode_info);
953
954 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200955 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800956 drm_mode->base.width,
957 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400958 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800959 ret = -1;
960 } else {
961 output->base.current->flags = 0;
962 output->base.current = &drm_mode->base;
963 drm_mode->base.flags =
964 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
965 ret = 0;
966 }
967
968 return ret;
969 }
970
971 drm_mode->base.flags =
972 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
973
974 surface = gbm_surface_create(ec->gbm,
975 drm_mode->base.width,
976 drm_mode->base.height,
977 GBM_FORMAT_XRGB8888,
978 GBM_BO_USE_SCANOUT |
979 GBM_BO_USE_RENDERING);
980 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200981 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800982 return -1;
983 }
984
985 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400986 eglCreateWindowSurface(ec->base.egl_display,
987 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800988 surface, NULL);
989
990 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200991 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800992 goto err;
993 }
994
995 ret = drmModeSetCrtc(ec->drm.fd,
996 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300997 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800998 &output->connector_id, 1, &drm_mode->mode_info);
999 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001000 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001001 goto err;
1002 }
1003
1004 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001005 if (output->current) {
1006 if (output->current->is_client_buffer)
1007 gbm_bo_destroy(output->current->bo);
1008 else
1009 gbm_surface_release_buffer(output->surface,
1010 output->current->bo);
1011 }
1012 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001013
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001014 if (output->next) {
1015 if (output->next->is_client_buffer)
1016 gbm_bo_destroy(output->next->bo);
1017 else
1018 gbm_surface_release_buffer(output->surface,
1019 output->next->bo);
1020 }
1021 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001022
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001023 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001024 gbm_surface_destroy(output->surface);
1025 output->egl_surface = egl_surface;
1026 output->surface = surface;
1027
1028 /*update output*/
1029 output->base.current = &drm_mode->base;
1030 output->base.dirty = 1;
1031 weston_output_move(&output->base, output->base.x, output->base.y);
1032 return 0;
1033
1034err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001035 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001036 gbm_surface_destroy(surface);
1037 return -1;
1038}
1039
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001040static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001041on_drm_input(int fd, uint32_t mask, void *data)
1042{
1043 drmEventContext evctx;
1044
1045 memset(&evctx, 0, sizeof evctx);
1046 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1047 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001048 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001049 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001050
1051 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001052}
1053
1054static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001055init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001056{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001057 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001058 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001059 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001060 static const EGLint context_attribs[] = {
1061 EGL_CONTEXT_CLIENT_VERSION, 2,
1062 EGL_NONE
1063 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001064
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001065 static const EGLint config_attribs[] = {
1066 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1067 EGL_RED_SIZE, 1,
1068 EGL_GREEN_SIZE, 1,
1069 EGL_BLUE_SIZE, 1,
1070 EGL_ALPHA_SIZE, 0,
1071 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1072 EGL_NONE
1073 };
1074
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001075 sysnum = udev_device_get_sysnum(device);
1076 if (sysnum)
1077 ec->drm.id = atoi(sysnum);
1078 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001079 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001080 return -1;
1081 }
1082
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001083 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001084 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001085 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001086 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001087 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001088 udev_device_get_devnode(device));
1089 return -1;
1090 }
1091
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001092 weston_log("using %s\n", filename);
1093
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001094 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001095 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001096 ec->base.egl_display = eglGetDisplay(ec->gbm);
1097 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001098 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001099 return -1;
1100 }
1101
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001102 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001103 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001104 return -1;
1105 }
1106
Darxus55973f22010-11-22 21:24:39 -05001107 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001108 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001109 return -1;
1110 }
1111
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001112 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1113 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001114 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001115 return -1;
1116 }
1117
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001118 ec->base.egl_context =
1119 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1120 EGL_NO_CONTEXT, context_attribs);
1121 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001122 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001123 return -1;
1124 }
1125
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001126 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1127 GBM_FORMAT_XRGB8888,
1128 GBM_BO_USE_RENDERING);
1129 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001130 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001131 return -1;
1132 }
1133
1134 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001135 eglCreateWindowSurface(ec->base.egl_display,
1136 ec->base.egl_config,
1137 ec->dummy_surface,
1138 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001139 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001140 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001141 return -1;
1142 }
1143
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001144 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1145 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001146 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001147 return -1;
1148 }
1149
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001150 return 0;
1151}
1152
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001153static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001154drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1155{
1156 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001157 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001158
1159 mode = malloc(sizeof *mode);
1160 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001161 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001162
1163 mode->base.flags = 0;
1164 mode->base.width = info->hdisplay;
1165 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001166
1167 /* Calculate higher precision (mHz) refresh rate */
1168 refresh = (info->clock * 1000000LL / info->htotal +
1169 info->vtotal / 2) / info->vtotal;
1170
1171 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1172 refresh *= 2;
1173 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1174 refresh /= 2;
1175 if (info->vscan > 1)
1176 refresh /= info->vscan;
1177
1178 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001179 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001180
1181 if (info->type & DRM_MODE_TYPE_PREFERRED)
1182 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1183
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001184 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1185
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001186 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001187}
1188
1189static int
1190drm_subpixel_to_wayland(int drm_value)
1191{
1192 switch (drm_value) {
1193 default:
1194 case DRM_MODE_SUBPIXEL_UNKNOWN:
1195 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1196 case DRM_MODE_SUBPIXEL_NONE:
1197 return WL_OUTPUT_SUBPIXEL_NONE;
1198 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1199 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1200 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1201 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1202 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1203 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1204 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1205 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1206 }
1207}
1208
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001209static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001210sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001211{
1212 struct drm_sprite *sprite =
1213 container_of(listener, struct drm_sprite,
1214 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001215 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001216
1217 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001218 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1219 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001220}
1221
1222static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001223sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001224{
1225 struct drm_sprite *sprite =
1226 container_of(listener, struct drm_sprite,
1227 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001228 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001229
1230 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001231 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1232 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001233}
1234
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001235/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001236static uint32_t
1237drm_get_backlight(struct drm_output *output)
1238{
1239 long brightness, max_brightness, norm;
1240
1241 brightness = backlight_get_brightness(output->backlight);
1242 max_brightness = backlight_get_max_brightness(output->backlight);
1243
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001244 /* convert it on a scale of 0 to 255 */
1245 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001246
1247 return (uint32_t) norm;
1248}
1249
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001250/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001251static void
1252drm_set_backlight(struct weston_output *output_base, uint32_t value)
1253{
1254 struct drm_output *output = (struct drm_output *) output_base;
1255 long max_brightness, new_brightness;
1256
1257 if (!output->backlight)
1258 return;
1259
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001260 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001261 return;
1262
1263 max_brightness = backlight_get_max_brightness(output->backlight);
1264
1265 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001266 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001267
1268 backlight_set_brightness(output->backlight, new_brightness);
1269}
1270
1271static drmModePropertyPtr
1272drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1273{
1274 drmModePropertyPtr props;
1275 int i;
1276
1277 for (i = 0; i < connector->count_props; i++) {
1278 props = drmModeGetProperty(fd, connector->props[i]);
1279 if (!props)
1280 continue;
1281
1282 if (!strcmp(props->name, name))
1283 return props;
1284
1285 drmModeFreeProperty(props);
1286 }
1287
1288 return NULL;
1289}
1290
1291static void
1292drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1293{
1294 struct drm_output *output = (struct drm_output *) output_base;
1295 struct weston_compositor *ec = output_base->compositor;
1296 struct drm_compositor *c = (struct drm_compositor *) ec;
1297 drmModeConnectorPtr connector;
1298 drmModePropertyPtr prop;
1299
1300 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1301 if (!connector)
1302 return;
1303
1304 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1305 if (!prop) {
1306 drmModeFreeConnector(connector);
1307 return;
1308 }
1309
1310 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1311 prop->prop_id, level);
1312 drmModeFreeProperty(prop);
1313 drmModeFreeConnector(connector);
1314}
1315
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001316static const char *connector_type_names[] = {
1317 "None",
1318 "VGA",
1319 "DVI",
1320 "DVI",
1321 "DVI",
1322 "Composite",
1323 "TV",
1324 "LVDS",
1325 "CTV",
1326 "DIN",
1327 "DP",
1328 "HDMI",
1329 "HDMI",
1330 "TV",
1331 "eDP",
1332};
1333
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001334static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001335find_crtc_for_connector(struct drm_compositor *ec,
1336 drmModeRes *resources, drmModeConnector *connector)
1337{
1338 drmModeEncoder *encoder;
1339 uint32_t possible_crtcs;
1340 int i, j;
1341
1342 for (j = 0; j < connector->count_encoders; j++) {
1343 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1344 if (encoder == NULL) {
1345 weston_log("Failed to get encoder.\n");
1346 return -1;
1347 }
1348 possible_crtcs = encoder->possible_crtcs;
1349 drmModeFreeEncoder(encoder);
1350
1351 for (i = 0; i < resources->count_crtcs; i++) {
1352 if (possible_crtcs & (1 << i) &&
1353 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1354 return i;
1355 }
1356 }
1357
1358 return -1;
1359}
1360
1361static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001362create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001363 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001364 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001365 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001366{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001367 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001368 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1369 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001370 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001371 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001372 drmModeModeInfo crtc_mode;
1373 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001374 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001375 char name[32];
1376 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001377
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001378 i = find_crtc_for_connector(ec, resources, connector);
1379 if (i < 0) {
1380 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001381 return -1;
1382 }
1383
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001384 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001385 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001386 return -1;
1387
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001388 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001389 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1390 output->base.make = "unknown";
1391 output->base.model = "unknown";
1392 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001393
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001394 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1395 type_name = connector_type_names[connector->connector_type];
1396 else
1397 type_name = "UNKNOWN";
1398 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1399 output->name = strdup(name);
1400
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001401 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001402 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001403 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001404 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001405 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001406
Matt Roper361d2ad2011-08-29 13:52:23 -07001407 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1408
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001409 /* Get the current mode on the crtc that's currently driving
1410 * this connector. */
1411 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001412 memset(&crtc_mode, 0, sizeof crtc_mode);
1413 if (encoder != NULL) {
1414 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1415 drmModeFreeEncoder(encoder);
1416 if (crtc == NULL)
1417 goto err_free;
1418 if (crtc->mode_valid)
1419 crtc_mode = crtc->mode;
1420 drmModeFreeCrtc(crtc);
1421 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001422
David Herrmann0f0d54e2011-12-08 17:05:45 +01001423 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001424 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1425 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001426 goto err_free;
1427 }
1428
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001429 preferred = NULL;
1430 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001431 configured = NULL;
1432
1433 wl_list_for_each(temp, &configured_output_list, link) {
1434 if (strcmp(temp->name, output->name) == 0) {
1435 weston_log("%s mode \"%s\" in config\n",
1436 temp->name, temp->mode);
1437 o = temp;
1438 break;
1439 }
1440 }
1441
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001442 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001443 weston_log("Disabling output %s\n", o->name);
1444
1445 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1446 0, 0, 0, 0, 0, NULL);
1447 goto err_free;
1448 }
1449
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001450 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001451 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001452 o->height == drm_mode->base.height &&
1453 o->config == OUTPUT_CONFIG_MODE)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001454 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001455 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001456 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001457 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001458 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001459 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001460
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001461 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001462 configured = drm_output_add_mode(output, &o->crtc_mode);
1463 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001464 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001465 current = configured;
1466 }
1467
Wang Quanxianacb805a2012-07-30 18:09:46 -04001468 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001469 current = drm_output_add_mode(output, &crtc_mode);
1470 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001471 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001472 }
1473
Scott Moreau8ab5d452012-07-30 19:51:08 -06001474 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1475 configured = current;
1476
Wang Quanxianacb805a2012-07-30 18:09:46 -04001477 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001478 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001479 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001480 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001481 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001482 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001483 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001484 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001485
1486 if (output->base.current == NULL) {
1487 weston_log("no available modes for %s\n", output->name);
1488 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001489 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001490
Wang Quanxianacb805a2012-07-30 18:09:46 -04001491 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1492
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001493 output->surface = gbm_surface_create(ec->gbm,
1494 output->base.current->width,
1495 output->base.current->height,
1496 GBM_FORMAT_XRGB8888,
1497 GBM_BO_USE_SCANOUT |
1498 GBM_BO_USE_RENDERING);
1499 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001500 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001501 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001502 }
1503
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001504 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001505 eglCreateWindowSurface(ec->base.egl_display,
1506 ec->base.egl_config,
1507 output->surface,
1508 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001509 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001510 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001511 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001512 }
1513
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001514 output->cursor_bo[0] =
1515 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1516 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1517 output->cursor_bo[1] =
1518 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1519 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1520
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001521 output->backlight = backlight_init(drm_device,
1522 connector->connector_type);
1523 if (output->backlight) {
1524 output->base.set_backlight = drm_set_backlight;
1525 output->base.backlight_current = drm_get_backlight(output);
1526 }
1527
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001528 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001529 connector->mmWidth, connector->mmHeight,
1530 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001531
1532 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1533
Alex Wubd3354b2012-04-17 17:20:49 +08001534 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001535 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001536 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001537 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001538 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001539 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001540
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001541 weston_plane_init(&output->cursor_plane, 0, 0);
1542 weston_plane_init(&output->fb_plane, 0, 0);
1543
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001544 weston_log("Output %s, (connector %d, crtc %d)\n",
1545 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001546 wl_list_for_each(m, &output->base.mode_list, link)
1547 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1548 m->width, m->height, m->refresh / 1000.0,
1549 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1550 ", preferred" : "",
1551 m->flags & WL_OUTPUT_MODE_CURRENT ?
1552 ", current" : "",
1553 connector->count_modes == 0 ?
1554 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001555
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001556 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001557
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001558err_surface:
1559 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001560err_free:
1561 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1562 base.link) {
1563 wl_list_remove(&drm_mode->base.link);
1564 free(drm_mode);
1565 }
1566
1567 drmModeFreeCrtc(output->original_crtc);
1568 ec->crtc_allocator &= ~(1 << output->crtc_id);
1569 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001570 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001571 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001572
David Herrmann0f0d54e2011-12-08 17:05:45 +01001573 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001574}
1575
Jesse Barnes58ef3792012-02-23 09:45:49 -05001576static void
1577create_sprites(struct drm_compositor *ec)
1578{
1579 struct drm_sprite *sprite;
1580 drmModePlaneRes *plane_res;
1581 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001582 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001583
1584 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1585 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001586 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001587 strerror(errno));
1588 return;
1589 }
1590
1591 for (i = 0; i < plane_res->count_planes; i++) {
1592 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1593 if (!plane)
1594 continue;
1595
1596 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1597 plane->count_formats));
1598 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001599 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001600 __func__);
1601 free(plane);
1602 continue;
1603 }
1604
1605 memset(sprite, 0, sizeof *sprite);
1606
1607 sprite->possible_crtcs = plane->possible_crtcs;
1608 sprite->plane_id = plane->plane_id;
1609 sprite->surface = NULL;
1610 sprite->pending_surface = NULL;
1611 sprite->fb_id = 0;
1612 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001613 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1614 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001615 sprite_handle_pending_buffer_destroy;
1616 sprite->compositor = ec;
1617 sprite->count_formats = plane->count_formats;
1618 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001619 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001620 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001621 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001622
1623 wl_list_insert(&ec->sprite_list, &sprite->link);
1624 }
1625
1626 free(plane_res->planes);
1627 free(plane_res);
1628}
1629
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001630static void
1631destroy_sprites(struct drm_compositor *compositor)
1632{
1633 struct drm_sprite *sprite, *next;
1634 struct drm_output *output;
1635
1636 output = container_of(compositor->base.output_list.next,
1637 struct drm_output, base.link);
1638
1639 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1640 drmModeSetPlane(compositor->drm.fd,
1641 sprite->plane_id,
1642 output->crtc_id, 0, 0,
1643 0, 0, 0, 0, 0, 0, 0, 0);
1644 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001645 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001646 free(sprite);
1647 }
1648}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001649
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001650static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001651create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001652 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001653{
1654 drmModeConnector *connector;
1655 drmModeRes *resources;
1656 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001657 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001658
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001659 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001660 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001661 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001662 return -1;
1663 }
1664
Jesse Barnes58ef3792012-02-23 09:45:49 -05001665 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001666 if (!ec->crtcs) {
1667 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001668 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001669 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001670
Rob Clark4339add2012-08-09 14:18:28 -05001671 ec->min_width = resources->min_width;
1672 ec->max_width = resources->max_width;
1673 ec->min_height = resources->min_height;
1674 ec->max_height = resources->max_height;
1675
Jesse Barnes58ef3792012-02-23 09:45:49 -05001676 ec->num_crtcs = resources->count_crtcs;
1677 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1678
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001679 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001680 connector = drmModeGetConnector(ec->drm.fd,
1681 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001682 if (connector == NULL)
1683 continue;
1684
1685 if (connector->connection == DRM_MODE_CONNECTED &&
1686 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001687 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001688 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001689 connector, x, y,
1690 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001691 drmModeFreeConnector(connector);
1692 continue;
1693 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001694
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001695 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001696 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001697 link)->current->width;
1698 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001699
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001700 drmModeFreeConnector(connector);
1701 }
1702
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001703 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001704 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001705 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001706 return -1;
1707 }
1708
1709 drmModeFreeResources(resources);
1710
1711 return 0;
1712}
1713
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001714static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001715update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001716{
1717 drmModeConnector *connector;
1718 drmModeRes *resources;
1719 struct drm_output *output, *next;
1720 int x = 0, y = 0;
1721 int x_offset = 0, y_offset = 0;
1722 uint32_t connected = 0, disconnects = 0;
1723 int i;
1724
1725 resources = drmModeGetResources(ec->drm.fd);
1726 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001727 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001728 return;
1729 }
1730
1731 /* collect new connects */
1732 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001733 int connector_id = resources->connectors[i];
1734
1735 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001736 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001737 continue;
1738
David Herrmann7551cff2011-12-08 17:05:43 +01001739 if (connector->connection != DRM_MODE_CONNECTED) {
1740 drmModeFreeConnector(connector);
1741 continue;
1742 }
1743
Benjamin Franzke117483d2011-08-30 11:38:26 +02001744 connected |= (1 << connector_id);
1745
1746 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001747 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001748 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001749 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001750
1751 /* XXX: not yet needed, we die with 0 outputs */
1752 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001753 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001754 else
1755 x = 0;
1756 y = 0;
1757 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001758 connector, x, y,
1759 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001760 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001761
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001762 }
1763 drmModeFreeConnector(connector);
1764 }
1765 drmModeFreeResources(resources);
1766
1767 disconnects = ec->connector_allocator & ~connected;
1768 if (disconnects) {
1769 wl_list_for_each_safe(output, next, &ec->base.output_list,
1770 base.link) {
1771 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001772 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001773 output->base.x - x_offset,
1774 output->base.y - y_offset);
1775 }
1776
1777 if (disconnects & (1 << output->connector_id)) {
1778 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001779 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001780 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001781 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001782 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001783 }
1784 }
1785 }
1786
1787 /* FIXME: handle zero outputs, without terminating */
1788 if (ec->connector_allocator == 0)
1789 wl_display_terminate(ec->base.wl_display);
1790}
1791
1792static int
David Herrmannd7488c22012-03-11 20:05:21 +01001793udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001794{
David Herrmannd7488c22012-03-11 20:05:21 +01001795 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001796 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001797
1798 sysnum = udev_device_get_sysnum(device);
1799 if (!sysnum || atoi(sysnum) != ec->drm.id)
1800 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001801
David Herrmann6ac52db2012-03-11 20:05:22 +01001802 val = udev_device_get_property_value(device, "HOTPLUG");
1803 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001804 return 0;
1805
David Herrmann6ac52db2012-03-11 20:05:22 +01001806 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001807}
1808
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001809static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001810udev_drm_event(int fd, uint32_t mask, void *data)
1811{
1812 struct drm_compositor *ec = data;
1813 struct udev_device *event;
1814
1815 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001816
David Herrmannd7488c22012-03-11 20:05:21 +01001817 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001818 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001819
1820 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001821
1822 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001823}
1824
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001825static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001826drm_restore(struct weston_compositor *ec)
1827{
1828 struct drm_compositor *d = (struct drm_compositor *) ec;
1829
1830 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1831 weston_log("failed to drop master: %m\n");
1832 tty_reset(d->tty);
1833}
1834
Pekka Paalanen33156972012-08-03 13:30:30 -04001835static const char default_seat[] = "seat0";
1836
1837static void
1838device_added(struct udev_device *udev_device, struct drm_seat *master)
1839{
1840 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001841 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001842 const char *devnode;
1843 const char *device_seat;
1844 int fd;
1845
1846 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1847 if (!device_seat)
1848 device_seat = default_seat;
1849
1850 if (strcmp(device_seat, master->seat_id))
1851 return;
1852
1853 c = master->base.compositor;
1854 devnode = udev_device_get_devnode(udev_device);
1855
1856 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001857 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001858 * read. mtdev_get() also expects this. */
1859 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1860 if (fd < 0) {
1861 weston_log("opening input device '%s' failed.\n", devnode);
1862 return;
1863 }
1864
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001865 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001866 if (!device) {
1867 close(fd);
1868 weston_log("not using input device '%s'.\n", devnode);
1869 return;
1870 }
1871
1872 wl_list_insert(master->devices_list.prev, &device->link);
1873}
1874
1875static void
1876evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1877{
1878 struct drm_seat *seat = (struct drm_seat *) seat_base;
1879 struct udev_enumerate *e;
1880 struct udev_list_entry *entry;
1881 struct udev_device *device;
1882 const char *path, *sysname;
1883
1884 e = udev_enumerate_new(udev);
1885 udev_enumerate_add_match_subsystem(e, "input");
1886 udev_enumerate_scan_devices(e);
1887 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1888 path = udev_list_entry_get_name(entry);
1889 device = udev_device_new_from_syspath(udev, path);
1890
1891 sysname = udev_device_get_sysname(device);
1892 if (strncmp("event", sysname, 5) != 0) {
1893 udev_device_unref(device);
1894 continue;
1895 }
1896
1897 device_added(device, seat);
1898
1899 udev_device_unref(device);
1900 }
1901 udev_enumerate_unref(e);
1902
1903 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1904
1905 if (wl_list_empty(&seat->devices_list)) {
1906 weston_log(
1907 "warning: no input devices on entering Weston. "
1908 "Possible causes:\n"
1909 "\t- no permissions to read /dev/input/event*\n"
1910 "\t- seats misconfigured "
1911 "(Weston backend option 'seat', "
1912 "udev device property ID_SEAT)\n");
1913 }
1914}
1915
1916static int
1917evdev_udev_handler(int fd, uint32_t mask, void *data)
1918{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001919 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001920 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001921 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001922 const char *action;
1923 const char *devnode;
1924
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001925 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001926 if (!udev_device)
1927 return 1;
1928
1929 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001930 if (!action)
1931 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001932
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001933 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1934 goto out;
1935
1936 if (!strcmp(action, "add")) {
1937 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001938 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001939 else if (!strcmp(action, "remove")) {
1940 devnode = udev_device_get_devnode(udev_device);
1941 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1942 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001943 weston_log("input device %s, %s removed\n",
1944 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001945 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001946 break;
1947 }
1948 }
1949
1950out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001951 udev_device_unref(udev_device);
1952
1953 return 0;
1954}
1955
1956static int
1957evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1958{
1959 struct drm_seat *master = (struct drm_seat *) seat_base;
1960 struct wl_event_loop *loop;
1961 struct weston_compositor *c = master->base.compositor;
1962 int fd;
1963
1964 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1965 if (!master->udev_monitor) {
1966 weston_log("udev: failed to create the udev monitor\n");
1967 return 0;
1968 }
1969
1970 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1971 "input", NULL);
1972
1973 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1974 weston_log("udev: failed to bind the udev monitor\n");
1975 udev_monitor_unref(master->udev_monitor);
1976 return 0;
1977 }
1978
1979 loop = wl_display_get_event_loop(c->wl_display);
1980 fd = udev_monitor_get_fd(master->udev_monitor);
1981 master->udev_monitor_source =
1982 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1983 evdev_udev_handler, master);
1984 if (!master->udev_monitor_source) {
1985 udev_monitor_unref(master->udev_monitor);
1986 return 0;
1987 }
1988
1989 return 1;
1990}
1991
1992static void
1993evdev_disable_udev_monitor(struct weston_seat *seat_base)
1994{
1995 struct drm_seat *seat = (struct drm_seat *) seat_base;
1996
1997 if (!seat->udev_monitor)
1998 return;
1999
2000 udev_monitor_unref(seat->udev_monitor);
2001 seat->udev_monitor = NULL;
2002 wl_event_source_remove(seat->udev_monitor_source);
2003 seat->udev_monitor_source = NULL;
2004}
2005
2006static void
2007drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
2008{
2009 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002010 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002011
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002012 wl_list_for_each(device, &seat->devices_list, link)
2013 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002014}
2015
2016static void
2017evdev_input_create(struct weston_compositor *c, struct udev *udev,
2018 const char *seat_id)
2019{
2020 struct drm_seat *seat;
2021
2022 seat = malloc(sizeof *seat);
2023 if (seat == NULL)
2024 return;
2025
2026 memset(seat, 0, sizeof *seat);
2027 weston_seat_init(&seat->base, c);
2028 seat->base.led_update = drm_led_update;
2029
2030 wl_list_init(&seat->devices_list);
2031 seat->seat_id = strdup(seat_id);
2032 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2033 free(seat->seat_id);
2034 free(seat);
2035 return;
2036 }
2037
2038 evdev_add_devices(udev, &seat->base);
2039
2040 c->seat = &seat->base;
2041}
2042
2043static void
2044evdev_remove_devices(struct weston_seat *seat_base)
2045{
2046 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002047 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002048
2049 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002050 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002051
Pekka Paalanend8583512012-08-03 14:39:11 +03002052 if (seat->base.seat.keyboard)
2053 notify_keyboard_focus_out(&seat->base.seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002054}
2055
2056static void
2057evdev_input_destroy(struct weston_seat *seat_base)
2058{
2059 struct drm_seat *seat = (struct drm_seat *) seat_base;
2060
2061 evdev_remove_devices(seat_base);
2062 evdev_disable_udev_monitor(&seat->base);
2063
2064 weston_seat_release(seat_base);
2065 free(seat->seat_id);
2066 free(seat);
2067}
2068
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002069static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002070drm_free_configured_output(struct drm_configured_output *output)
2071{
2072 free(output->name);
2073 free(output->mode);
2074 free(output);
2075}
2076
2077static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002078drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002079{
2080 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002081 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002082 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002083
Daniel Stone37816df2012-05-16 18:45:18 +01002084 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2085 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002086 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002087 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002088
2089 wl_event_source_remove(d->udev_drm_source);
2090 wl_event_source_remove(d->drm_source);
2091
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002092 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002093
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002094 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002095 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002096 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002097 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002098 eglReleaseThread();
2099
Matt Roper361d2ad2011-08-29 13:52:23 -07002100 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002101 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002102 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002103 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002104 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002105
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002106 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002107}
2108
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002109static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002110drm_compositor_set_modes(struct drm_compositor *compositor)
2111{
2112 struct drm_output *output;
2113 struct drm_mode *drm_mode;
2114 int ret;
2115
2116 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2117 drm_mode = (struct drm_mode *) output->base.current;
2118 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002119 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002120 &output->connector_id, 1,
2121 &drm_mode->mode_info);
2122 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002123 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002124 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002125 drm_mode->base.width, drm_mode->base.height,
2126 output->base.x, output->base.y);
2127 }
2128 }
2129}
2130
2131static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002132vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002133{
2134 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002135 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002136 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002137 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002138
2139 switch (event) {
2140 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002141 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002142 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002143 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002144 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002145 wl_display_terminate(compositor->wl_display);
2146 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002147 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002148 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002149 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002150 wl_list_for_each(seat, &compositor->seat_list, link) {
2151 evdev_add_devices(ec->udev, seat);
2152 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002153 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002154 break;
2155 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002156 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002157 wl_list_for_each(seat, &compositor->seat_list, link) {
2158 evdev_disable_udev_monitor(seat);
2159 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002160 }
2161
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002162 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002163 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002164 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002165
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002166 /* If we have a repaint scheduled (either from a
2167 * pending pageflip or the idle handler), make sure we
2168 * cancel that so we don't try to pageflip when we're
2169 * vt switched away. The SLEEPING state will prevent
2170 * further attemps at repainting. When we switch
2171 * back, we schedule a repaint, which will process
2172 * pending frame callbacks. */
2173
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002174 wl_list_for_each(output, &ec->base.output_list, base.link) {
2175 output->base.repaint_needed = 0;
2176 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002177 }
2178
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002179 output = container_of(ec->base.output_list.next,
2180 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002181
2182 wl_list_for_each(sprite, &ec->sprite_list, link)
2183 drmModeSetPlane(ec->drm.fd,
2184 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002185 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002186 0, 0, 0, 0, 0, 0, 0, 0);
2187
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002188 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002189 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002190
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002191 break;
2192 };
2193}
2194
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002195static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002196switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002197{
2198 struct drm_compositor *ec = data;
2199
Daniel Stone325fc2d2012-05-30 16:31:58 +01002200 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002201}
2202
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002203static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002204drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002205 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002206 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002207{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002208 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002209 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002210 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002211 struct udev_device *device, *drm_device;
2212 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002213 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002214 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002215 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002216
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002217 weston_log("initializing drm backend\n");
2218
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002219 ec = malloc(sizeof *ec);
2220 if (ec == NULL)
2221 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002222 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002223
2224 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002225 config_file) < 0) {
2226 weston_log("weston_compositor_init failed\n");
2227 goto err_base;
2228 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002229
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002230 ec->udev = udev_new();
2231 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002232 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002233 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002234 }
2235
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002236 ec->base.wl_display = display;
2237 ec->tty = tty_create(&ec->base, vt_func, tty);
2238 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002239 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002240 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002241 }
2242
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002243 e = udev_enumerate_new(ec->udev);
2244 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002245 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002246
Benjamin Franzke117483d2011-08-30 11:38:26 +02002247 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002248 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002249 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002250 path = udev_list_entry_get_name(entry);
2251 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002252 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002253 udev_device_get_property_value(device, "ID_SEAT");
2254 if (!device_seat)
2255 device_seat = default_seat;
2256 if (strcmp(device_seat, seat) == 0) {
2257 drm_device = device;
2258 break;
2259 }
2260 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002261 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002262
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002263 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002264 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002265 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002266 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002267
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002268 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002269 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002270 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002271 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002272
2273 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002274 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002275
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002276 ec->base.focus = 1;
2277
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002278 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002279
Daniel Stone725c2c32012-06-22 14:04:36 +01002280 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002281 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002282
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002283 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002284 weston_compositor_add_key_binding(&ec->base, key,
2285 MODIFIER_CTRL | MODIFIER_ALT,
2286 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002287
Jesse Barnes58ef3792012-02-23 09:45:49 -05002288 wl_list_init(&ec->sprite_list);
2289 create_sprites(ec);
2290
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002291 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002292 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002293 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002294 }
2295
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002296 path = NULL;
2297
Tiago Vignattice03ec32011-12-19 01:14:03 +02002298 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002299
2300 loop = wl_display_get_event_loop(ec->base.wl_display);
2301 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002302 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002303 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002304
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002305 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2306 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002307 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002308 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002309 }
2310 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2311 "drm", NULL);
2312 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002313 wl_event_loop_add_fd(loop,
2314 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002315 WL_EVENT_READABLE, udev_drm_event, ec);
2316
2317 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002318 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002319 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002320 }
2321
Daniel Stonea96b93c2012-06-22 14:04:37 +01002322 udev_device_unref(drm_device);
2323 udev_enumerate_unref(e);
2324
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002325 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002326
2327err_udev_monitor:
2328 wl_event_source_remove(ec->udev_drm_source);
2329 udev_monitor_unref(ec->udev_monitor);
2330err_drm_source:
2331 wl_event_source_remove(ec->drm_source);
2332 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2333 evdev_input_destroy(weston_seat);
2334err_sprite:
2335 destroy_sprites(ec);
2336err_egl:
2337 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2338 EGL_NO_CONTEXT);
2339 eglTerminate(ec->base.egl_display);
2340 eglReleaseThread();
2341 gbm_device_destroy(ec->gbm);
2342err_udev_dev:
2343 udev_device_unref(drm_device);
2344err_udev_enum:
2345 udev_enumerate_unref(e);
2346 tty_destroy(ec->tty);
2347err_udev:
2348 udev_unref(ec->udev);
2349err_compositor:
2350 weston_compositor_shutdown(&ec->base);
2351err_base:
2352 free(ec);
2353 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002354}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002355
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002356static int
2357set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2358{
2359 mode->flags = 0;
2360
2361 if (strcmp(hsync, "+hsync") == 0)
2362 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2363 else if (strcmp(hsync, "-hsync") == 0)
2364 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2365 else
2366 return -1;
2367
2368 if (strcmp(vsync, "+vsync") == 0)
2369 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2370 else if (strcmp(vsync, "-vsync") == 0)
2371 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2372 else
2373 return -1;
2374
2375 return 0;
2376}
2377
2378static int
2379check_for_modeline(struct drm_configured_output *output)
2380{
2381 drmModeModeInfo mode;
2382 char hsync[16];
2383 char vsync[16];
2384 char mode_name[16];
2385 float fclock;
2386
2387 mode.type = DRM_MODE_TYPE_USERDEF;
2388 mode.hskew = 0;
2389 mode.vscan = 0;
2390 mode.vrefresh = 0;
2391
2392 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2393 &fclock, &mode.hdisplay,
2394 &mode.hsync_start,
2395 &mode.hsync_end, &mode.htotal,
2396 &mode.vdisplay,
2397 &mode.vsync_start,
2398 &mode.vsync_end, &mode.vtotal,
2399 hsync, vsync) == 11) {
2400 if (set_sync_flags(&mode, hsync, vsync))
2401 return -1;
2402
2403 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2404 strcpy(mode.name, mode_name);
2405
2406 mode.clock = fclock * 1000;
2407 } else
2408 return -1;
2409
2410 output->crtc_mode = mode;
2411
2412 return 0;
2413}
2414
Scott Moreau8ab5d452012-07-30 19:51:08 -06002415static void
2416output_section_done(void *data)
2417{
2418 struct drm_configured_output *output;
2419
2420 output = malloc(sizeof *output);
2421
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002422 if (!output || !output_name || !output_mode) {
2423 free(output_name);
2424 output_name = NULL;
2425 free(output_mode);
2426 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002427 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002428 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002429
2430 output->config = OUTPUT_CONFIG_INVALID;
2431 output->name = output_name;
2432 output->mode = output_mode;
2433
2434 if (strcmp(output_mode, "off") == 0)
2435 output->config = OUTPUT_CONFIG_OFF;
2436 else if (strcmp(output_mode, "preferred") == 0)
2437 output->config = OUTPUT_CONFIG_PREFERRED;
2438 else if (strcmp(output_mode, "current") == 0)
2439 output->config = OUTPUT_CONFIG_CURRENT;
2440 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2441 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002442 else if (check_for_modeline(output) == 0)
2443 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002444
2445 if (output->config != OUTPUT_CONFIG_INVALID)
2446 wl_list_insert(&configured_output_list, &output->link);
2447 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002448 weston_log("Invalid mode \"%s\" for output %s\n",
2449 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002450 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002451 }
2452}
2453
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002454WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002455backend_init(struct wl_display *display, int argc, char *argv[],
2456 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002457{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002458 int connector = 0, tty = 0;
2459 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002460
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002461 const struct weston_option drm_options[] = {
2462 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2463 { WESTON_OPTION_STRING, "seat", 0, &seat },
2464 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002465 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002466 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002467
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002468 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002469
Scott Moreau8ab5d452012-07-30 19:51:08 -06002470 wl_list_init(&configured_output_list);
2471
2472 const struct config_key drm_config_keys[] = {
2473 { "name", CONFIG_KEY_STRING, &output_name },
2474 { "mode", CONFIG_KEY_STRING, &output_mode },
2475 };
2476
2477 const struct config_section config_section[] = {
2478 { "output", drm_config_keys,
2479 ARRAY_LENGTH(drm_config_keys), output_section_done },
2480 };
2481
2482 parse_config_file(config_file, config_section,
2483 ARRAY_LENGTH(config_section), NULL);
2484
Daniel Stonec1be8e52012-06-01 11:14:02 -04002485 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2486 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002487}