blob: d35588c067a6916b2b3770795312e6c7b4db24b6 [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øgsberg79af73e2012-08-03 15:45:23 -0400735 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400736 if (es == NULL) {
737 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
738 return;
739 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500740
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400741 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
742 pixman_region32_fini(&output->cursor_plane.damage);
743 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400744 output->current_cursor ^= 1;
745 bo = output->cursor_bo[output->current_cursor];
746 memset(buf, 0, sizeof buf);
747 stride = wl_shm_buffer_get_stride(es->buffer);
748 s = wl_shm_buffer_get_data(es->buffer);
749 for (i = 0; i < es->geometry.height; i++)
750 memcpy(buf + i * 64, s + i * stride,
751 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500752
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400753 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300754 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400755
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400756 handle = gbm_bo_get_handle(bo).s32;
757 if (drmModeSetCursor(c->drm.fd,
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400758 output->crtc_id, handle, 64, 64))
Pekka Paalanenae29da22012-08-06 14:57:05 +0300759 weston_log("failed to set cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400760 }
761
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400762 x = es->geometry.x - output->base.x;
763 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400764 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
765 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y))
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400766 weston_log("failed to move cursor: %m\n");
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400767 output->cursor_plane.x = x;
768 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400769 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500770}
771
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772static void
773drm_assign_planes(struct weston_output *output)
774{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400775 struct drm_compositor *c =
776 (struct drm_compositor *) output->compositor;
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øgsberg65a11e12012-08-03 11:30:18 -0400795 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400796 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797 pixman_region32_init(&surface_overlap);
798 pixman_region32_intersect(&surface_overlap, &overlap,
799 &es->transform.boundingbox);
800
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400801 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400802 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400803 next_plane = primary;
804 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400805 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400806 if (next_plane == NULL)
807 next_plane = drm_output_prepare_scanout_surface(output, es);
808 if (next_plane == NULL)
809 next_plane = drm_output_prepare_overlay_surface(output, es);
810 if (next_plane == NULL)
811 next_plane = primary;
812 weston_surface_move_to_plane(es, next_plane);
813 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814 pixman_region32_union(&overlap, &overlap,
815 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400816
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817 pixman_region32_fini(&surface_overlap);
818 }
819 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500820}
821
Matt Roper361d2ad2011-08-29 13:52:23 -0700822static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500823drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700824{
825 struct drm_output *output = (struct drm_output *) output_base;
826 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200827 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700828 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700829
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200830 if (output->backlight)
831 backlight_destroy(output->backlight);
832
Matt Roper361d2ad2011-08-29 13:52:23 -0700833 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400834 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700835
836 /* Restore original CRTC state */
837 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200838 origcrtc->x, origcrtc->y,
839 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700840 drmModeFreeCrtc(origcrtc);
841
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200842 c->crtc_allocator &= ~(1 << output->crtc_id);
843 c->connector_allocator &= ~(1 << output->connector_id);
844
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400845 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400846 gbm_surface_destroy(output->surface);
847
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400848 weston_plane_release(&output->fb_plane);
849 weston_plane_release(&output->cursor_plane);
850
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500851 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200852 wl_list_remove(&output->base.link);
853
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400854 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700855 free(output);
856}
857
Alex Wub7b8bda2012-04-17 17:20:48 +0800858static struct drm_mode *
859choose_mode (struct drm_output *output, struct weston_mode *target_mode)
860{
861 struct drm_mode *tmp_mode = NULL, *mode;
862
863 if (output->base.current->width == target_mode->width &&
864 output->base.current->height == target_mode->height &&
865 (output->base.current->refresh == target_mode->refresh ||
866 target_mode->refresh == 0))
867 return (struct drm_mode *)output->base.current;
868
869 wl_list_for_each(mode, &output->base.mode_list, base.link) {
870 if (mode->mode_info.hdisplay == target_mode->width &&
871 mode->mode_info.vdisplay == target_mode->height) {
872 if (mode->mode_info.vrefresh == target_mode->refresh ||
873 target_mode->refresh == 0) {
874 return mode;
875 } else if (!tmp_mode)
876 tmp_mode = mode;
877 }
878 }
879
880 return tmp_mode;
881}
882
883static int
884drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
885{
886 struct drm_output *output;
887 struct drm_mode *drm_mode;
888 int ret;
889 struct drm_compositor *ec;
890 struct gbm_surface *surface;
891 EGLSurface egl_surface;
892
893 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200894 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800895 return -1;
896 }
897
898 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200899 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800900 return -1;
901 }
902
903 ec = (struct drm_compositor *)output_base->compositor;
904 output = (struct drm_output *)output_base;
905 drm_mode = choose_mode (output, mode);
906
907 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200908 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800909 return -1;
910 } else if (&drm_mode->base == output->base.current) {
911 return 0;
912 } else if (drm_mode->base.width == output->base.current->width &&
913 drm_mode->base.height == output->base.current->height) {
914 /* only change refresh value */
915 ret = drmModeSetCrtc(ec->drm.fd,
916 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300917 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800918 &output->connector_id, 1, &drm_mode->mode_info);
919
920 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200921 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800922 drm_mode->base.width,
923 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400924 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800925 ret = -1;
926 } else {
927 output->base.current->flags = 0;
928 output->base.current = &drm_mode->base;
929 drm_mode->base.flags =
930 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
931 ret = 0;
932 }
933
934 return ret;
935 }
936
937 drm_mode->base.flags =
938 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
939
940 surface = gbm_surface_create(ec->gbm,
941 drm_mode->base.width,
942 drm_mode->base.height,
943 GBM_FORMAT_XRGB8888,
944 GBM_BO_USE_SCANOUT |
945 GBM_BO_USE_RENDERING);
946 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200947 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800948 return -1;
949 }
950
951 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400952 eglCreateWindowSurface(ec->base.egl_display,
953 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800954 surface, NULL);
955
956 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200957 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800958 goto err;
959 }
960
961 ret = drmModeSetCrtc(ec->drm.fd,
962 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300963 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800964 &output->connector_id, 1, &drm_mode->mode_info);
965 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200966 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800967 goto err;
968 }
969
970 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300971 if (output->current) {
972 if (output->current->is_client_buffer)
973 gbm_bo_destroy(output->current->bo);
974 else
975 gbm_surface_release_buffer(output->surface,
976 output->current->bo);
977 }
978 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800979
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300980 if (output->next) {
981 if (output->next->is_client_buffer)
982 gbm_bo_destroy(output->next->bo);
983 else
984 gbm_surface_release_buffer(output->surface,
985 output->next->bo);
986 }
987 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800988
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400989 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800990 gbm_surface_destroy(output->surface);
991 output->egl_surface = egl_surface;
992 output->surface = surface;
993
994 /*update output*/
995 output->base.current = &drm_mode->base;
996 output->base.dirty = 1;
997 weston_output_move(&output->base, output->base.x, output->base.y);
998 return 0;
999
1000err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001001 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001002 gbm_surface_destroy(surface);
1003 return -1;
1004}
1005
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001006static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001007on_drm_input(int fd, uint32_t mask, void *data)
1008{
1009 drmEventContext evctx;
1010
1011 memset(&evctx, 0, sizeof evctx);
1012 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1013 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001014 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001015 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001016
1017 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001018}
1019
1020static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001021init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001022{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001023 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001024 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001025 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001026 static const EGLint context_attribs[] = {
1027 EGL_CONTEXT_CLIENT_VERSION, 2,
1028 EGL_NONE
1029 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001030
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001031 static const EGLint config_attribs[] = {
1032 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1033 EGL_RED_SIZE, 1,
1034 EGL_GREEN_SIZE, 1,
1035 EGL_BLUE_SIZE, 1,
1036 EGL_ALPHA_SIZE, 0,
1037 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1038 EGL_NONE
1039 };
1040
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001041 sysnum = udev_device_get_sysnum(device);
1042 if (sysnum)
1043 ec->drm.id = atoi(sysnum);
1044 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001045 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001046 return -1;
1047 }
1048
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001049 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001050 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001051 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001052 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001053 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001054 udev_device_get_devnode(device));
1055 return -1;
1056 }
1057
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001058 weston_log("using %s\n", filename);
1059
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001060 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001061 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001062 ec->base.egl_display = eglGetDisplay(ec->gbm);
1063 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001064 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001065 return -1;
1066 }
1067
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001068 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001069 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001070 return -1;
1071 }
1072
Darxus55973f22010-11-22 21:24:39 -05001073 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001074 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001075 return -1;
1076 }
1077
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001078 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1079 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001080 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001081 return -1;
1082 }
1083
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001084 ec->base.egl_context =
1085 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1086 EGL_NO_CONTEXT, context_attribs);
1087 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001088 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001089 return -1;
1090 }
1091
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001092 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1093 GBM_FORMAT_XRGB8888,
1094 GBM_BO_USE_RENDERING);
1095 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001096 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001097 return -1;
1098 }
1099
1100 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001101 eglCreateWindowSurface(ec->base.egl_display,
1102 ec->base.egl_config,
1103 ec->dummy_surface,
1104 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001105 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001106 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001107 return -1;
1108 }
1109
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001110 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1111 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001112 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001113 return -1;
1114 }
1115
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001116 return 0;
1117}
1118
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001119static int
1120drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1121{
1122 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001123 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001124
1125 mode = malloc(sizeof *mode);
1126 if (mode == NULL)
1127 return -1;
1128
1129 mode->base.flags = 0;
1130 mode->base.width = info->hdisplay;
1131 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001132
1133 /* Calculate higher precision (mHz) refresh rate */
1134 refresh = (info->clock * 1000000LL / info->htotal +
1135 info->vtotal / 2) / info->vtotal;
1136
1137 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1138 refresh *= 2;
1139 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1140 refresh /= 2;
1141 if (info->vscan > 1)
1142 refresh /= info->vscan;
1143
1144 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001145 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001146
1147 if (info->type & DRM_MODE_TYPE_PREFERRED)
1148 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1149
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001150 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1151
1152 return 0;
1153}
1154
1155static int
1156drm_subpixel_to_wayland(int drm_value)
1157{
1158 switch (drm_value) {
1159 default:
1160 case DRM_MODE_SUBPIXEL_UNKNOWN:
1161 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1162 case DRM_MODE_SUBPIXEL_NONE:
1163 return WL_OUTPUT_SUBPIXEL_NONE;
1164 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1165 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1166 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1167 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1168 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1169 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1170 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1171 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1172 }
1173}
1174
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001175static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001176sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001177{
1178 struct drm_sprite *sprite =
1179 container_of(listener, struct drm_sprite,
1180 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001181 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001182
1183 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001184 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1185 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001186}
1187
1188static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001189sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001190{
1191 struct drm_sprite *sprite =
1192 container_of(listener, struct drm_sprite,
1193 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001194 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001195
1196 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001197 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1198 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001199}
1200
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001201/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001202static uint32_t
1203drm_get_backlight(struct drm_output *output)
1204{
1205 long brightness, max_brightness, norm;
1206
1207 brightness = backlight_get_brightness(output->backlight);
1208 max_brightness = backlight_get_max_brightness(output->backlight);
1209
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001210 /* convert it on a scale of 0 to 255 */
1211 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001212
1213 return (uint32_t) norm;
1214}
1215
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001216/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001217static void
1218drm_set_backlight(struct weston_output *output_base, uint32_t value)
1219{
1220 struct drm_output *output = (struct drm_output *) output_base;
1221 long max_brightness, new_brightness;
1222
1223 if (!output->backlight)
1224 return;
1225
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001226 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001227 return;
1228
1229 max_brightness = backlight_get_max_brightness(output->backlight);
1230
1231 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001232 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001233
1234 backlight_set_brightness(output->backlight, new_brightness);
1235}
1236
1237static drmModePropertyPtr
1238drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1239{
1240 drmModePropertyPtr props;
1241 int i;
1242
1243 for (i = 0; i < connector->count_props; i++) {
1244 props = drmModeGetProperty(fd, connector->props[i]);
1245 if (!props)
1246 continue;
1247
1248 if (!strcmp(props->name, name))
1249 return props;
1250
1251 drmModeFreeProperty(props);
1252 }
1253
1254 return NULL;
1255}
1256
1257static void
1258drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1259{
1260 struct drm_output *output = (struct drm_output *) output_base;
1261 struct weston_compositor *ec = output_base->compositor;
1262 struct drm_compositor *c = (struct drm_compositor *) ec;
1263 drmModeConnectorPtr connector;
1264 drmModePropertyPtr prop;
1265
1266 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1267 if (!connector)
1268 return;
1269
1270 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1271 if (!prop) {
1272 drmModeFreeConnector(connector);
1273 return;
1274 }
1275
1276 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1277 prop->prop_id, level);
1278 drmModeFreeProperty(prop);
1279 drmModeFreeConnector(connector);
1280}
1281
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001282static const char *connector_type_names[] = {
1283 "None",
1284 "VGA",
1285 "DVI",
1286 "DVI",
1287 "DVI",
1288 "Composite",
1289 "TV",
1290 "LVDS",
1291 "CTV",
1292 "DIN",
1293 "DP",
1294 "HDMI",
1295 "HDMI",
1296 "TV",
1297 "eDP",
1298};
1299
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001300static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001301find_crtc_for_connector(struct drm_compositor *ec,
1302 drmModeRes *resources, drmModeConnector *connector)
1303{
1304 drmModeEncoder *encoder;
1305 uint32_t possible_crtcs;
1306 int i, j;
1307
1308 for (j = 0; j < connector->count_encoders; j++) {
1309 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1310 if (encoder == NULL) {
1311 weston_log("Failed to get encoder.\n");
1312 return -1;
1313 }
1314 possible_crtcs = encoder->possible_crtcs;
1315 drmModeFreeEncoder(encoder);
1316
1317 for (i = 0; i < resources->count_crtcs; i++) {
1318 if (possible_crtcs & (1 << i) &&
1319 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1320 return i;
1321 }
1322 }
1323
1324 return -1;
1325}
1326
1327static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001328create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001329 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001330 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001331 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001332{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001333 struct drm_output *output;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001334 struct drm_mode *drm_mode, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001335 struct weston_mode *m, *preferred, *current, *configured;
1336 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001337 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001338 drmModeModeInfo crtc_mode;
1339 drmModeCrtc *crtc;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001340 int i, ret;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001341 char name[32];
1342 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001343
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001344 i = find_crtc_for_connector(ec, resources, connector);
1345 if (i < 0) {
1346 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001347 return -1;
1348 }
1349
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001350 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001351 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001352 return -1;
1353
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001354 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001355 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1356 output->base.make = "unknown";
1357 output->base.model = "unknown";
1358 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001359
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001360 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1361 type_name = connector_type_names[connector->connector_type];
1362 else
1363 type_name = "UNKNOWN";
1364 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1365 output->name = strdup(name);
1366
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001367 output->crtc_id = resources->crtcs[i];
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001368 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001369 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001370 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001371
Matt Roper361d2ad2011-08-29 13:52:23 -07001372 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1373
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001374 /* Get the current mode on the crtc that's currently driving
1375 * this connector. */
1376 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001377 memset(&crtc_mode, 0, sizeof crtc_mode);
1378 if (encoder != NULL) {
1379 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1380 drmModeFreeEncoder(encoder);
1381 if (crtc == NULL)
1382 goto err_free;
1383 if (crtc->mode_valid)
1384 crtc_mode = crtc->mode;
1385 drmModeFreeCrtc(crtc);
1386 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001387
David Herrmann0f0d54e2011-12-08 17:05:45 +01001388 for (i = 0; i < connector->count_modes; i++) {
1389 ret = drm_output_add_mode(output, &connector->modes[i]);
1390 if (ret)
1391 goto err_free;
1392 }
1393
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001394 preferred = NULL;
1395 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001396 configured = NULL;
1397
1398 wl_list_for_each(temp, &configured_output_list, link) {
1399 if (strcmp(temp->name, output->name) == 0) {
1400 weston_log("%s mode \"%s\" in config\n",
1401 temp->name, temp->mode);
1402 o = temp;
1403 break;
1404 }
1405 }
1406
1407 if (o && strcmp("off", o->mode) == 0) {
1408 weston_log("Disabling output %s\n", o->name);
1409
1410 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1411 0, 0, 0, 0, 0, NULL);
1412 goto err_free;
1413 }
1414
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001415 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001416 if (o && o->width == drm_mode->base.width &&
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001417 o->height == drm_mode->base.height &&
1418 o->config == OUTPUT_CONFIG_MODE)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001419 configured = &drm_mode->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001420 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001421 current = &drm_mode->base;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001422 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
1423 preferred = &drm_mode->base;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001424 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001425
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001426 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
1427 ret = drm_output_add_mode(output, &o->crtc_mode);
1428 if (ret)
1429 goto err_free;
1430 configured = container_of(output->base.mode_list.prev,
1431 struct weston_mode, link);
1432 current = configured;
1433 }
1434
Wang Quanxianacb805a2012-07-30 18:09:46 -04001435 if (current == NULL && crtc_mode.clock != 0) {
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001436 ret = drm_output_add_mode(output, &crtc_mode);
1437 if (ret)
1438 goto err_free;
1439 current = container_of(output->base.mode_list.prev,
1440 struct weston_mode, link);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001441 }
1442
Scott Moreau8ab5d452012-07-30 19:51:08 -06001443 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1444 configured = current;
1445
Wang Quanxianacb805a2012-07-30 18:09:46 -04001446 if (option_current_mode && current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001447 output->base.current = current;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001448 else if (configured)
1449 output->base.current = configured;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001450 else if (preferred)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001451 output->base.current = preferred;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001452 else if (current)
1453 output->base.current = current;
1454
1455 if (output->base.current == NULL) {
1456 weston_log("no available modes for %s\n", output->name);
1457 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001458 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001459
Wang Quanxianacb805a2012-07-30 18:09:46 -04001460 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1461
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001462 output->surface = gbm_surface_create(ec->gbm,
1463 output->base.current->width,
1464 output->base.current->height,
1465 GBM_FORMAT_XRGB8888,
1466 GBM_BO_USE_SCANOUT |
1467 GBM_BO_USE_RENDERING);
1468 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001469 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001470 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001471 }
1472
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001473 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001474 eglCreateWindowSurface(ec->base.egl_display,
1475 ec->base.egl_config,
1476 output->surface,
1477 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001478 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001479 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001480 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001481 }
1482
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001483 output->cursor_bo[0] =
1484 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1485 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1486 output->cursor_bo[1] =
1487 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1488 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1489
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001490 output->backlight = backlight_init(drm_device,
1491 connector->connector_type);
1492 if (output->backlight) {
1493 output->base.set_backlight = drm_set_backlight;
1494 output->base.backlight_current = drm_get_backlight(output);
1495 }
1496
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001497 weston_output_init(&output->base, &ec->base, x, y,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001498 connector->mmWidth, connector->mmHeight,
1499 WL_OUTPUT_FLIPPED);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001500
1501 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1502
Alex Wubd3354b2012-04-17 17:20:49 +08001503 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001504 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001505 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001506 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001507 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001508 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001509
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001510 weston_plane_init(&output->cursor_plane, 0, 0);
1511 weston_plane_init(&output->fb_plane, 0, 0);
1512
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001513 weston_log("Output %s, (connector %d, crtc %d)\n",
1514 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001515 wl_list_for_each(m, &output->base.mode_list, link)
1516 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1517 m->width, m->height, m->refresh / 1000.0,
1518 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1519 ", preferred" : "",
1520 m->flags & WL_OUTPUT_MODE_CURRENT ?
1521 ", current" : "",
1522 connector->count_modes == 0 ?
1523 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001524
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001525 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001526
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001527err_surface:
1528 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001529err_free:
1530 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1531 base.link) {
1532 wl_list_remove(&drm_mode->base.link);
1533 free(drm_mode);
1534 }
1535
1536 drmModeFreeCrtc(output->original_crtc);
1537 ec->crtc_allocator &= ~(1 << output->crtc_id);
1538 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001539 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001540 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001541
David Herrmann0f0d54e2011-12-08 17:05:45 +01001542 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001543}
1544
Jesse Barnes58ef3792012-02-23 09:45:49 -05001545static void
1546create_sprites(struct drm_compositor *ec)
1547{
1548 struct drm_sprite *sprite;
1549 drmModePlaneRes *plane_res;
1550 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001551 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001552
1553 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1554 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001555 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001556 strerror(errno));
1557 return;
1558 }
1559
1560 for (i = 0; i < plane_res->count_planes; i++) {
1561 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1562 if (!plane)
1563 continue;
1564
1565 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1566 plane->count_formats));
1567 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001568 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001569 __func__);
1570 free(plane);
1571 continue;
1572 }
1573
1574 memset(sprite, 0, sizeof *sprite);
1575
1576 sprite->possible_crtcs = plane->possible_crtcs;
1577 sprite->plane_id = plane->plane_id;
1578 sprite->surface = NULL;
1579 sprite->pending_surface = NULL;
1580 sprite->fb_id = 0;
1581 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001582 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1583 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001584 sprite_handle_pending_buffer_destroy;
1585 sprite->compositor = ec;
1586 sprite->count_formats = plane->count_formats;
1587 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001588 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001589 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001590 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001591
1592 wl_list_insert(&ec->sprite_list, &sprite->link);
1593 }
1594
1595 free(plane_res->planes);
1596 free(plane_res);
1597}
1598
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001599static void
1600destroy_sprites(struct drm_compositor *compositor)
1601{
1602 struct drm_sprite *sprite, *next;
1603 struct drm_output *output;
1604
1605 output = container_of(compositor->base.output_list.next,
1606 struct drm_output, base.link);
1607
1608 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1609 drmModeSetPlane(compositor->drm.fd,
1610 sprite->plane_id,
1611 output->crtc_id, 0, 0,
1612 0, 0, 0, 0, 0, 0, 0, 0);
1613 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001614 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001615 free(sprite);
1616 }
1617}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001618
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001619static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001620create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001621 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001622{
1623 drmModeConnector *connector;
1624 drmModeRes *resources;
1625 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001626 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001627
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001628 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001629 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001630 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001631 return -1;
1632 }
1633
Jesse Barnes58ef3792012-02-23 09:45:49 -05001634 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001635 if (!ec->crtcs) {
1636 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001637 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001638 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001639
1640 ec->num_crtcs = resources->count_crtcs;
1641 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1642
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001643 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001644 connector = drmModeGetConnector(ec->drm.fd,
1645 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001646 if (connector == NULL)
1647 continue;
1648
1649 if (connector->connection == DRM_MODE_CONNECTED &&
1650 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001651 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001652 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001653 connector, x, y,
1654 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001655 drmModeFreeConnector(connector);
1656 continue;
1657 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001658
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001659 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001660 struct weston_output,
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001661 link)->current->width;
1662 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001663
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001664 drmModeFreeConnector(connector);
1665 }
1666
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001667 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001668 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001669 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001670 return -1;
1671 }
1672
1673 drmModeFreeResources(resources);
1674
1675 return 0;
1676}
1677
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001678static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001679update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001680{
1681 drmModeConnector *connector;
1682 drmModeRes *resources;
1683 struct drm_output *output, *next;
1684 int x = 0, y = 0;
1685 int x_offset = 0, y_offset = 0;
1686 uint32_t connected = 0, disconnects = 0;
1687 int i;
1688
1689 resources = drmModeGetResources(ec->drm.fd);
1690 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001691 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001692 return;
1693 }
1694
1695 /* collect new connects */
1696 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001697 int connector_id = resources->connectors[i];
1698
1699 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001700 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001701 continue;
1702
David Herrmann7551cff2011-12-08 17:05:43 +01001703 if (connector->connection != DRM_MODE_CONNECTED) {
1704 drmModeFreeConnector(connector);
1705 continue;
1706 }
1707
Benjamin Franzke117483d2011-08-30 11:38:26 +02001708 connected |= (1 << connector_id);
1709
1710 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001711 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001712 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001713 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001714
1715 /* XXX: not yet needed, we die with 0 outputs */
1716 if (!wl_list_empty(&ec->base.output_list))
Benjamin Franzke117483d2011-08-30 11:38:26 +02001717 x = last->x + last->current->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718 else
1719 x = 0;
1720 y = 0;
1721 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001722 connector, x, y,
1723 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001724 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001725
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001726 }
1727 drmModeFreeConnector(connector);
1728 }
1729 drmModeFreeResources(resources);
1730
1731 disconnects = ec->connector_allocator & ~connected;
1732 if (disconnects) {
1733 wl_list_for_each_safe(output, next, &ec->base.output_list,
1734 base.link) {
1735 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001736 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001737 output->base.x - x_offset,
1738 output->base.y - y_offset);
1739 }
1740
1741 if (disconnects & (1 << output->connector_id)) {
1742 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001743 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001744 output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001745 x_offset += output->base.current->width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001746 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001747 }
1748 }
1749 }
1750
1751 /* FIXME: handle zero outputs, without terminating */
1752 if (ec->connector_allocator == 0)
1753 wl_display_terminate(ec->base.wl_display);
1754}
1755
1756static int
David Herrmannd7488c22012-03-11 20:05:21 +01001757udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001758{
David Herrmannd7488c22012-03-11 20:05:21 +01001759 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001760 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001761
1762 sysnum = udev_device_get_sysnum(device);
1763 if (!sysnum || atoi(sysnum) != ec->drm.id)
1764 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001765
David Herrmann6ac52db2012-03-11 20:05:22 +01001766 val = udev_device_get_property_value(device, "HOTPLUG");
1767 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001768 return 0;
1769
David Herrmann6ac52db2012-03-11 20:05:22 +01001770 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001771}
1772
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001773static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001774udev_drm_event(int fd, uint32_t mask, void *data)
1775{
1776 struct drm_compositor *ec = data;
1777 struct udev_device *event;
1778
1779 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001780
David Herrmannd7488c22012-03-11 20:05:21 +01001781 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001782 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001783
1784 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001785
1786 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001787}
1788
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001789static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001790drm_restore(struct weston_compositor *ec)
1791{
1792 struct drm_compositor *d = (struct drm_compositor *) ec;
1793
1794 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1795 weston_log("failed to drop master: %m\n");
1796 tty_reset(d->tty);
1797}
1798
Pekka Paalanen33156972012-08-03 13:30:30 -04001799static const char default_seat[] = "seat0";
1800
1801static void
1802device_added(struct udev_device *udev_device, struct drm_seat *master)
1803{
1804 struct weston_compositor *c;
1805 struct evdev_input_device *device;
1806 const char *devnode;
1807 const char *device_seat;
1808 int fd;
1809
1810 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1811 if (!device_seat)
1812 device_seat = default_seat;
1813
1814 if (strcmp(device_seat, master->seat_id))
1815 return;
1816
1817 c = master->base.compositor;
1818 devnode = udev_device_get_devnode(udev_device);
1819
1820 /* Use non-blocking mode so that we can loop on read on
1821 * evdev_input_device_data() until all events on the fd are
1822 * read. mtdev_get() also expects this. */
1823 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1824 if (fd < 0) {
1825 weston_log("opening input device '%s' failed.\n", devnode);
1826 return;
1827 }
1828
1829 device = evdev_input_device_create(&master->base, devnode, fd);
1830 if (!device) {
1831 close(fd);
1832 weston_log("not using input device '%s'.\n", devnode);
1833 return;
1834 }
1835
1836 wl_list_insert(master->devices_list.prev, &device->link);
1837}
1838
1839static void
1840evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1841{
1842 struct drm_seat *seat = (struct drm_seat *) seat_base;
1843 struct udev_enumerate *e;
1844 struct udev_list_entry *entry;
1845 struct udev_device *device;
1846 const char *path, *sysname;
1847
1848 e = udev_enumerate_new(udev);
1849 udev_enumerate_add_match_subsystem(e, "input");
1850 udev_enumerate_scan_devices(e);
1851 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1852 path = udev_list_entry_get_name(entry);
1853 device = udev_device_new_from_syspath(udev, path);
1854
1855 sysname = udev_device_get_sysname(device);
1856 if (strncmp("event", sysname, 5) != 0) {
1857 udev_device_unref(device);
1858 continue;
1859 }
1860
1861 device_added(device, seat);
1862
1863 udev_device_unref(device);
1864 }
1865 udev_enumerate_unref(e);
1866
1867 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1868
1869 if (wl_list_empty(&seat->devices_list)) {
1870 weston_log(
1871 "warning: no input devices on entering Weston. "
1872 "Possible causes:\n"
1873 "\t- no permissions to read /dev/input/event*\n"
1874 "\t- seats misconfigured "
1875 "(Weston backend option 'seat', "
1876 "udev device property ID_SEAT)\n");
1877 }
1878}
1879
1880static int
1881evdev_udev_handler(int fd, uint32_t mask, void *data)
1882{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001883 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001884 struct udev_device *udev_device;
1885 struct evdev_input_device *device, *next;
1886 const char *action;
1887 const char *devnode;
1888
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001889 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001890 if (!udev_device)
1891 return 1;
1892
1893 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001894 if (!action)
1895 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001896
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001897 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1898 goto out;
1899
1900 if (!strcmp(action, "add")) {
1901 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001902 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001903 else if (!strcmp(action, "remove")) {
1904 devnode = udev_device_get_devnode(udev_device);
1905 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1906 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001907 weston_log("input device %s, %s removed\n",
1908 device->devname, device->devnode);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001909 evdev_input_device_destroy(device);
1910 break;
1911 }
1912 }
1913
1914out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001915 udev_device_unref(udev_device);
1916
1917 return 0;
1918}
1919
1920static int
1921evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1922{
1923 struct drm_seat *master = (struct drm_seat *) seat_base;
1924 struct wl_event_loop *loop;
1925 struct weston_compositor *c = master->base.compositor;
1926 int fd;
1927
1928 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1929 if (!master->udev_monitor) {
1930 weston_log("udev: failed to create the udev monitor\n");
1931 return 0;
1932 }
1933
1934 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1935 "input", NULL);
1936
1937 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1938 weston_log("udev: failed to bind the udev monitor\n");
1939 udev_monitor_unref(master->udev_monitor);
1940 return 0;
1941 }
1942
1943 loop = wl_display_get_event_loop(c->wl_display);
1944 fd = udev_monitor_get_fd(master->udev_monitor);
1945 master->udev_monitor_source =
1946 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1947 evdev_udev_handler, master);
1948 if (!master->udev_monitor_source) {
1949 udev_monitor_unref(master->udev_monitor);
1950 return 0;
1951 }
1952
1953 return 1;
1954}
1955
1956static void
1957evdev_disable_udev_monitor(struct weston_seat *seat_base)
1958{
1959 struct drm_seat *seat = (struct drm_seat *) seat_base;
1960
1961 if (!seat->udev_monitor)
1962 return;
1963
1964 udev_monitor_unref(seat->udev_monitor);
1965 seat->udev_monitor = NULL;
1966 wl_event_source_remove(seat->udev_monitor_source);
1967 seat->udev_monitor_source = NULL;
1968}
1969
1970static void
1971drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1972{
1973 struct drm_seat *seat = (struct drm_seat *) seat_base;
1974
1975 evdev_led_update(&seat->devices_list, leds);
1976}
1977
1978static void
1979evdev_input_create(struct weston_compositor *c, struct udev *udev,
1980 const char *seat_id)
1981{
1982 struct drm_seat *seat;
1983
1984 seat = malloc(sizeof *seat);
1985 if (seat == NULL)
1986 return;
1987
1988 memset(seat, 0, sizeof *seat);
1989 weston_seat_init(&seat->base, c);
1990 seat->base.led_update = drm_led_update;
1991
1992 wl_list_init(&seat->devices_list);
1993 seat->seat_id = strdup(seat_id);
1994 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1995 free(seat->seat_id);
1996 free(seat);
1997 return;
1998 }
1999
2000 evdev_add_devices(udev, &seat->base);
2001
2002 c->seat = &seat->base;
2003}
2004
2005static void
2006evdev_remove_devices(struct weston_seat *seat_base)
2007{
2008 struct drm_seat *seat = (struct drm_seat *) seat_base;
2009 struct evdev_input_device *device, *next;
2010
2011 wl_list_for_each_safe(device, next, &seat->devices_list, link)
2012 evdev_input_device_destroy(device);
2013
Pekka Paalanend8583512012-08-03 14:39:11 +03002014 if (seat->base.seat.keyboard)
2015 notify_keyboard_focus_out(&seat->base.seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04002016}
2017
2018static void
2019evdev_input_destroy(struct weston_seat *seat_base)
2020{
2021 struct drm_seat *seat = (struct drm_seat *) seat_base;
2022
2023 evdev_remove_devices(seat_base);
2024 evdev_disable_udev_monitor(&seat->base);
2025
2026 weston_seat_release(seat_base);
2027 free(seat->seat_id);
2028 free(seat);
2029}
2030
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002031static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002032drm_free_configured_output(struct drm_configured_output *output)
2033{
2034 free(output->name);
2035 free(output->mode);
2036 free(output);
2037}
2038
2039static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002040drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002041{
2042 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002043 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002044 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002045
Daniel Stone37816df2012-05-16 18:45:18 +01002046 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2047 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002048 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002049 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002050
2051 wl_event_source_remove(d->udev_drm_source);
2052 wl_event_source_remove(d->drm_source);
2053
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002054 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002055
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002056 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002057 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002058 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002059 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002060 eglReleaseThread();
2061
Matt Roper361d2ad2011-08-29 13:52:23 -07002062 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002063 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002064 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002065 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002066 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002067
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002068 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002069}
2070
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002071static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002072drm_compositor_set_modes(struct drm_compositor *compositor)
2073{
2074 struct drm_output *output;
2075 struct drm_mode *drm_mode;
2076 int ret;
2077
2078 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2079 drm_mode = (struct drm_mode *) output->base.current;
2080 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002081 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002082 &output->connector_id, 1,
2083 &drm_mode->mode_info);
2084 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002085 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002086 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002087 drm_mode->base.width, drm_mode->base.height,
2088 output->base.x, output->base.y);
2089 }
2090 }
2091}
2092
2093static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002094vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002095{
2096 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002097 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002098 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002099 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002100
2101 switch (event) {
2102 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002103 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002104 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002105 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002106 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002107 wl_display_terminate(compositor->wl_display);
2108 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002109 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002110 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002111 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002112 wl_list_for_each(seat, &compositor->seat_list, link) {
2113 evdev_add_devices(ec->udev, seat);
2114 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002115 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002116 break;
2117 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002118 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002119 wl_list_for_each(seat, &compositor->seat_list, link) {
2120 evdev_disable_udev_monitor(seat);
2121 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002122 }
2123
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002124 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002125 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002126 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002127
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002128 /* If we have a repaint scheduled (either from a
2129 * pending pageflip or the idle handler), make sure we
2130 * cancel that so we don't try to pageflip when we're
2131 * vt switched away. The SLEEPING state will prevent
2132 * further attemps at repainting. When we switch
2133 * back, we schedule a repaint, which will process
2134 * pending frame callbacks. */
2135
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002136 wl_list_for_each(output, &ec->base.output_list, base.link) {
2137 output->base.repaint_needed = 0;
2138 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002139 }
2140
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002141 output = container_of(ec->base.output_list.next,
2142 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002143
2144 wl_list_for_each(sprite, &ec->sprite_list, link)
2145 drmModeSetPlane(ec->drm.fd,
2146 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002147 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002148 0, 0, 0, 0, 0, 0, 0, 0);
2149
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002150 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002151 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002152
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002153 break;
2154 };
2155}
2156
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002157static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002158switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002159{
2160 struct drm_compositor *ec = data;
2161
Daniel Stone325fc2d2012-05-30 16:31:58 +01002162 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002163}
2164
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002165static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002166drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002167 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002168 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002169{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002170 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002171 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002172 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002173 struct udev_device *device, *drm_device;
2174 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002175 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002176 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002177 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002178
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002179 weston_log("initializing drm backend\n");
2180
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002181 ec = malloc(sizeof *ec);
2182 if (ec == NULL)
2183 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002184 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002185
2186 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002187 config_file) < 0) {
2188 weston_log("weston_compositor_init failed\n");
2189 goto err_base;
2190 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002191
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002192 ec->udev = udev_new();
2193 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002194 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002195 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002196 }
2197
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002198 ec->base.wl_display = display;
2199 ec->tty = tty_create(&ec->base, vt_func, tty);
2200 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002201 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002202 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002203 }
2204
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002205 e = udev_enumerate_new(ec->udev);
2206 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002207 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002208
Benjamin Franzke117483d2011-08-30 11:38:26 +02002209 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002210 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002211 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002212 path = udev_list_entry_get_name(entry);
2213 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002214 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002215 udev_device_get_property_value(device, "ID_SEAT");
2216 if (!device_seat)
2217 device_seat = default_seat;
2218 if (strcmp(device_seat, seat) == 0) {
2219 drm_device = device;
2220 break;
2221 }
2222 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002223 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002224
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002225 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002226 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002227 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002228 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002229
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002230 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002231 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002232 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002233 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002234
2235 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002236 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002237
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002238 ec->base.focus = 1;
2239
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002240 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002241
Daniel Stone725c2c32012-06-22 14:04:36 +01002242 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002243 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002244
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002245 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002246 weston_compositor_add_key_binding(&ec->base, key,
2247 MODIFIER_CTRL | MODIFIER_ALT,
2248 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002249
Jesse Barnes58ef3792012-02-23 09:45:49 -05002250 wl_list_init(&ec->sprite_list);
2251 create_sprites(ec);
2252
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002253 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002254 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002255 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002256 }
2257
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002258 path = NULL;
2259
Tiago Vignattice03ec32011-12-19 01:14:03 +02002260 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002261
2262 loop = wl_display_get_event_loop(ec->base.wl_display);
2263 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002264 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002265 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002266
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002267 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2268 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002269 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002270 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002271 }
2272 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2273 "drm", NULL);
2274 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002275 wl_event_loop_add_fd(loop,
2276 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002277 WL_EVENT_READABLE, udev_drm_event, ec);
2278
2279 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002280 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002281 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002282 }
2283
Daniel Stonea96b93c2012-06-22 14:04:37 +01002284 udev_device_unref(drm_device);
2285 udev_enumerate_unref(e);
2286
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002287 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002288
2289err_udev_monitor:
2290 wl_event_source_remove(ec->udev_drm_source);
2291 udev_monitor_unref(ec->udev_monitor);
2292err_drm_source:
2293 wl_event_source_remove(ec->drm_source);
2294 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2295 evdev_input_destroy(weston_seat);
2296err_sprite:
2297 destroy_sprites(ec);
2298err_egl:
2299 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2300 EGL_NO_CONTEXT);
2301 eglTerminate(ec->base.egl_display);
2302 eglReleaseThread();
2303 gbm_device_destroy(ec->gbm);
2304err_udev_dev:
2305 udev_device_unref(drm_device);
2306err_udev_enum:
2307 udev_enumerate_unref(e);
2308 tty_destroy(ec->tty);
2309err_udev:
2310 udev_unref(ec->udev);
2311err_compositor:
2312 weston_compositor_shutdown(&ec->base);
2313err_base:
2314 free(ec);
2315 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002316}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002317
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002318static int
2319set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2320{
2321 mode->flags = 0;
2322
2323 if (strcmp(hsync, "+hsync") == 0)
2324 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2325 else if (strcmp(hsync, "-hsync") == 0)
2326 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2327 else
2328 return -1;
2329
2330 if (strcmp(vsync, "+vsync") == 0)
2331 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2332 else if (strcmp(vsync, "-vsync") == 0)
2333 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2334 else
2335 return -1;
2336
2337 return 0;
2338}
2339
2340static int
2341check_for_modeline(struct drm_configured_output *output)
2342{
2343 drmModeModeInfo mode;
2344 char hsync[16];
2345 char vsync[16];
2346 char mode_name[16];
2347 float fclock;
2348
2349 mode.type = DRM_MODE_TYPE_USERDEF;
2350 mode.hskew = 0;
2351 mode.vscan = 0;
2352 mode.vrefresh = 0;
2353
2354 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2355 &fclock, &mode.hdisplay,
2356 &mode.hsync_start,
2357 &mode.hsync_end, &mode.htotal,
2358 &mode.vdisplay,
2359 &mode.vsync_start,
2360 &mode.vsync_end, &mode.vtotal,
2361 hsync, vsync) == 11) {
2362 if (set_sync_flags(&mode, hsync, vsync))
2363 return -1;
2364
2365 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2366 strcpy(mode.name, mode_name);
2367
2368 mode.clock = fclock * 1000;
2369 } else
2370 return -1;
2371
2372 output->crtc_mode = mode;
2373
2374 return 0;
2375}
2376
Scott Moreau8ab5d452012-07-30 19:51:08 -06002377static void
2378output_section_done(void *data)
2379{
2380 struct drm_configured_output *output;
2381
2382 output = malloc(sizeof *output);
2383
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002384 if (!output || !output_name || !output_mode) {
2385 free(output_name);
2386 output_name = NULL;
2387 free(output_mode);
2388 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002389 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002390 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002391
2392 output->config = OUTPUT_CONFIG_INVALID;
2393 output->name = output_name;
2394 output->mode = output_mode;
2395
2396 if (strcmp(output_mode, "off") == 0)
2397 output->config = OUTPUT_CONFIG_OFF;
2398 else if (strcmp(output_mode, "preferred") == 0)
2399 output->config = OUTPUT_CONFIG_PREFERRED;
2400 else if (strcmp(output_mode, "current") == 0)
2401 output->config = OUTPUT_CONFIG_CURRENT;
2402 else if (sscanf(output_mode, "%dx%d", &output->width, &output->height) == 2)
2403 output->config = OUTPUT_CONFIG_MODE;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002404 else if (check_for_modeline(output) == 0)
2405 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002406
2407 if (output->config != OUTPUT_CONFIG_INVALID)
2408 wl_list_insert(&configured_output_list, &output->link);
2409 else {
Scott Moreau8ab5d452012-07-30 19:51:08 -06002410 weston_log("Invalid mode \"%s\" for output %s\n",
2411 output_mode, output_name);
Scott Moreauc50645c2012-07-31 22:29:56 -06002412 drm_free_configured_output(output);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002413 }
2414}
2415
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002416WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002417backend_init(struct wl_display *display, int argc, char *argv[],
2418 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002419{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002420 int connector = 0, tty = 0;
2421 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002422
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002423 const struct weston_option drm_options[] = {
2424 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2425 { WESTON_OPTION_STRING, "seat", 0, &seat },
2426 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002427 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002428 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002429
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002430 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002431
Scott Moreau8ab5d452012-07-30 19:51:08 -06002432 wl_list_init(&configured_output_list);
2433
2434 const struct config_key drm_config_keys[] = {
2435 { "name", CONFIG_KEY_STRING, &output_name },
2436 { "mode", CONFIG_KEY_STRING, &output_mode },
2437 };
2438
2439 const struct config_section config_section[] = {
2440 { "output", drm_config_keys,
2441 ARRAY_LENGTH(drm_config_keys), output_section_done },
2442 };
2443
2444 parse_config_file(config_file, config_section,
2445 ARRAY_LENGTH(config_section), NULL);
2446
Daniel Stonec1be8e52012-06-01 11:14:02 -04002447 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2448 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002449}