blob: c12bc01d1055f297b2c06e57d6a1a1cf8af4014b [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
Jesse Barnes58ef3792012-02-23 09:45:49 -050092 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050093 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -050094
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020095 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040096};
97
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -040098struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050099 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400100 drmModeModeInfo mode_info;
101};
102
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300103struct drm_output;
104
105struct drm_fb {
106 struct gbm_bo *bo;
107 struct drm_output *output;
108 uint32_t fb_id;
109 int is_client_buffer;
110 struct wl_buffer *buffer;
111 struct wl_listener buffer_destroy_listener;
112};
113
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400114struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500115 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400116
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400117 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400118 uint32_t crtc_id;
119 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700120 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200121
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300122 int vblank_pending;
123 int page_flip_pending;
124
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400125 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400126 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400127 struct weston_plane cursor_plane;
128 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400129 struct weston_surface *cursor_surface;
130 int current_cursor;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400131 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200133 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400134};
135
Jesse Barnes58ef3792012-02-23 09:45:49 -0500136/*
137 * An output has a primary display plane plus zero or more sprites for
138 * blending display contents.
139 */
140struct drm_sprite {
141 struct wl_list link;
142
143 uint32_t fb_id;
144 uint32_t pending_fb_id;
145 struct weston_surface *surface;
146 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400147 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500148
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300149 struct drm_output *output;
150
Jesse Barnes58ef3792012-02-23 09:45:49 -0500151 struct drm_compositor *compositor;
152
153 struct wl_listener destroy_listener;
154 struct wl_listener pending_destroy_listener;
155
156 uint32_t possible_crtcs;
157 uint32_t plane_id;
158 uint32_t count_formats;
159
160 int32_t src_x, src_y;
161 uint32_t src_w, src_h;
162 uint32_t dest_x, dest_y;
163 uint32_t dest_w, dest_h;
164
165 uint32_t formats[];
166};
167
Pekka Paalanen33156972012-08-03 13:30:30 -0400168struct drm_seat {
169 struct weston_seat base;
170 struct wl_list devices_list;
171 struct udev_monitor *udev_monitor;
172 struct wl_event_source *udev_monitor_source;
173 char *seat_id;
174};
175
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400176static void
177drm_output_set_cursor(struct drm_output *output);
178static void
179drm_disable_unused_sprites(struct weston_output *output_base);
180
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
183{
184 struct weston_compositor *ec = output_base->compositor;
185 struct drm_compositor *c =(struct drm_compositor *) ec;
186 struct drm_output *output = (struct drm_output *) output_base;
187 int crtc;
188
189 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
190 if (c->crtcs[crtc] != output->crtc_id)
191 continue;
192
193 if (supported & (1 << crtc))
194 return -1;
195 }
196
197 return 0;
198}
199
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300200static void
201drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
202{
203 struct drm_fb *fb = data;
204 struct gbm_device *gbm = gbm_bo_get_device(bo);
205
206 if (fb->fb_id)
207 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
208
209 if (fb->buffer) {
210 weston_buffer_post_release(fb->buffer);
211 wl_list_remove(&fb->buffer_destroy_listener.link);
212 }
213
214 free(data);
215}
216
217static struct drm_fb *
218drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
219{
220 struct drm_fb *fb = gbm_bo_get_user_data(bo);
221 struct drm_compositor *compositor =
222 (struct drm_compositor *) output->base.compositor;
223 uint32_t width, height, stride, handle;
224 int ret;
225
226 if (fb)
227 return fb;
228
229 fb = malloc(sizeof *fb);
230
231 fb->bo = bo;
232 fb->output = output;
233 fb->is_client_buffer = 0;
234 fb->buffer = NULL;
235
236 width = gbm_bo_get_width(bo);
237 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400238 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300239 handle = gbm_bo_get_handle(bo).u32;
240
241 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
242 stride, handle, &fb->fb_id);
243 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200244 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300245 free(fb);
246 return NULL;
247 }
248
249 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
250
251 return fb;
252}
253
254static void
255fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
256{
257 struct drm_fb *fb = container_of(listener, struct drm_fb,
258 buffer_destroy_listener);
259
260 fb->buffer = NULL;
261
262 if (fb == fb->output->next ||
263 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400264 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300265}
266
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400267static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400268drm_output_prepare_scanout_surface(struct weston_output *_output,
269 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500270{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400271 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500272 struct drm_compositor *c =
273 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300274 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500275
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500276 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200277 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200278 es->geometry.width != output->base.current->width ||
279 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200280 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400281 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400282 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500283
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400284 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
285 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500286
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300287 /* Need to verify output->region contained in surface opaque
288 * region. Or maybe just that format doesn't have alpha.
289 * For now, scanout only if format is XRGB8888. */
290 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
291 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400292 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300293 }
294
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300295 output->next = drm_fb_get_from_bo(bo, output);
296 if (!output->next) {
297 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400298 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300299 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500300
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300301 output->next->is_client_buffer = 1;
302 output->next->buffer = es->buffer;
303 output->next->buffer->busy_count++;
304 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
305
306 wl_signal_add(&output->next->buffer->resource.destroy_signal,
307 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500308
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400309 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500310}
311
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500312static void
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400313drm_output_render(struct drm_output *output, pixman_region32_t *damage)
314{
315 struct drm_compositor *compositor =
316 (struct drm_compositor *) output->base.compositor;
317 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300318 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400319
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400320 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
321 output->egl_surface,
322 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200323 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400324 return;
325 }
326
327 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400328 if (surface->plane == &compositor->base.primary_plane)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400329 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400330
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400331 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600332
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400333 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300334 bo = gbm_surface_lock_front_buffer(output->surface);
335 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200336 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400337 return;
338 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
340 output->next = drm_fb_get_from_bo(bo, output);
341 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200342 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300343 gbm_surface_release_buffer(output->surface, bo);
344 return;
345 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400346}
347
348static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500349drm_output_repaint(struct weston_output *output_base,
350 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100351{
352 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500353 struct drm_compositor *compositor =
354 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500355 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400356 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500357 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100358
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400360 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300361 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400362 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100363
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400364 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300365 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400366 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400368 &output->connector_id, 1,
369 &mode->mode_info);
370 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200371 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400372 return;
373 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200374 }
375
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500376 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500378 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200379 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500380 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500381 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100382
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300383 output->page_flip_pending = 1;
384
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400385 drm_output_set_cursor(output);
386
Jesse Barnes58ef3792012-02-23 09:45:49 -0500387 /*
388 * Now, update all the sprite surfaces
389 */
390 wl_list_for_each(s, &compositor->sprite_list, link) {
391 uint32_t flags = 0;
392 drmVBlank vbl = {
393 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
394 .request.sequence = 1,
395 };
396
397 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
398 continue;
399
400 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
401 output->crtc_id, s->pending_fb_id, flags,
402 s->dest_x, s->dest_y,
403 s->dest_w, s->dest_h,
404 s->src_x, s->src_y,
405 s->src_w, s->src_h);
406 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200407 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500408 ret, strerror(errno));
409
410 /*
411 * Queue a vblank signal so we know when the surface
412 * becomes active on the display or has been replaced.
413 */
414 vbl.request.signal = (unsigned long)s;
415 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
416 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200417 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500418 ret, strerror(errno));
419 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300420
421 s->output = output;
422 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500423 }
424
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400425 drm_disable_unused_sprites(&output->base);
426
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500427 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400428}
429
430static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500431vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
432 void *data)
433{
434 struct drm_sprite *s = (struct drm_sprite *)data;
435 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300436 struct drm_output *output = s->output;
437 uint32_t msecs;
438
439 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500440
441 if (s->surface) {
442 weston_buffer_post_release(s->surface->buffer);
443 wl_list_remove(&s->destroy_listener.link);
444 s->surface = NULL;
445 drmModeRmFB(c->drm.fd, s->fb_id);
446 s->fb_id = 0;
447 }
448
449 if (s->pending_surface) {
450 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400451 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
452 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500453 s->surface = s->pending_surface;
454 s->pending_surface = NULL;
455 s->fb_id = s->pending_fb_id;
456 s->pending_fb_id = 0;
457 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300458
459 if (!output->page_flip_pending) {
460 msecs = sec * 1000 + usec / 1000;
461 weston_output_finish_frame(&output->base, msecs);
462 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500463}
464
465static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400466page_flip_handler(int fd, unsigned int frame,
467 unsigned int sec, unsigned int usec, void *data)
468{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200469 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400470 uint32_t msecs;
471
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300472 output->page_flip_pending = 0;
473
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300474 if (output->current) {
475 if (output->current->is_client_buffer)
476 gbm_bo_destroy(output->current->bo);
477 else
478 gbm_surface_release_buffer(output->surface,
479 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200480 }
481
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300482 output->current = output->next;
483 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400484
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300485 if (!output->vblank_pending) {
486 msecs = sec * 1000 + usec / 1000;
487 weston_output_finish_frame(&output->base, msecs);
488 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200489}
490
491static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500492drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
493{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400494 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500495
496 for (i = 0; i < s->count_formats; i++)
497 if (s->formats[i] == format)
498 return 1;
499
500 return 0;
501}
502
503static int
504drm_surface_transform_supported(struct weston_surface *es)
505{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400506 struct weston_matrix *matrix = &es->transform.matrix;
507 int i;
508
509 if (!es->transform.enabled)
510 return 1;
511
512 for (i = 0; i < 16; i++) {
513 switch (i) {
514 case 10:
515 case 15:
516 if (matrix->d[i] != 1.0)
517 return 0;
518 break;
519 case 0:
520 case 5:
521 case 12:
522 case 13:
523 break;
524 default:
525 if (matrix->d[i] != 0.0)
526 return 0;
527 break;
528 }
529 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500530
531 return 1;
532}
533
Jesse Barnes58ef3792012-02-23 09:45:49 -0500534static void
535drm_disable_unused_sprites(struct weston_output *output_base)
536{
537 struct weston_compositor *ec = output_base->compositor;
538 struct drm_compositor *c =(struct drm_compositor *) ec;
539 struct drm_output *output = (struct drm_output *) output_base;
540 struct drm_sprite *s;
541 int ret;
542
543 wl_list_for_each(s, &c->sprite_list, link) {
544 if (s->pending_fb_id)
545 continue;
546
547 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
548 output->crtc_id, 0, 0,
549 0, 0, 0, 0, 0, 0, 0, 0);
550 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200551 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500552 ret, strerror(errno));
553 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300554
555 if (s->surface) {
556 s->surface = NULL;
557 wl_list_remove(&s->destroy_listener.link);
558 }
559
560 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500561 s->fb_id = 0;
562 s->pending_fb_id = 0;
563 }
564}
565
566/*
567 * This function must take care to damage any previously assigned surface
568 * if the sprite ends up binding to a different surface than in the
569 * previous frame.
570 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400571static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500572drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400573 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500574{
575 struct weston_compositor *ec = output_base->compositor;
576 struct drm_compositor *c =(struct drm_compositor *) ec;
577 struct drm_sprite *s;
578 int found = 0;
579 EGLint handle, stride;
580 struct gbm_bo *bo;
581 uint32_t fb_id = 0;
582 uint32_t handles[4], pitches[4], offsets[4];
583 int ret = 0;
584 pixman_region32_t dest_rect, src_rect;
585 pixman_box32_t *box;
586 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400587 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500588
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500589 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400590 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500591
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300592 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400593 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300594
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400595 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400596 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500597
598 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400599 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500600
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601 wl_list_for_each(s, &c->sprite_list, link) {
602 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
603 continue;
604
605 if (!s->pending_fb_id) {
606 found = 1;
607 break;
608 }
609 }
610
611 /* No sprites available */
612 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400613 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500614
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400615 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
616 es->buffer, GBM_BO_USE_SCANOUT);
617 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400618 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400619
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 format = gbm_bo_get_format(bo);
621 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400622 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500623
624 gbm_bo_destroy(bo);
625
626 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400627 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628
629 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400630 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500631
632 handles[0] = handle;
633 pitches[0] = stride;
634 offsets[0] = 0;
635
636 ret = drmModeAddFB2(c->drm.fd, es->geometry.width, es->geometry.height,
637 format, handles, pitches, offsets,
638 &fb_id, 0);
639 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200640 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500641 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400642 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 }
644
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 s->pending_fb_id = fb_id;
646 s->pending_surface = es;
647 es->buffer->busy_count++;
648
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400649 box = pixman_region32_extents(&es->transform.boundingbox);
650 s->plane.x = box->x1;
651 s->plane.y = box->y1;
652
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653 /*
654 * Calculate the source & dest rects properly based on actual
655 * postion (note the caller has called weston_surface_update_transform()
656 * for us already).
657 */
658 pixman_region32_init(&dest_rect);
659 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
660 &output_base->region);
661 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
662 box = pixman_region32_extents(&dest_rect);
663 s->dest_x = box->x1;
664 s->dest_y = box->y1;
665 s->dest_w = box->x2 - box->x1;
666 s->dest_h = box->y2 - box->y1;
667 pixman_region32_fini(&dest_rect);
668
669 pixman_region32_init(&src_rect);
670 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
671 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500672 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400673
674 weston_surface_from_global_fixed(es,
675 wl_fixed_from_int(box->x1),
676 wl_fixed_from_int(box->y1),
677 &sx1, &sy1);
678 weston_surface_from_global_fixed(es,
679 wl_fixed_from_int(box->x2),
680 wl_fixed_from_int(box->y2),
681 &sx2, &sy2);
682
683 if (sx1 < 0)
684 sx1 = 0;
685 if (sy1 < 0)
686 sy1 = 0;
687 if (sx2 > wl_fixed_from_int(es->geometry.width))
688 sx2 = wl_fixed_from_int(es->geometry.width);
689 if (sy2 > wl_fixed_from_int(es->geometry.height))
690 sy2 = wl_fixed_from_int(es->geometry.height);
691
692 s->src_x = sx1 << 8;
693 s->src_y = sy1 << 8;
694 s->src_w = (sx2 - sx1) << 8;
695 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500696 pixman_region32_fini(&src_rect);
697
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400698 wl_signal_add(&es->buffer->resource.destroy_signal,
699 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400700
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400701 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500702}
703
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400704static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400705drm_output_prepare_cursor_surface(struct weston_output *output_base,
706 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500707{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400708 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400709
710 if (output->cursor_surface)
711 return NULL;
712 if (es->output_mask != (1u << output_base->id))
713 return NULL;
714 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
715 es->geometry.width > 64 || es->geometry.height > 64)
716 return NULL;
717
718 output->cursor_surface = es;
719
720 return &output->cursor_plane;
721}
722
723static void
724drm_output_set_cursor(struct drm_output *output)
725{
726 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400727 struct drm_compositor *c =
728 (struct drm_compositor *) output->base.compositor;
729 EGLint handle, stride;
730 struct gbm_bo *bo;
731 uint32_t buf[64 * 64];
732 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400733 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500734
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400735 if (es == NULL) {
736 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
737 return;
738 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500739
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400740 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
741 pixman_region32_fini(&output->cursor_plane.damage);
742 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400743 output->current_cursor ^= 1;
744 bo = output->cursor_bo[output->current_cursor];
745 memset(buf, 0, sizeof buf);
746 stride = wl_shm_buffer_get_stride(es->buffer);
747 s = wl_shm_buffer_get_data(es->buffer);
748 for (i = 0; i < es->geometry.height; i++)
749 memcpy(buf + i * 64, s + i * stride,
750 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500751
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400752 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400753 weston_log("failed update cursor: %n\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400754
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400755 handle = gbm_bo_get_handle(bo).s32;
756 if (drmModeSetCursor(c->drm.fd,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400757 output->crtc_id, handle, 64, 64))
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400758 weston_log("failed to set cursor: %n\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400759 }
760
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400761 x = es->geometry.x - output->base.x;
762 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400763 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
764 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y))
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400765 weston_log("failed to move cursor: %m\n");
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400766 output->cursor_plane.x = x;
767 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400768 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500769}
770
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771static void
772drm_assign_planes(struct weston_output *output)
773{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400774 struct drm_compositor *c =
775 (struct drm_compositor *) output->compositor;
776 struct drm_output *drm_output = (struct drm_output *) output;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400777 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500778 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400779 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780
781 /*
782 * Find a surface for each sprite in the output using some heuristics:
783 * 1) size
784 * 2) frequency of update
785 * 3) opacity (though some hw might support alpha blending)
786 * 4) clipping (this can be fixed with color keys)
787 *
788 * The idea is to save on blitting since this should save power.
789 * If we can get a large video surface on the sprite for example,
790 * the main display surface may not need to update at all, and
791 * the client buffer can be used directly for the sprite surface
792 * as we do for flipping full screen surfaces.
793 */
794 pixman_region32_init(&overlap);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400795 drm_output->cursor_surface = NULL;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400796 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400797 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798 pixman_region32_init(&surface_overlap);
799 pixman_region32_intersect(&surface_overlap, &overlap,
800 &es->transform.boundingbox);
801
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400802 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400803 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400804 next_plane = primary;
805 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400806 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400807 if (next_plane == NULL)
808 next_plane = drm_output_prepare_scanout_surface(output, es);
809 if (next_plane == NULL)
810 next_plane = drm_output_prepare_overlay_surface(output, es);
811 if (next_plane == NULL)
812 next_plane = primary;
813 weston_surface_move_to_plane(es, next_plane);
814 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815 pixman_region32_union(&overlap, &overlap,
816 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400817
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818 pixman_region32_fini(&surface_overlap);
819 }
820 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821}
822
Matt Roper361d2ad2011-08-29 13:52:23 -0700823static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500824drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700825{
826 struct drm_output *output = (struct drm_output *) output_base;
827 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200828 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700829 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700830
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200831 if (output->backlight)
832 backlight_destroy(output->backlight);
833
Matt Roper361d2ad2011-08-29 13:52:23 -0700834 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400835 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700836
837 /* Restore original CRTC state */
838 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200839 origcrtc->x, origcrtc->y,
840 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700841 drmModeFreeCrtc(origcrtc);
842
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200843 c->crtc_allocator &= ~(1 << output->crtc_id);
844 c->connector_allocator &= ~(1 << output->connector_id);
845
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400846 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400847 gbm_surface_destroy(output->surface);
848
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400849 weston_plane_release(&output->fb_plane);
850 weston_plane_release(&output->cursor_plane);
851
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500852 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200853 wl_list_remove(&output->base.link);
854
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400855 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700856 free(output);
857}
858
Alex Wub7b8bda2012-04-17 17:20:48 +0800859static struct drm_mode *
860choose_mode (struct drm_output *output, struct weston_mode *target_mode)
861{
862 struct drm_mode *tmp_mode = NULL, *mode;
863
864 if (output->base.current->width == target_mode->width &&
865 output->base.current->height == target_mode->height &&
866 (output->base.current->refresh == target_mode->refresh ||
867 target_mode->refresh == 0))
868 return (struct drm_mode *)output->base.current;
869
870 wl_list_for_each(mode, &output->base.mode_list, base.link) {
871 if (mode->mode_info.hdisplay == target_mode->width &&
872 mode->mode_info.vdisplay == target_mode->height) {
873 if (mode->mode_info.vrefresh == target_mode->refresh ||
874 target_mode->refresh == 0) {
875 return mode;
876 } else if (!tmp_mode)
877 tmp_mode = mode;
878 }
879 }
880
881 return tmp_mode;
882}
883
884static int
885drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
886{
887 struct drm_output *output;
888 struct drm_mode *drm_mode;
889 int ret;
890 struct drm_compositor *ec;
891 struct gbm_surface *surface;
892 EGLSurface egl_surface;
893
894 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200895 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800896 return -1;
897 }
898
899 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200900 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800901 return -1;
902 }
903
904 ec = (struct drm_compositor *)output_base->compositor;
905 output = (struct drm_output *)output_base;
906 drm_mode = choose_mode (output, mode);
907
908 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200909 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800910 return -1;
911 } else if (&drm_mode->base == output->base.current) {
912 return 0;
913 } else if (drm_mode->base.width == output->base.current->width &&
914 drm_mode->base.height == output->base.current->height) {
915 /* only change refresh value */
916 ret = drmModeSetCrtc(ec->drm.fd,
917 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300918 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800919 &output->connector_id, 1, &drm_mode->mode_info);
920
921 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200922 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800923 drm_mode->base.width,
924 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400925 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800926 ret = -1;
927 } else {
928 output->base.current->flags = 0;
929 output->base.current = &drm_mode->base;
930 drm_mode->base.flags =
931 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
932 ret = 0;
933 }
934
935 return ret;
936 }
937
938 drm_mode->base.flags =
939 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
940
941 surface = gbm_surface_create(ec->gbm,
942 drm_mode->base.width,
943 drm_mode->base.height,
944 GBM_FORMAT_XRGB8888,
945 GBM_BO_USE_SCANOUT |
946 GBM_BO_USE_RENDERING);
947 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200948 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800949 return -1;
950 }
951
952 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400953 eglCreateWindowSurface(ec->base.egl_display,
954 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800955 surface, NULL);
956
957 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200958 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800959 goto err;
960 }
961
962 ret = drmModeSetCrtc(ec->drm.fd,
963 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300964 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800965 &output->connector_id, 1, &drm_mode->mode_info);
966 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200967 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800968 goto err;
969 }
970
971 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300972 if (output->current) {
973 if (output->current->is_client_buffer)
974 gbm_bo_destroy(output->current->bo);
975 else
976 gbm_surface_release_buffer(output->surface,
977 output->current->bo);
978 }
979 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800980
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300981 if (output->next) {
982 if (output->next->is_client_buffer)
983 gbm_bo_destroy(output->next->bo);
984 else
985 gbm_surface_release_buffer(output->surface,
986 output->next->bo);
987 }
988 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800989
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400990 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800991 gbm_surface_destroy(output->surface);
992 output->egl_surface = egl_surface;
993 output->surface = surface;
994
995 /*update output*/
996 output->base.current = &drm_mode->base;
997 output->base.dirty = 1;
998 weston_output_move(&output->base, output->base.x, output->base.y);
999 return 0;
1000
1001err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001002 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001003 gbm_surface_destroy(surface);
1004 return -1;
1005}
1006
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001007static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001008on_drm_input(int fd, uint32_t mask, void *data)
1009{
1010 drmEventContext evctx;
1011
1012 memset(&evctx, 0, sizeof evctx);
1013 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1014 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001015 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001016 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001017
1018 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001019}
1020
1021static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001022init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001023{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001024 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001025 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001026 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001027 static const EGLint context_attribs[] = {
1028 EGL_CONTEXT_CLIENT_VERSION, 2,
1029 EGL_NONE
1030 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001031
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001032 static const EGLint config_attribs[] = {
1033 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1034 EGL_RED_SIZE, 1,
1035 EGL_GREEN_SIZE, 1,
1036 EGL_BLUE_SIZE, 1,
1037 EGL_ALPHA_SIZE, 0,
1038 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1039 EGL_NONE
1040 };
1041
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001042 sysnum = udev_device_get_sysnum(device);
1043 if (sysnum)
1044 ec->drm.id = atoi(sysnum);
1045 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001046 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001047 return -1;
1048 }
1049
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001050 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001051 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001052 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001053 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001054 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001055 udev_device_get_devnode(device));
1056 return -1;
1057 }
1058
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001059 weston_log("using %s\n", filename);
1060
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001061 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001062 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001063 ec->base.egl_display = eglGetDisplay(ec->gbm);
1064 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001065 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001066 return -1;
1067 }
1068
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001069 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001070 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001071 return -1;
1072 }
1073
Darxus55973f22010-11-22 21:24:39 -05001074 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001075 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001076 return -1;
1077 }
1078
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001079 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1080 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001081 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001082 return -1;
1083 }
1084
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001085 ec->base.egl_context =
1086 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1087 EGL_NO_CONTEXT, context_attribs);
1088 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001089 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001090 return -1;
1091 }
1092
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001093 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1094 GBM_FORMAT_XRGB8888,
1095 GBM_BO_USE_RENDERING);
1096 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001097 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001098 return -1;
1099 }
1100
1101 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001102 eglCreateWindowSurface(ec->base.egl_display,
1103 ec->base.egl_config,
1104 ec->dummy_surface,
1105 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001106 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001107 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001108 return -1;
1109 }
1110
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001111 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1112 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001113 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001114 return -1;
1115 }
1116
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001117 return 0;
1118}
1119
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001120static int
1121drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1122{
1123 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001124 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001125
1126 mode = malloc(sizeof *mode);
1127 if (mode == NULL)
1128 return -1;
1129
1130 mode->base.flags = 0;
1131 mode->base.width = info->hdisplay;
1132 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001133
1134 /* Calculate higher precision (mHz) refresh rate */
1135 refresh = (info->clock * 1000000LL / info->htotal +
1136 info->vtotal / 2) / info->vtotal;
1137
1138 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1139 refresh *= 2;
1140 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1141 refresh /= 2;
1142 if (info->vscan > 1)
1143 refresh /= info->vscan;
1144
1145 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001146 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001147
1148 if (info->type & DRM_MODE_TYPE_PREFERRED)
1149 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1150
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001151 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1152
1153 return 0;
1154}
1155
1156static int
1157drm_subpixel_to_wayland(int drm_value)
1158{
1159 switch (drm_value) {
1160 default:
1161 case DRM_MODE_SUBPIXEL_UNKNOWN:
1162 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1163 case DRM_MODE_SUBPIXEL_NONE:
1164 return WL_OUTPUT_SUBPIXEL_NONE;
1165 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1166 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1167 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1168 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1169 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1170 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1171 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1172 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1173 }
1174}
1175
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001176static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001177sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001178{
1179 struct drm_sprite *sprite =
1180 container_of(listener, struct drm_sprite,
1181 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001182 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001183
1184 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001185 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1186 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001187}
1188
1189static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001190sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001191{
1192 struct drm_sprite *sprite =
1193 container_of(listener, struct drm_sprite,
1194 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001195 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001196
1197 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001198 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1199 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001200}
1201
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001202/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001203static uint32_t
1204drm_get_backlight(struct drm_output *output)
1205{
1206 long brightness, max_brightness, norm;
1207
1208 brightness = backlight_get_brightness(output->backlight);
1209 max_brightness = backlight_get_max_brightness(output->backlight);
1210
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001211 /* convert it on a scale of 0 to 255 */
1212 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001213
1214 return (uint32_t) norm;
1215}
1216
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001217/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001218static void
1219drm_set_backlight(struct weston_output *output_base, uint32_t value)
1220{
1221 struct drm_output *output = (struct drm_output *) output_base;
1222 long max_brightness, new_brightness;
1223
1224 if (!output->backlight)
1225 return;
1226
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001227 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001228 return;
1229
1230 max_brightness = backlight_get_max_brightness(output->backlight);
1231
1232 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001233 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001234
1235 backlight_set_brightness(output->backlight, new_brightness);
1236}
1237
1238static drmModePropertyPtr
1239drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1240{
1241 drmModePropertyPtr props;
1242 int i;
1243
1244 for (i = 0; i < connector->count_props; i++) {
1245 props = drmModeGetProperty(fd, connector->props[i]);
1246 if (!props)
1247 continue;
1248
1249 if (!strcmp(props->name, name))
1250 return props;
1251
1252 drmModeFreeProperty(props);
1253 }
1254
1255 return NULL;
1256}
1257
1258static void
1259drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1260{
1261 struct drm_output *output = (struct drm_output *) output_base;
1262 struct weston_compositor *ec = output_base->compositor;
1263 struct drm_compositor *c = (struct drm_compositor *) ec;
1264 drmModeConnectorPtr connector;
1265 drmModePropertyPtr prop;
1266
1267 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1268 if (!connector)
1269 return;
1270
1271 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1272 if (!prop) {
1273 drmModeFreeConnector(connector);
1274 return;
1275 }
1276
1277 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1278 prop->prop_id, level);
1279 drmModeFreeProperty(prop);
1280 drmModeFreeConnector(connector);
1281}
1282
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001283static const char *connector_type_names[] = {
1284 "None",
1285 "VGA",
1286 "DVI",
1287 "DVI",
1288 "DVI",
1289 "Composite",
1290 "TV",
1291 "LVDS",
1292 "CTV",
1293 "DIN",
1294 "DP",
1295 "HDMI",
1296 "HDMI",
1297 "TV",
1298 "eDP",
1299};
1300
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001301static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001302find_crtc_for_connector(struct drm_compositor *ec,
1303 drmModeRes *resources, drmModeConnector *connector)
1304{
1305 drmModeEncoder *encoder;
1306 uint32_t possible_crtcs;
1307 int i, j;
1308
1309 for (j = 0; j < connector->count_encoders; j++) {
1310 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1311 if (encoder == NULL) {
1312 weston_log("Failed to get encoder.\n");
1313 return -1;
1314 }
1315 possible_crtcs = encoder->possible_crtcs;
1316 drmModeFreeEncoder(encoder);
1317
1318 for (i = 0; i < resources->count_crtcs; i++) {
1319 if (possible_crtcs & (1 << i) &&
1320 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1321 return i;
1322 }
1323 }
1324
1325 return -1;
1326}
1327
1328static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001329create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001330 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001331 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001332 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001333{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001334 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001335 struct drm_mode *drm_mode, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001336 struct weston_mode *m, *preferred, *current, *configured;
1337 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001338 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001339 drmModeModeInfo crtc_mode;
1340 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001341 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001342 char name[32];
1343 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001344
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001345 i = find_crtc_for_connector(ec, resources, connector);
1346 if (i < 0) {
1347 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001348 return -1;
1349 }
1350
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001351 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001352 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001353 return -1;
1354
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001355 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001356 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1357 output->base.make = "unknown";
1358 output->base.model = "unknown";
1359 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001360
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001361 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1362 type_name = connector_type_names[connector->connector_type];
1363 else
1364 type_name = "UNKNOWN";
1365 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1366 output->name = strdup(name);
1367
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001368 output->crtc_id = resources->crtcs[i];
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001369 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001370 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001371 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001372
Matt Roper361d2ad2011-08-29 13:52:23 -07001373 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1374
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001375 /* Get the current mode on the crtc that's currently driving
1376 * this connector. */
1377 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001378 memset(&crtc_mode, 0, sizeof crtc_mode);
1379 if (encoder != NULL) {
1380 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1381 drmModeFreeEncoder(encoder);
1382 if (crtc == NULL)
1383 goto err_free;
1384 if (crtc->mode_valid)
1385 crtc_mode = crtc->mode;
1386 drmModeFreeCrtc(crtc);
1387 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001388
David Herrmann0f0d54e2011-12-08 17:05:45 +01001389 for (i = 0; i < connector->count_modes; i++) {
1390 ret = drm_output_add_mode(output, &connector->modes[i]);
1391 if (ret)
1392 goto err_free;
1393 }
1394
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001395 preferred = NULL;
1396 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001397 configured = NULL;
1398
1399 wl_list_for_each(temp, &configured_output_list, link) {
1400 if (strcmp(temp->name, output->name) == 0) {
1401 weston_log("%s mode \"%s\" in config\n",
1402 temp->name, temp->mode);
1403 o = temp;
1404 break;
1405 }
1406 }
1407
1408 if (o && strcmp("off", o->mode) == 0) {
1409 weston_log("Disabling output %s\n", o->name);
1410
1411 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1412 0, 0, 0, 0, 0, NULL);
1413 goto err_free;
1414 }
1415
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001416 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001417 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001418 o->height == drm_mode->base.height &&
1419 o->config == OUTPUT_CONFIG_MODE)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001420 configured = &drm_mode->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001421 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001422 current = &drm_mode->base;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001423 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1424 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001425 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001426
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001427 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
1428 ret = drm_output_add_mode(output, &o->crtc_mode);
1429 if (ret)
1430 goto err_free;
1431 configured = container_of(output->base.mode_list.prev,
1432 struct weston_mode, link);
1433 current = configured;
1434 }
1435
Wang Quanxianacb805a2012-07-30 18:09:46 -04001436 if (current == NULL && crtc_mode.clock != 0) {
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001437 ret = drm_output_add_mode(output, &crtc_mode);
1438 if (ret)
1439 goto err_free;
1440 current = container_of(output->base.mode_list.prev,
1441 struct weston_mode, link);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001442 }
1443
Scott Moreau8ab5d452012-07-30 19:51:08 -06001444 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1445 configured = current;
1446
Wang Quanxianacb805a2012-07-30 18:09:46 -04001447 if (option_current_mode && current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001448 output->base.current = current;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001449 else if (configured)
1450 output->base.current = configured;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001451 else if (preferred)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001452 output->base.current = preferred;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001453 else if (current)
1454 output->base.current = current;
1455
1456 if (output->base.current == NULL) {
1457 weston_log("no available modes for %s\n", output->name);
1458 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001459 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001460
Wang Quanxianacb805a2012-07-30 18:09:46 -04001461 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1462
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001463 output->surface = gbm_surface_create(ec->gbm,
1464 output->base.current->width,
1465 output->base.current->height,
1466 GBM_FORMAT_XRGB8888,
1467 GBM_BO_USE_SCANOUT |
1468 GBM_BO_USE_RENDERING);
1469 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001470 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001471 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001472 }
1473
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001474 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001475 eglCreateWindowSurface(ec->base.egl_display,
1476 ec->base.egl_config,
1477 output->surface,
1478 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001479 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001480 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001481 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001482 }
1483
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001484 output->cursor_bo[0] =
1485 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1486 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1487 output->cursor_bo[1] =
1488 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1489 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1490
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001491 output->backlight = backlight_init(drm_device,
1492 connector->connector_type);
1493 if (output->backlight) {
1494 output->base.set_backlight = drm_set_backlight;
1495 output->base.backlight_current = drm_get_backlight(output);
1496 }
1497
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001498 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001499 connector->mmWidth, connector->mmHeight,
1500 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001501
1502 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1503
Alex Wubd3354b2012-04-17 17:20:49 +08001504 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001505 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001506 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001507 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001508 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001509 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001510
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001511 weston_plane_init(&output->cursor_plane, 0, 0);
1512 weston_plane_init(&output->fb_plane, 0, 0);
1513
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001514 weston_log("Output %s, (connector %d, crtc %d)\n",
1515 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001516 wl_list_for_each(m, &output->base.mode_list, link)
1517 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1518 m->width, m->height, m->refresh / 1000.0,
1519 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1520 ", preferred" : "",
1521 m->flags & WL_OUTPUT_MODE_CURRENT ?
1522 ", current" : "",
1523 connector->count_modes == 0 ?
1524 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001525
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001526 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001527
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001528err_surface:
1529 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001530err_free:
1531 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1532 base.link) {
1533 wl_list_remove(&drm_mode->base.link);
1534 free(drm_mode);
1535 }
1536
1537 drmModeFreeCrtc(output->original_crtc);
1538 ec->crtc_allocator &= ~(1 << output->crtc_id);
1539 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001540 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001541 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001542
David Herrmann0f0d54e2011-12-08 17:05:45 +01001543 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001544}
1545
Jesse Barnes58ef3792012-02-23 09:45:49 -05001546static void
1547create_sprites(struct drm_compositor *ec)
1548{
1549 struct drm_sprite *sprite;
1550 drmModePlaneRes *plane_res;
1551 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001552 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001553
1554 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1555 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001556 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001557 strerror(errno));
1558 return;
1559 }
1560
1561 for (i = 0; i < plane_res->count_planes; i++) {
1562 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1563 if (!plane)
1564 continue;
1565
1566 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1567 plane->count_formats));
1568 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001569 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001570 __func__);
1571 free(plane);
1572 continue;
1573 }
1574
1575 memset(sprite, 0, sizeof *sprite);
1576
1577 sprite->possible_crtcs = plane->possible_crtcs;
1578 sprite->plane_id = plane->plane_id;
1579 sprite->surface = NULL;
1580 sprite->pending_surface = NULL;
1581 sprite->fb_id = 0;
1582 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001583 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1584 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001585 sprite_handle_pending_buffer_destroy;
1586 sprite->compositor = ec;
1587 sprite->count_formats = plane->count_formats;
1588 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001589 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001590 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001591 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001592
1593 wl_list_insert(&ec->sprite_list, &sprite->link);
1594 }
1595
1596 free(plane_res->planes);
1597 free(plane_res);
1598}
1599
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001600static void
1601destroy_sprites(struct drm_compositor *compositor)
1602{
1603 struct drm_sprite *sprite, *next;
1604 struct drm_output *output;
1605
1606 output = container_of(compositor->base.output_list.next,
1607 struct drm_output, base.link);
1608
1609 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1610 drmModeSetPlane(compositor->drm.fd,
1611 sprite->plane_id,
1612 output->crtc_id, 0, 0,
1613 0, 0, 0, 0, 0, 0, 0, 0);
1614 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001615 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001616 free(sprite);
1617 }
1618}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001619
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001620static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001621create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001622 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001623{
1624 drmModeConnector *connector;
1625 drmModeRes *resources;
1626 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001627 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001628
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001629 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001630 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001631 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001632 return -1;
1633 }
1634
Jesse Barnes58ef3792012-02-23 09:45:49 -05001635 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001636 if (!ec->crtcs) {
1637 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001638 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001639 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001640
1641 ec->num_crtcs = resources->count_crtcs;
1642 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1643
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001644 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001645 connector = drmModeGetConnector(ec->drm.fd,
1646 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001647 if (connector == NULL)
1648 continue;
1649
1650 if (connector->connection == DRM_MODE_CONNECTED &&
1651 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001652 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001653 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001654 connector, x, y,
1655 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001656 drmModeFreeConnector(connector);
1657 continue;
1658 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001659
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001660 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001661 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001662 link)->current->width;
1663 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001664
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001665 drmModeFreeConnector(connector);
1666 }
1667
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001668 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001669 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001670 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001671 return -1;
1672 }
1673
1674 drmModeFreeResources(resources);
1675
1676 return 0;
1677}
1678
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001679static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001680update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001681{
1682 drmModeConnector *connector;
1683 drmModeRes *resources;
1684 struct drm_output *output, *next;
1685 int x = 0, y = 0;
1686 int x_offset = 0, y_offset = 0;
1687 uint32_t connected = 0, disconnects = 0;
1688 int i;
1689
1690 resources = drmModeGetResources(ec->drm.fd);
1691 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001692 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001693 return;
1694 }
1695
1696 /* collect new connects */
1697 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001698 int connector_id = resources->connectors[i];
1699
1700 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001701 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001702 continue;
1703
David Herrmann7551cff2011-12-08 17:05:43 +01001704 if (connector->connection != DRM_MODE_CONNECTED) {
1705 drmModeFreeConnector(connector);
1706 continue;
1707 }
1708
Benjamin Franzke117483d2011-08-30 11:38:26 +02001709 connected |= (1 << connector_id);
1710
1711 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001712 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001713 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001714 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001715
1716 /* XXX: not yet needed, we die with 0 outputs */
1717 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001718 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001719 else
1720 x = 0;
1721 y = 0;
1722 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001723 connector, x, y,
1724 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001725 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001726
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001727 }
1728 drmModeFreeConnector(connector);
1729 }
1730 drmModeFreeResources(resources);
1731
1732 disconnects = ec->connector_allocator & ~connected;
1733 if (disconnects) {
1734 wl_list_for_each_safe(output, next, &ec->base.output_list,
1735 base.link) {
1736 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001737 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001738 output->base.x - x_offset,
1739 output->base.y - y_offset);
1740 }
1741
1742 if (disconnects & (1 << output->connector_id)) {
1743 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001744 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001745 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001746 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001747 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001748 }
1749 }
1750 }
1751
1752 /* FIXME: handle zero outputs, without terminating */
1753 if (ec->connector_allocator == 0)
1754 wl_display_terminate(ec->base.wl_display);
1755}
1756
1757static int
David Herrmannd7488c22012-03-11 20:05:21 +01001758udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001759{
David Herrmannd7488c22012-03-11 20:05:21 +01001760 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001761 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001762
1763 sysnum = udev_device_get_sysnum(device);
1764 if (!sysnum || atoi(sysnum) != ec->drm.id)
1765 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001766
David Herrmann6ac52db2012-03-11 20:05:22 +01001767 val = udev_device_get_property_value(device, "HOTPLUG");
1768 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001769 return 0;
1770
David Herrmann6ac52db2012-03-11 20:05:22 +01001771 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001772}
1773
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001774static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001775udev_drm_event(int fd, uint32_t mask, void *data)
1776{
1777 struct drm_compositor *ec = data;
1778 struct udev_device *event;
1779
1780 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001781
David Herrmannd7488c22012-03-11 20:05:21 +01001782 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001783 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001784
1785 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001786
1787 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001788}
1789
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001790static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001791drm_restore(struct weston_compositor *ec)
1792{
1793 struct drm_compositor *d = (struct drm_compositor *) ec;
1794
1795 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1796 weston_log("failed to drop master: %m\n");
1797 tty_reset(d->tty);
1798}
1799
Pekka Paalanen33156972012-08-03 13:30:30 -04001800static const char default_seat[] = "seat0";
1801
1802static void
1803device_added(struct udev_device *udev_device, struct drm_seat *master)
1804{
1805 struct weston_compositor *c;
1806 struct evdev_input_device *device;
1807 const char *devnode;
1808 const char *device_seat;
1809 int fd;
1810
1811 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1812 if (!device_seat)
1813 device_seat = default_seat;
1814
1815 if (strcmp(device_seat, master->seat_id))
1816 return;
1817
1818 c = master->base.compositor;
1819 devnode = udev_device_get_devnode(udev_device);
1820
1821 /* Use non-blocking mode so that we can loop on read on
1822 * evdev_input_device_data() until all events on the fd are
1823 * read. mtdev_get() also expects this. */
1824 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1825 if (fd < 0) {
1826 weston_log("opening input device '%s' failed.\n", devnode);
1827 return;
1828 }
1829
1830 device = evdev_input_device_create(&master->base, devnode, fd);
1831 if (!device) {
1832 close(fd);
1833 weston_log("not using input device '%s'.\n", devnode);
1834 return;
1835 }
1836
1837 wl_list_insert(master->devices_list.prev, &device->link);
1838}
1839
1840static void
1841evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1842{
1843 struct drm_seat *seat = (struct drm_seat *) seat_base;
1844 struct udev_enumerate *e;
1845 struct udev_list_entry *entry;
1846 struct udev_device *device;
1847 const char *path, *sysname;
1848
1849 e = udev_enumerate_new(udev);
1850 udev_enumerate_add_match_subsystem(e, "input");
1851 udev_enumerate_scan_devices(e);
1852 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1853 path = udev_list_entry_get_name(entry);
1854 device = udev_device_new_from_syspath(udev, path);
1855
1856 sysname = udev_device_get_sysname(device);
1857 if (strncmp("event", sysname, 5) != 0) {
1858 udev_device_unref(device);
1859 continue;
1860 }
1861
1862 device_added(device, seat);
1863
1864 udev_device_unref(device);
1865 }
1866 udev_enumerate_unref(e);
1867
1868 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1869
1870 if (wl_list_empty(&seat->devices_list)) {
1871 weston_log(
1872 "warning: no input devices on entering Weston. "
1873 "Possible causes:\n"
1874 "\t- no permissions to read /dev/input/event*\n"
1875 "\t- seats misconfigured "
1876 "(Weston backend option 'seat', "
1877 "udev device property ID_SEAT)\n");
1878 }
1879}
1880
1881static int
1882evdev_udev_handler(int fd, uint32_t mask, void *data)
1883{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001884 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001885 struct udev_device *udev_device;
1886 struct evdev_input_device *device, *next;
1887 const char *action;
1888 const char *devnode;
1889
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001890 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001891 if (!udev_device)
1892 return 1;
1893
1894 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001895 if (!action)
1896 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001897
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001898 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1899 goto out;
1900
1901 if (!strcmp(action, "add")) {
1902 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001903 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001904 else if (!strcmp(action, "remove")) {
1905 devnode = udev_device_get_devnode(udev_device);
1906 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1907 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001908 weston_log("input device %s, %s removed\n",
1909 device->devname, device->devnode);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001910 evdev_input_device_destroy(device);
1911 break;
1912 }
1913 }
1914
1915out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001916 udev_device_unref(udev_device);
1917
1918 return 0;
1919}
1920
1921static int
1922evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1923{
1924 struct drm_seat *master = (struct drm_seat *) seat_base;
1925 struct wl_event_loop *loop;
1926 struct weston_compositor *c = master->base.compositor;
1927 int fd;
1928
1929 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1930 if (!master->udev_monitor) {
1931 weston_log("udev: failed to create the udev monitor\n");
1932 return 0;
1933 }
1934
1935 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1936 "input", NULL);
1937
1938 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1939 weston_log("udev: failed to bind the udev monitor\n");
1940 udev_monitor_unref(master->udev_monitor);
1941 return 0;
1942 }
1943
1944 loop = wl_display_get_event_loop(c->wl_display);
1945 fd = udev_monitor_get_fd(master->udev_monitor);
1946 master->udev_monitor_source =
1947 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1948 evdev_udev_handler, master);
1949 if (!master->udev_monitor_source) {
1950 udev_monitor_unref(master->udev_monitor);
1951 return 0;
1952 }
1953
1954 return 1;
1955}
1956
1957static void
1958evdev_disable_udev_monitor(struct weston_seat *seat_base)
1959{
1960 struct drm_seat *seat = (struct drm_seat *) seat_base;
1961
1962 if (!seat->udev_monitor)
1963 return;
1964
1965 udev_monitor_unref(seat->udev_monitor);
1966 seat->udev_monitor = NULL;
1967 wl_event_source_remove(seat->udev_monitor_source);
1968 seat->udev_monitor_source = NULL;
1969}
1970
1971static void
1972drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1973{
1974 struct drm_seat *seat = (struct drm_seat *) seat_base;
1975
1976 evdev_led_update(&seat->devices_list, leds);
1977}
1978
1979static void
1980evdev_input_create(struct weston_compositor *c, struct udev *udev,
1981 const char *seat_id)
1982{
1983 struct drm_seat *seat;
1984
1985 seat = malloc(sizeof *seat);
1986 if (seat == NULL)
1987 return;
1988
1989 memset(seat, 0, sizeof *seat);
1990 weston_seat_init(&seat->base, c);
1991 seat->base.led_update = drm_led_update;
1992
1993 wl_list_init(&seat->devices_list);
1994 seat->seat_id = strdup(seat_id);
1995 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1996 free(seat->seat_id);
1997 free(seat);
1998 return;
1999 }
2000
2001 evdev_add_devices(udev, &seat->base);
2002
2003 c->seat = &seat->base;
2004}
2005
2006static void
2007evdev_remove_devices(struct weston_seat *seat_base)
2008{
2009 struct drm_seat *seat = (struct drm_seat *) seat_base;
2010 struct evdev_input_device *device, *next;
2011
2012 wl_list_for_each_safe(device, next, &seat->devices_list, link)
2013 evdev_input_device_destroy(device);
2014
2015 notify_keyboard_focus_out(&seat->base.seat);
2016}
2017
2018static void
2019evdev_input_destroy(struct weston_seat *seat_base)
2020{
2021 struct drm_seat *seat = (struct drm_seat *) seat_base;
2022
2023 evdev_remove_devices(seat_base);
2024 evdev_disable_udev_monitor(&seat->base);
2025
2026 weston_seat_release(seat_base);
2027 free(seat->seat_id);
2028 free(seat);
2029}
2030
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002031static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002032drm_free_configured_output(struct drm_configured_output *output)
2033{
2034 free(output->name);
2035 free(output->mode);
2036 free(output);
2037}
2038
2039static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002040drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002041{
2042 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002043 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002044 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002045
Daniel Stone37816df2012-05-16 18:45:18 +01002046 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2047 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002048 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002049 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002050
2051 wl_event_source_remove(d->udev_drm_source);
2052 wl_event_source_remove(d->drm_source);
2053
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002054 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002055
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002056 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002057 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002058 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002059 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002060 eglReleaseThread();
2061
Matt Roper361d2ad2011-08-29 13:52:23 -07002062 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002063 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002064 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002065 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002066 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002067
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002068 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002069}
2070
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002071static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002072drm_compositor_set_modes(struct drm_compositor *compositor)
2073{
2074 struct drm_output *output;
2075 struct drm_mode *drm_mode;
2076 int ret;
2077
2078 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2079 drm_mode = (struct drm_mode *) output->base.current;
2080 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002081 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002082 &output->connector_id, 1,
2083 &drm_mode->mode_info);
2084 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002085 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002086 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002087 drm_mode->base.width, drm_mode->base.height,
2088 output->base.x, output->base.y);
2089 }
2090 }
2091}
2092
2093static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002094vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002095{
2096 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002097 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002098 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002099 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002100
2101 switch (event) {
2102 case TTY_ENTER_VT:
2103 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002104 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002105 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002106 wl_display_terminate(compositor->wl_display);
2107 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002108 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002109 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002110 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002111 wl_list_for_each(seat, &compositor->seat_list, link) {
2112 evdev_add_devices(ec->udev, seat);
2113 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002114 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002115 break;
2116 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01002117 wl_list_for_each(seat, &compositor->seat_list, link) {
2118 evdev_disable_udev_monitor(seat);
2119 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002120 }
2121
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002122 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002123 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002124 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002125
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002126 /* If we have a repaint scheduled (either from a
2127 * pending pageflip or the idle handler), make sure we
2128 * cancel that so we don't try to pageflip when we're
2129 * vt switched away. The SLEEPING state will prevent
2130 * further attemps at repainting. When we switch
2131 * back, we schedule a repaint, which will process
2132 * pending frame callbacks. */
2133
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002134 wl_list_for_each(output, &ec->base.output_list, base.link) {
2135 output->base.repaint_needed = 0;
2136 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002137 }
2138
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002139 output = container_of(ec->base.output_list.next,
2140 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002141
2142 wl_list_for_each(sprite, &ec->sprite_list, link)
2143 drmModeSetPlane(ec->drm.fd,
2144 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002145 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002146 0, 0, 0, 0, 0, 0, 0, 0);
2147
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002148 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002149 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002150
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002151 break;
2152 };
2153}
2154
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002155static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002156switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002157{
2158 struct drm_compositor *ec = data;
2159
Daniel Stone325fc2d2012-05-30 16:31:58 +01002160 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002161}
2162
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002163static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002164drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002165 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002166 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002167{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002168 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002169 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002170 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002171 struct udev_device *device, *drm_device;
2172 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002173 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002174 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002175 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002176
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002177 weston_log("initializing drm backend\n");
2178
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002179 ec = malloc(sizeof *ec);
2180 if (ec == NULL)
2181 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002182 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002183
2184 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002185 config_file) < 0) {
2186 weston_log("weston_compositor_init failed\n");
2187 goto err_base;
2188 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002189
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002190 ec->udev = udev_new();
2191 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002192 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002193 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002194 }
2195
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002196 ec->base.wl_display = display;
2197 ec->tty = tty_create(&ec->base, vt_func, tty);
2198 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002199 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002200 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002201 }
2202
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002203 e = udev_enumerate_new(ec->udev);
2204 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002205 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002206
Benjamin Franzke117483d2011-08-30 11:38:26 +02002207 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002208 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002209 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002210 path = udev_list_entry_get_name(entry);
2211 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002212 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002213 udev_device_get_property_value(device, "ID_SEAT");
2214 if (!device_seat)
2215 device_seat = default_seat;
2216 if (strcmp(device_seat, seat) == 0) {
2217 drm_device = device;
2218 break;
2219 }
2220 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002221 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002222
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002223 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002224 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002225 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002226 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002227
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002228 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002229 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002230 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002231 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002232
2233 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002234 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002235
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002236 ec->base.focus = 1;
2237
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002238 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002239
Daniel Stone725c2c32012-06-22 14:04:36 +01002240 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002241 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002242
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002243 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002244 weston_compositor_add_key_binding(&ec->base, key,
2245 MODIFIER_CTRL | MODIFIER_ALT,
2246 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002247
Jesse Barnes58ef3792012-02-23 09:45:49 -05002248 wl_list_init(&ec->sprite_list);
2249 create_sprites(ec);
2250
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002251 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002252 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002253 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002254 }
2255
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002256 path = NULL;
2257
Tiago Vignattice03ec32011-12-19 01:14:03 +02002258 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002259
2260 loop = wl_display_get_event_loop(ec->base.wl_display);
2261 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002262 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002263 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002264
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002265 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2266 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002267 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002268 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002269 }
2270 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2271 "drm", NULL);
2272 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002273 wl_event_loop_add_fd(loop,
2274 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002275 WL_EVENT_READABLE, udev_drm_event, ec);
2276
2277 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002278 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002279 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002280 }
2281
Daniel Stonea96b93c2012-06-22 14:04:37 +01002282 udev_device_unref(drm_device);
2283 udev_enumerate_unref(e);
2284
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002285 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002286
2287err_udev_monitor:
2288 wl_event_source_remove(ec->udev_drm_source);
2289 udev_monitor_unref(ec->udev_monitor);
2290err_drm_source:
2291 wl_event_source_remove(ec->drm_source);
2292 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2293 evdev_input_destroy(weston_seat);
2294err_sprite:
2295 destroy_sprites(ec);
2296err_egl:
2297 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2298 EGL_NO_CONTEXT);
2299 eglTerminate(ec->base.egl_display);
2300 eglReleaseThread();
2301 gbm_device_destroy(ec->gbm);
2302err_udev_dev:
2303 udev_device_unref(drm_device);
2304err_udev_enum:
2305 udev_enumerate_unref(e);
2306 tty_destroy(ec->tty);
2307err_udev:
2308 udev_unref(ec->udev);
2309err_compositor:
2310 weston_compositor_shutdown(&ec->base);
2311err_base:
2312 free(ec);
2313 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002314}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002315
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002316static int
2317set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2318{
2319 mode->flags = 0;
2320
2321 if (strcmp(hsync, "+hsync") == 0)
2322 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2323 else if (strcmp(hsync, "-hsync") == 0)
2324 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2325 else
2326 return -1;
2327
2328 if (strcmp(vsync, "+vsync") == 0)
2329 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2330 else if (strcmp(vsync, "-vsync") == 0)
2331 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2332 else
2333 return -1;
2334
2335 return 0;
2336}
2337
2338static int
2339check_for_modeline(struct drm_configured_output *output)
2340{
2341 drmModeModeInfo mode;
2342 char hsync[16];
2343 char vsync[16];
2344 char mode_name[16];
2345 float fclock;
2346
2347 mode.type = DRM_MODE_TYPE_USERDEF;
2348 mode.hskew = 0;
2349 mode.vscan = 0;
2350 mode.vrefresh = 0;
2351
2352 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2353 &fclock, &mode.hdisplay,
2354 &mode.hsync_start,
2355 &mode.hsync_end, &mode.htotal,
2356 &mode.vdisplay,
2357 &mode.vsync_start,
2358 &mode.vsync_end, &mode.vtotal,
2359 hsync, vsync) == 11) {
2360 if (set_sync_flags(&mode, hsync, vsync))
2361 return -1;
2362
2363 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2364 strcpy(mode.name, mode_name);
2365
2366 mode.clock = fclock * 1000;
2367 } else
2368 return -1;
2369
2370 output->crtc_mode = mode;
2371
2372 return 0;
2373}
2374
Scott Moreau8ab5d452012-07-30 19:51:08 -06002375static void
2376output_section_done(void *data)
2377{
2378 struct drm_configured_output *output;
2379
2380 output = malloc(sizeof *output);
2381
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002382 if (!output || !output_name || !output_mode) {
2383 free(output_name);
2384 output_name = NULL;
2385 free(output_mode);
2386 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002387 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002388 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002389
2390 output->config = OUTPUT_CONFIG_INVALID;
2391 output->name = output_name;
2392 output->mode = output_mode;
2393
2394 if (strcmp(output_mode, "off") == 0)
2395 output->config = OUTPUT_CONFIG_OFF;
2396 else if (strcmp(output_mode, "preferred") == 0)
2397 output->config = OUTPUT_CONFIG_PREFERRED;
2398 else if (strcmp(output_mode, "current") == 0)
2399 output->config = OUTPUT_CONFIG_CURRENT;
2400 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2401 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002402 else if (check_for_modeline(output) == 0)
2403 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002404
2405 if (output->config != OUTPUT_CONFIG_INVALID)
2406 wl_list_insert(&configured_output_list, &output->link);
2407 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002408 weston_log("Invalid mode \"%s\" for output %s\n",
2409 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002410 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002411 }
2412}
2413
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002414WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002415backend_init(struct wl_display *display, int argc, char *argv[],
2416 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002417{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002418 int connector = 0, tty = 0;
2419 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002420
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002421 const struct weston_option drm_options[] = {
2422 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2423 { WESTON_OPTION_STRING, "seat", 0, &seat },
2424 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002425 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002426 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002427
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002428 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002429
Scott Moreau8ab5d452012-07-30 19:51:08 -06002430 wl_list_init(&configured_output_list);
2431
2432 const struct config_key drm_config_keys[] = {
2433 { "name", CONFIG_KEY_STRING, &output_name },
2434 { "mode", CONFIG_KEY_STRING, &output_mode },
2435 };
2436
2437 const struct config_section config_section[] = {
2438 { "output", drm_config_keys,
2439 ARRAY_LENGTH(drm_config_keys), output_section_done },
2440 };
2441
2442 parse_config_file(config_file, config_section,
2443 ARRAY_LENGTH(config_section), NULL);
2444
Daniel Stonec1be8e52012-06-01 11:14:02 -04002445 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2446 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002447}