blob: 8dfe276a48ad34013e2a615c62bef5b522ab1639 [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{
1884 struct drm_seat *master = data;
1885 struct udev_device *udev_device;
1886 struct evdev_input_device *device, *next;
1887 const char *action;
1888 const char *devnode;
1889
1890 udev_device = udev_monitor_receive_device(master->udev_monitor);
1891 if (!udev_device)
1892 return 1;
1893
1894 action = udev_device_get_action(udev_device);
1895 if (action) {
1896 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1897 return 0;
1898
1899 if (!strcmp(action, "add")) {
1900 device_added(udev_device, master);
1901 }
1902 else if (!strcmp(action, "remove")) {
1903 devnode = udev_device_get_devnode(udev_device);
1904 wl_list_for_each_safe(device, next,
1905 &master->devices_list, link)
1906 if (!strcmp(device->devnode, devnode)) {
1907 evdev_input_device_destroy(device);
1908 break;
1909 }
1910 }
1911 }
1912 udev_device_unref(udev_device);
1913
1914 return 0;
1915}
1916
1917static int
1918evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1919{
1920 struct drm_seat *master = (struct drm_seat *) seat_base;
1921 struct wl_event_loop *loop;
1922 struct weston_compositor *c = master->base.compositor;
1923 int fd;
1924
1925 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1926 if (!master->udev_monitor) {
1927 weston_log("udev: failed to create the udev monitor\n");
1928 return 0;
1929 }
1930
1931 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1932 "input", NULL);
1933
1934 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1935 weston_log("udev: failed to bind the udev monitor\n");
1936 udev_monitor_unref(master->udev_monitor);
1937 return 0;
1938 }
1939
1940 loop = wl_display_get_event_loop(c->wl_display);
1941 fd = udev_monitor_get_fd(master->udev_monitor);
1942 master->udev_monitor_source =
1943 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1944 evdev_udev_handler, master);
1945 if (!master->udev_monitor_source) {
1946 udev_monitor_unref(master->udev_monitor);
1947 return 0;
1948 }
1949
1950 return 1;
1951}
1952
1953static void
1954evdev_disable_udev_monitor(struct weston_seat *seat_base)
1955{
1956 struct drm_seat *seat = (struct drm_seat *) seat_base;
1957
1958 if (!seat->udev_monitor)
1959 return;
1960
1961 udev_monitor_unref(seat->udev_monitor);
1962 seat->udev_monitor = NULL;
1963 wl_event_source_remove(seat->udev_monitor_source);
1964 seat->udev_monitor_source = NULL;
1965}
1966
1967static void
1968drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1969{
1970 struct drm_seat *seat = (struct drm_seat *) seat_base;
1971
1972 evdev_led_update(&seat->devices_list, leds);
1973}
1974
1975static void
1976evdev_input_create(struct weston_compositor *c, struct udev *udev,
1977 const char *seat_id)
1978{
1979 struct drm_seat *seat;
1980
1981 seat = malloc(sizeof *seat);
1982 if (seat == NULL)
1983 return;
1984
1985 memset(seat, 0, sizeof *seat);
1986 weston_seat_init(&seat->base, c);
1987 seat->base.led_update = drm_led_update;
1988
1989 wl_list_init(&seat->devices_list);
1990 seat->seat_id = strdup(seat_id);
1991 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1992 free(seat->seat_id);
1993 free(seat);
1994 return;
1995 }
1996
1997 evdev_add_devices(udev, &seat->base);
1998
1999 c->seat = &seat->base;
2000}
2001
2002static void
2003evdev_remove_devices(struct weston_seat *seat_base)
2004{
2005 struct drm_seat *seat = (struct drm_seat *) seat_base;
2006 struct evdev_input_device *device, *next;
2007
2008 wl_list_for_each_safe(device, next, &seat->devices_list, link)
2009 evdev_input_device_destroy(device);
2010
2011 notify_keyboard_focus_out(&seat->base.seat);
2012}
2013
2014static void
2015evdev_input_destroy(struct weston_seat *seat_base)
2016{
2017 struct drm_seat *seat = (struct drm_seat *) seat_base;
2018
2019 evdev_remove_devices(seat_base);
2020 evdev_disable_udev_monitor(&seat->base);
2021
2022 weston_seat_release(seat_base);
2023 free(seat->seat_id);
2024 free(seat);
2025}
2026
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002027static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002028drm_free_configured_output(struct drm_configured_output *output)
2029{
2030 free(output->name);
2031 free(output->mode);
2032 free(output);
2033}
2034
2035static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002036drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002037{
2038 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002039 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002040 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002041
Daniel Stone37816df2012-05-16 18:45:18 +01002042 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2043 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002044 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002045 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002046
2047 wl_event_source_remove(d->udev_drm_source);
2048 wl_event_source_remove(d->drm_source);
2049
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002050 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002051
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002052 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002053 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002054 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002055 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002056 eglReleaseThread();
2057
Matt Roper361d2ad2011-08-29 13:52:23 -07002058 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002059 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002060 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002061 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002062 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002063
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002064 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002065}
2066
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002067static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002068drm_compositor_set_modes(struct drm_compositor *compositor)
2069{
2070 struct drm_output *output;
2071 struct drm_mode *drm_mode;
2072 int ret;
2073
2074 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2075 drm_mode = (struct drm_mode *) output->base.current;
2076 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002077 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002078 &output->connector_id, 1,
2079 &drm_mode->mode_info);
2080 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002081 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002082 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002083 drm_mode->base.width, drm_mode->base.height,
2084 output->base.x, output->base.y);
2085 }
2086 }
2087}
2088
2089static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002090vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002091{
2092 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002093 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002094 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002095 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002096
2097 switch (event) {
2098 case TTY_ENTER_VT:
2099 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002100 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002101 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002102 wl_display_terminate(compositor->wl_display);
2103 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002104 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002105 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002106 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002107 wl_list_for_each(seat, &compositor->seat_list, link) {
2108 evdev_add_devices(ec->udev, seat);
2109 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002110 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002111 break;
2112 case TTY_LEAVE_VT:
Daniel Stone37816df2012-05-16 18:45:18 +01002113 wl_list_for_each(seat, &compositor->seat_list, link) {
2114 evdev_disable_udev_monitor(seat);
2115 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002116 }
2117
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002118 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002119 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002120 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002121
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002122 /* If we have a repaint scheduled (either from a
2123 * pending pageflip or the idle handler), make sure we
2124 * cancel that so we don't try to pageflip when we're
2125 * vt switched away. The SLEEPING state will prevent
2126 * further attemps at repainting. When we switch
2127 * back, we schedule a repaint, which will process
2128 * pending frame callbacks. */
2129
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002130 wl_list_for_each(output, &ec->base.output_list, base.link) {
2131 output->base.repaint_needed = 0;
2132 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002133 }
2134
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002135 output = container_of(ec->base.output_list.next,
2136 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002137
2138 wl_list_for_each(sprite, &ec->sprite_list, link)
2139 drmModeSetPlane(ec->drm.fd,
2140 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002141 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002142 0, 0, 0, 0, 0, 0, 0, 0);
2143
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002144 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002145 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002146
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002147 break;
2148 };
2149}
2150
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002151static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002152switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002153{
2154 struct drm_compositor *ec = data;
2155
Daniel Stone325fc2d2012-05-30 16:31:58 +01002156 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002157}
2158
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002159static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002160drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002161 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002162 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002163{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002164 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002165 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002166 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002167 struct udev_device *device, *drm_device;
2168 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002169 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002170 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002171 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002172
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002173 weston_log("initializing drm backend\n");
2174
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002175 ec = malloc(sizeof *ec);
2176 if (ec == NULL)
2177 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002178 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002179
2180 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002181 config_file) < 0) {
2182 weston_log("weston_compositor_init failed\n");
2183 goto err_base;
2184 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002185
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002186 ec->udev = udev_new();
2187 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002188 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002189 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002190 }
2191
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002192 ec->base.wl_display = display;
2193 ec->tty = tty_create(&ec->base, vt_func, tty);
2194 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002195 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002196 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002197 }
2198
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002199 e = udev_enumerate_new(ec->udev);
2200 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002201 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002202
Benjamin Franzke117483d2011-08-30 11:38:26 +02002203 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002204 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002205 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002206 path = udev_list_entry_get_name(entry);
2207 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002208 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002209 udev_device_get_property_value(device, "ID_SEAT");
2210 if (!device_seat)
2211 device_seat = default_seat;
2212 if (strcmp(device_seat, seat) == 0) {
2213 drm_device = device;
2214 break;
2215 }
2216 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002217 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002218
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002219 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002220 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002221 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002222 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002223
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002224 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002225 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002226 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002227 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002228
2229 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002230 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002231
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002232 ec->base.focus = 1;
2233
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002234 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002235
Daniel Stone725c2c32012-06-22 14:04:36 +01002236 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002237 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002238
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002239 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002240 weston_compositor_add_key_binding(&ec->base, key,
2241 MODIFIER_CTRL | MODIFIER_ALT,
2242 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002243
Jesse Barnes58ef3792012-02-23 09:45:49 -05002244 wl_list_init(&ec->sprite_list);
2245 create_sprites(ec);
2246
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002247 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002248 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002249 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002250 }
2251
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002252 path = NULL;
2253
Tiago Vignattice03ec32011-12-19 01:14:03 +02002254 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002255
2256 loop = wl_display_get_event_loop(ec->base.wl_display);
2257 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002258 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002259 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002260
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002261 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2262 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002263 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002264 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002265 }
2266 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2267 "drm", NULL);
2268 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002269 wl_event_loop_add_fd(loop,
2270 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002271 WL_EVENT_READABLE, udev_drm_event, ec);
2272
2273 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002274 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002275 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002276 }
2277
Daniel Stonea96b93c2012-06-22 14:04:37 +01002278 udev_device_unref(drm_device);
2279 udev_enumerate_unref(e);
2280
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002281 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002282
2283err_udev_monitor:
2284 wl_event_source_remove(ec->udev_drm_source);
2285 udev_monitor_unref(ec->udev_monitor);
2286err_drm_source:
2287 wl_event_source_remove(ec->drm_source);
2288 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2289 evdev_input_destroy(weston_seat);
2290err_sprite:
2291 destroy_sprites(ec);
2292err_egl:
2293 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2294 EGL_NO_CONTEXT);
2295 eglTerminate(ec->base.egl_display);
2296 eglReleaseThread();
2297 gbm_device_destroy(ec->gbm);
2298err_udev_dev:
2299 udev_device_unref(drm_device);
2300err_udev_enum:
2301 udev_enumerate_unref(e);
2302 tty_destroy(ec->tty);
2303err_udev:
2304 udev_unref(ec->udev);
2305err_compositor:
2306 weston_compositor_shutdown(&ec->base);
2307err_base:
2308 free(ec);
2309 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002310}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002311
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002312static int
2313set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2314{
2315 mode->flags = 0;
2316
2317 if (strcmp(hsync, "+hsync") == 0)
2318 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2319 else if (strcmp(hsync, "-hsync") == 0)
2320 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2321 else
2322 return -1;
2323
2324 if (strcmp(vsync, "+vsync") == 0)
2325 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2326 else if (strcmp(vsync, "-vsync") == 0)
2327 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2328 else
2329 return -1;
2330
2331 return 0;
2332}
2333
2334static int
2335check_for_modeline(struct drm_configured_output *output)
2336{
2337 drmModeModeInfo mode;
2338 char hsync[16];
2339 char vsync[16];
2340 char mode_name[16];
2341 float fclock;
2342
2343 mode.type = DRM_MODE_TYPE_USERDEF;
2344 mode.hskew = 0;
2345 mode.vscan = 0;
2346 mode.vrefresh = 0;
2347
2348 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2349 &fclock, &mode.hdisplay,
2350 &mode.hsync_start,
2351 &mode.hsync_end, &mode.htotal,
2352 &mode.vdisplay,
2353 &mode.vsync_start,
2354 &mode.vsync_end, &mode.vtotal,
2355 hsync, vsync) == 11) {
2356 if (set_sync_flags(&mode, hsync, vsync))
2357 return -1;
2358
2359 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2360 strcpy(mode.name, mode_name);
2361
2362 mode.clock = fclock * 1000;
2363 } else
2364 return -1;
2365
2366 output->crtc_mode = mode;
2367
2368 return 0;
2369}
2370
Scott Moreau8ab5d452012-07-30 19:51:08 -06002371static void
2372output_section_done(void *data)
2373{
2374 struct drm_configured_output *output;
2375
2376 output = malloc(sizeof *output);
2377
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002378 if (!output || !output_name || !output_mode) {
2379 free(output_name);
2380 output_name = NULL;
2381 free(output_mode);
2382 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002383 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002384 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002385
2386 output->config = OUTPUT_CONFIG_INVALID;
2387 output->name = output_name;
2388 output->mode = output_mode;
2389
2390 if (strcmp(output_mode, "off") == 0)
2391 output->config = OUTPUT_CONFIG_OFF;
2392 else if (strcmp(output_mode, "preferred") == 0)
2393 output->config = OUTPUT_CONFIG_PREFERRED;
2394 else if (strcmp(output_mode, "current") == 0)
2395 output->config = OUTPUT_CONFIG_CURRENT;
2396 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2397 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002398 else if (check_for_modeline(output) == 0)
2399 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002400
2401 if (output->config != OUTPUT_CONFIG_INVALID)
2402 wl_list_insert(&configured_output_list, &output->link);
2403 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002404 weston_log("Invalid mode \"%s\" for output %s\n",
2405 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002406 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002407 }
2408}
2409
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002410WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002411backend_init(struct wl_display *display, int argc, char *argv[],
2412 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002413{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002414 int connector = 0, tty = 0;
2415 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002416
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002417 const struct weston_option drm_options[] = {
2418 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2419 { WESTON_OPTION_STRING, "seat", 0, &seat },
2420 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002421 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002422 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002423
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002424 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002425
Scott Moreau8ab5d452012-07-30 19:51:08 -06002426 wl_list_init(&configured_output_list);
2427
2428 const struct config_key drm_config_keys[] = {
2429 { "name", CONFIG_KEY_STRING, &output_name },
2430 { "mode", CONFIG_KEY_STRING, &output_mode },
2431 };
2432
2433 const struct config_section config_section[] = {
2434 { "output", drm_config_keys,
2435 ARRAY_LENGTH(drm_config_keys), output_section_done },
2436 };
2437
2438 parse_config_file(config_file, config_section,
2439 ARRAY_LENGTH(config_section), NULL);
2440
Daniel Stonec1be8e52012-06-01 11:14:02 -04002441 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2442 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002443}