blob: 3a7d4329529cb5a5ba5aee4eb1aa600b5b0cb8c9 [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;
Scott Moreau1bad5db2012-08-18 01:04:05 -060049static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060050static struct wl_list configured_output_list;
51
52enum output_config {
53 OUTPUT_CONFIG_INVALID = 0,
54 OUTPUT_CONFIG_OFF,
55 OUTPUT_CONFIG_PREFERRED,
56 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060057 OUTPUT_CONFIG_MODE,
58 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060059};
60
61struct drm_configured_output {
62 char *name;
63 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060064 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060065 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060066 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060067 enum output_config config;
68 struct wl_list link;
69};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040070
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050072 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
74 struct udev *udev;
75 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040076
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010077 struct udev_monitor *udev_monitor;
78 struct wl_event_source *udev_drm_source;
79
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010081 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 int fd;
83 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020084 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050085 uint32_t *crtcs;
86 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050087 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010088 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050089 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Kristian Høgsberg8a015802012-08-09 17:19:23 -040095 int32_t min_width, max_width;
96 int32_t min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -050097
Jesse Barnes58ef3792012-02-23 09:45:49 -050098 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050099 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200100 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101
Rob Clarkab5b1e32012-08-09 13:24:45 -0500102 int cursors_are_broken;
103
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200104 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400105};
106
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400107struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500108 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109 drmModeModeInfo mode_info;
110};
111
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300112struct drm_output;
113
114struct drm_fb {
115 struct gbm_bo *bo;
116 struct drm_output *output;
117 uint32_t fb_id;
118 int is_client_buffer;
119 struct wl_buffer *buffer;
120 struct wl_listener buffer_destroy_listener;
121};
122
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400123struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500124 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400126 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400127 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500128 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400129 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700130 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200131
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300132 int vblank_pending;
133 int page_flip_pending;
134
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400135 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400136 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400137 struct weston_plane cursor_plane;
138 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400139 struct weston_surface *cursor_surface;
140 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300141 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200142 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143};
144
Jesse Barnes58ef3792012-02-23 09:45:49 -0500145/*
146 * An output has a primary display plane plus zero or more sprites for
147 * blending display contents.
148 */
149struct drm_sprite {
150 struct wl_list link;
151
152 uint32_t fb_id;
153 uint32_t pending_fb_id;
154 struct weston_surface *surface;
155 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400156 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500157
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300158 struct drm_output *output;
159
Jesse Barnes58ef3792012-02-23 09:45:49 -0500160 struct drm_compositor *compositor;
161
162 struct wl_listener destroy_listener;
163 struct wl_listener pending_destroy_listener;
164
165 uint32_t possible_crtcs;
166 uint32_t plane_id;
167 uint32_t count_formats;
168
169 int32_t src_x, src_y;
170 uint32_t src_w, src_h;
171 uint32_t dest_x, dest_y;
172 uint32_t dest_w, dest_h;
173
174 uint32_t formats[];
175};
176
Pekka Paalanen33156972012-08-03 13:30:30 -0400177struct drm_seat {
178 struct weston_seat base;
179 struct wl_list devices_list;
180 struct udev_monitor *udev_monitor;
181 struct wl_event_source *udev_monitor_source;
182 char *seat_id;
183};
184
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400185static void
186drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400187
Jesse Barnes58ef3792012-02-23 09:45:49 -0500188static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500189drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
190{
191 struct weston_compositor *ec = output_base->compositor;
192 struct drm_compositor *c =(struct drm_compositor *) ec;
193 struct drm_output *output = (struct drm_output *) output_base;
194 int crtc;
195
196 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
197 if (c->crtcs[crtc] != output->crtc_id)
198 continue;
199
200 if (supported & (1 << crtc))
201 return -1;
202 }
203
204 return 0;
205}
206
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300207static void
208drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
209{
210 struct drm_fb *fb = data;
211 struct gbm_device *gbm = gbm_bo_get_device(bo);
212
213 if (fb->fb_id)
214 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
215
216 if (fb->buffer) {
217 weston_buffer_post_release(fb->buffer);
218 wl_list_remove(&fb->buffer_destroy_listener.link);
219 }
220
221 free(data);
222}
223
224static struct drm_fb *
225drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
226{
227 struct drm_fb *fb = gbm_bo_get_user_data(bo);
228 struct drm_compositor *compositor =
229 (struct drm_compositor *) output->base.compositor;
230 uint32_t width, height, stride, handle;
231 int ret;
232
233 if (fb)
234 return fb;
235
236 fb = malloc(sizeof *fb);
237
238 fb->bo = bo;
239 fb->output = output;
240 fb->is_client_buffer = 0;
241 fb->buffer = NULL;
242
243 width = gbm_bo_get_width(bo);
244 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400245 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300246 handle = gbm_bo_get_handle(bo).u32;
247
248 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
249 stride, handle, &fb->fb_id);
250 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200251 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300252 free(fb);
253 return NULL;
254 }
255
256 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
257
258 return fb;
259}
260
261static void
262fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
263{
264 struct drm_fb *fb = container_of(listener, struct drm_fb,
265 buffer_destroy_listener);
266
267 fb->buffer = NULL;
268
269 if (fb == fb->output->next ||
270 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400271 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300272}
273
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400274static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400275drm_output_prepare_scanout_surface(struct weston_output *_output,
276 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500277{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400278 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500279 struct drm_compositor *c =
280 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300281 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500282
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500283 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200284 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200285 es->geometry.width != output->base.current->width ||
286 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200287 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400288 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400289 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500290
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400291 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
292 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500293
Rob Bradford9b101872012-09-14 23:25:41 +0100294 /* Unable to use the buffer for scanout */
295 if (!bo)
296 return NULL;
297
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300298 /* Need to verify output->region contained in surface opaque
299 * region. Or maybe just that format doesn't have alpha.
300 * For now, scanout only if format is XRGB8888. */
301 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
302 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400303 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300304 }
305
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300306 output->next = drm_fb_get_from_bo(bo, output);
307 if (!output->next) {
308 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400309 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300310 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500311
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300312 output->next->is_client_buffer = 1;
313 output->next->buffer = es->buffer;
314 output->next->buffer->busy_count++;
315 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
316
317 wl_signal_add(&output->next->buffer->resource.destroy_signal,
318 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500319
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400320 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500321}
322
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500323static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400324drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400325{
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400326 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400328
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400329 ec->renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400330
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 bo = gbm_surface_lock_front_buffer(output->surface);
332 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200333 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400334 return;
335 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300336
337 output->next = drm_fb_get_from_bo(bo, output);
338 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200339 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300340 gbm_surface_release_buffer(output->surface, bo);
341 return;
342 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400343}
344
345static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500346drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400347 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100348{
349 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500350 struct drm_compositor *compositor =
351 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500352 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400353 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500354 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100355
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300356 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400357 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300358 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400359 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100360
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400361 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300362 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400363 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300364 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400365 &output->connector_id, 1,
366 &mode->mode_info);
367 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200368 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400369 return;
370 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200371 }
372
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500373 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300374 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500375 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200376 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500377 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500378 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100379
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300380 output->page_flip_pending = 1;
381
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400382 drm_output_set_cursor(output);
383
Jesse Barnes58ef3792012-02-23 09:45:49 -0500384 /*
385 * Now, update all the sprite surfaces
386 */
387 wl_list_for_each(s, &compositor->sprite_list, link) {
388 uint32_t flags = 0;
389 drmVBlank vbl = {
390 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
391 .request.sequence = 1,
392 };
393
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200394 if ((!s->fb_id && !s->pending_fb_id) ||
395 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500396 continue;
397
398 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200399 output->crtc_id,
400 compositor->sprites_hidden ?
401 0 : s->pending_fb_id,
402 flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500403 s->dest_x, s->dest_y,
404 s->dest_w, s->dest_h,
405 s->src_x, s->src_y,
406 s->src_w, s->src_h);
407 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200408 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500409 ret, strerror(errno));
410
Rob Clark5ca1a472012-08-08 20:27:37 -0500411 if (output->pipe > 0)
412 vbl.request.type |= DRM_VBLANK_SECONDARY;
413
Jesse Barnes58ef3792012-02-23 09:45:49 -0500414 /*
415 * Queue a vblank signal so we know when the surface
416 * becomes active on the display or has been replaced.
417 */
418 vbl.request.signal = (unsigned long)s;
419 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
420 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200421 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500422 ret, strerror(errno));
423 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300424
425 s->output = output;
426 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500427 }
428
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500429 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400430}
431
432static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500433vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
434 void *data)
435{
436 struct drm_sprite *s = (struct drm_sprite *)data;
437 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300438 struct drm_output *output = s->output;
439 uint32_t msecs;
440
441 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500442
443 if (s->surface) {
444 weston_buffer_post_release(s->surface->buffer);
445 wl_list_remove(&s->destroy_listener.link);
446 s->surface = NULL;
447 drmModeRmFB(c->drm.fd, s->fb_id);
448 s->fb_id = 0;
449 }
450
451 if (s->pending_surface) {
452 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400453 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
454 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500455 s->surface = s->pending_surface;
456 s->pending_surface = NULL;
457 s->fb_id = s->pending_fb_id;
458 s->pending_fb_id = 0;
459 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300460
461 if (!output->page_flip_pending) {
462 msecs = sec * 1000 + usec / 1000;
463 weston_output_finish_frame(&output->base, msecs);
464 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500465}
466
467static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400468page_flip_handler(int fd, unsigned int frame,
469 unsigned int sec, unsigned int usec, void *data)
470{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200471 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400472 uint32_t msecs;
473
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300474 output->page_flip_pending = 0;
475
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300476 if (output->current) {
477 if (output->current->is_client_buffer)
478 gbm_bo_destroy(output->current->bo);
479 else
480 gbm_surface_release_buffer(output->surface,
481 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200482 }
483
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300484 output->current = output->next;
485 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400486
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300487 if (!output->vblank_pending) {
488 msecs = sec * 1000 + usec / 1000;
489 weston_output_finish_frame(&output->base, msecs);
490 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200491}
492
493static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500494drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
495{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400496 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500497
498 for (i = 0; i < s->count_formats; i++)
499 if (s->formats[i] == format)
500 return 1;
501
502 return 0;
503}
504
505static int
506drm_surface_transform_supported(struct weston_surface *es)
507{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400508 struct weston_matrix *matrix = &es->transform.matrix;
509 int i;
510
511 if (!es->transform.enabled)
512 return 1;
513
514 for (i = 0; i < 16; i++) {
515 switch (i) {
516 case 10:
517 case 15:
518 if (matrix->d[i] != 1.0)
519 return 0;
520 break;
521 case 0:
522 case 5:
523 case 12:
524 case 13:
525 break;
526 default:
527 if (matrix->d[i] != 0.0)
528 return 0;
529 break;
530 }
531 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500532
533 return 1;
534}
535
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400536static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500537drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400538 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500539{
540 struct weston_compositor *ec = output_base->compositor;
541 struct drm_compositor *c =(struct drm_compositor *) ec;
542 struct drm_sprite *s;
543 int found = 0;
544 EGLint handle, stride;
545 struct gbm_bo *bo;
546 uint32_t fb_id = 0;
547 uint32_t handles[4], pitches[4], offsets[4];
548 int ret = 0;
549 pixman_region32_t dest_rect, src_rect;
550 pixman_box32_t *box;
551 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400552 wl_fixed_t sx1, sy1, sx2, sy2;
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400553 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500554
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500555 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400556 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500557
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300558 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400559 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300560
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400561 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400562 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500563
Rob Clark702ffae2012-08-09 14:18:27 -0500564 if (wl_buffer_is_shm(es->buffer))
565 return NULL;
566
Jesse Barnes58ef3792012-02-23 09:45:49 -0500567 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400568 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500569
Jesse Barnes58ef3792012-02-23 09:45:49 -0500570 wl_list_for_each(s, &c->sprite_list, link) {
571 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
572 continue;
573
574 if (!s->pending_fb_id) {
575 found = 1;
576 break;
577 }
578 }
579
580 /* No sprites available */
581 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400582 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500583
Rob Clark4339add2012-08-09 14:18:28 -0500584 width = es->geometry.width;
585 height = es->geometry.height;
586
587 /* If geometry is out of bounds, don't even bother trying because
588 * we know the AddFB2() call will fail:
589 */
590 if (c->min_width > width || width > c->max_width ||
591 c->min_height > height || height > c->max_height)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400592 return NULL;
Rob Clark4339add2012-08-09 14:18:28 -0500593
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400594 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
595 es->buffer, GBM_BO_USE_SCANOUT);
596 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400597 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400598
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599 format = gbm_bo_get_format(bo);
600 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400601 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602
603 gbm_bo_destroy(bo);
604
605 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400606 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500607
608 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400609 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500610
611 handles[0] = handle;
612 pitches[0] = stride;
613 offsets[0] = 0;
614
Rob Clark4339add2012-08-09 14:18:28 -0500615 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500616 format, handles, pitches, offsets,
617 &fb_id, 0);
618 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200619 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500620 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400621 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 }
623
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 s->pending_fb_id = fb_id;
625 s->pending_surface = es;
626 es->buffer->busy_count++;
627
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400628 box = pixman_region32_extents(&es->transform.boundingbox);
629 s->plane.x = box->x1;
630 s->plane.y = box->y1;
631
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 /*
633 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200634 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635 * for us already).
636 */
637 pixman_region32_init(&dest_rect);
638 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
639 &output_base->region);
640 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
641 box = pixman_region32_extents(&dest_rect);
642 s->dest_x = box->x1;
643 s->dest_y = box->y1;
644 s->dest_w = box->x2 - box->x1;
645 s->dest_h = box->y2 - box->y1;
646 pixman_region32_fini(&dest_rect);
647
648 pixman_region32_init(&src_rect);
649 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
650 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500651 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400652
653 weston_surface_from_global_fixed(es,
654 wl_fixed_from_int(box->x1),
655 wl_fixed_from_int(box->y1),
656 &sx1, &sy1);
657 weston_surface_from_global_fixed(es,
658 wl_fixed_from_int(box->x2),
659 wl_fixed_from_int(box->y2),
660 &sx2, &sy2);
661
662 if (sx1 < 0)
663 sx1 = 0;
664 if (sy1 < 0)
665 sy1 = 0;
666 if (sx2 > wl_fixed_from_int(es->geometry.width))
667 sx2 = wl_fixed_from_int(es->geometry.width);
668 if (sy2 > wl_fixed_from_int(es->geometry.height))
669 sy2 = wl_fixed_from_int(es->geometry.height);
670
671 s->src_x = sx1 << 8;
672 s->src_y = sy1 << 8;
673 s->src_w = (sx2 - sx1) << 8;
674 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500675 pixman_region32_fini(&src_rect);
676
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400677 wl_signal_add(&es->buffer->resource.destroy_signal,
678 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400679
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400680 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500681}
682
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400683static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400684drm_output_prepare_cursor_surface(struct weston_output *output_base,
685 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500686{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400687 struct drm_compositor *c =
688 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400689 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400690
691 if (output->cursor_surface)
692 return NULL;
693 if (es->output_mask != (1u << output_base->id))
694 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500695 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400696 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400697 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
698 es->geometry.width > 64 || es->geometry.height > 64)
699 return NULL;
700
701 output->cursor_surface = es;
702
703 return &output->cursor_plane;
704}
705
706static void
707drm_output_set_cursor(struct drm_output *output)
708{
709 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400710 struct drm_compositor *c =
711 (struct drm_compositor *) output->base.compositor;
712 EGLint handle, stride;
713 struct gbm_bo *bo;
714 uint32_t buf[64 * 64];
715 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400716 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500717
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400718 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400719 if (es == NULL) {
720 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
721 return;
722 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500723
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400724 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
725 pixman_region32_fini(&output->cursor_plane.damage);
726 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400727 output->current_cursor ^= 1;
728 bo = output->cursor_bo[output->current_cursor];
729 memset(buf, 0, sizeof buf);
730 stride = wl_shm_buffer_get_stride(es->buffer);
731 s = wl_shm_buffer_get_data(es->buffer);
732 for (i = 0; i < es->geometry.height; i++)
733 memcpy(buf + i * 64, s + i * stride,
734 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500735
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400736 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300737 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400738
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400739 handle = gbm_bo_get_handle(bo).s32;
740 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500741 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300742 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500743 c->cursors_are_broken = 1;
744 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400745 }
746
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400747 x = es->geometry.x - output->base.x;
748 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400749 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500750 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400751 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500752 c->cursors_are_broken = 1;
753 }
754
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400755 output->cursor_plane.x = x;
756 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400757 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500758}
759
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760static void
761drm_assign_planes(struct weston_output *output)
762{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400763 struct drm_compositor *c =
764 (struct drm_compositor *) output->compositor;
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200765 struct drm_output *drm_output = (struct drm_output *) output;
766 struct drm_sprite *s;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400767 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400769 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770
Ander Conselvan de Oliveira4bcf3a52012-10-31 17:55:45 +0200771 /* Reset the opaque region of the planes */
772 pixman_region32_fini(&drm_output->cursor_plane.opaque);
773 pixman_region32_init(&drm_output->cursor_plane.opaque);
774 pixman_region32_fini(&drm_output->fb_plane.opaque);
775 pixman_region32_init(&drm_output->fb_plane.opaque);
776
777 wl_list_for_each (s, &c->sprite_list, link) {
778 if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
779 continue;
780
781 pixman_region32_fini(&s->plane.opaque);
782 pixman_region32_init(&s->plane.opaque);
783 }
784
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785 /*
786 * Find a surface for each sprite in the output using some heuristics:
787 * 1) size
788 * 2) frequency of update
789 * 3) opacity (though some hw might support alpha blending)
790 * 4) clipping (this can be fixed with color keys)
791 *
792 * The idea is to save on blitting since this should save power.
793 * If we can get a large video surface on the sprite for example,
794 * the main display surface may not need to update at all, and
795 * the client buffer can be used directly for the sprite surface
796 * as we do for flipping full screen surfaces.
797 */
798 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400799 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400800 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801 pixman_region32_init(&surface_overlap);
802 pixman_region32_intersect(&surface_overlap, &overlap,
803 &es->transform.boundingbox);
804
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400805 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400806 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400807 next_plane = primary;
808 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400809 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 if (next_plane == NULL)
811 next_plane = drm_output_prepare_scanout_surface(output, es);
812 if (next_plane == NULL)
813 next_plane = drm_output_prepare_overlay_surface(output, es);
814 if (next_plane == NULL)
815 next_plane = primary;
816 weston_surface_move_to_plane(es, next_plane);
817 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818 pixman_region32_union(&overlap, &overlap,
819 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400820
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821 pixman_region32_fini(&surface_overlap);
822 }
823 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824}
825
Matt Roper361d2ad2011-08-29 13:52:23 -0700826static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500827drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700828{
829 struct drm_output *output = (struct drm_output *) output_base;
830 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200831 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700832 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700833
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200834 if (output->backlight)
835 backlight_destroy(output->backlight);
836
Matt Roper361d2ad2011-08-29 13:52:23 -0700837 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400838 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700839
840 /* Restore original CRTC state */
841 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200842 origcrtc->x, origcrtc->y,
843 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700844 drmModeFreeCrtc(origcrtc);
845
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200846 c->crtc_allocator &= ~(1 << output->crtc_id);
847 c->connector_allocator &= ~(1 << output->connector_id);
848
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400849 eglDestroySurface(c->base.egl_display, output->base.egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400850 gbm_surface_destroy(output->surface);
851
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400852 weston_plane_release(&output->fb_plane);
853 weston_plane_release(&output->cursor_plane);
854
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500855 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200856 wl_list_remove(&output->base.link);
857
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400858 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700859 free(output);
860}
861
Alex Wub7b8bda2012-04-17 17:20:48 +0800862static struct drm_mode *
863choose_mode (struct drm_output *output, struct weston_mode *target_mode)
864{
865 struct drm_mode *tmp_mode = NULL, *mode;
866
867 if (output->base.current->width == target_mode->width &&
868 output->base.current->height == target_mode->height &&
869 (output->base.current->refresh == target_mode->refresh ||
870 target_mode->refresh == 0))
871 return (struct drm_mode *)output->base.current;
872
873 wl_list_for_each(mode, &output->base.mode_list, base.link) {
874 if (mode->mode_info.hdisplay == target_mode->width &&
875 mode->mode_info.vdisplay == target_mode->height) {
876 if (mode->mode_info.vrefresh == target_mode->refresh ||
877 target_mode->refresh == 0) {
878 return mode;
879 } else if (!tmp_mode)
880 tmp_mode = mode;
881 }
882 }
883
884 return tmp_mode;
885}
886
887static int
888drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
889{
890 struct drm_output *output;
891 struct drm_mode *drm_mode;
892 int ret;
893 struct drm_compositor *ec;
894 struct gbm_surface *surface;
895 EGLSurface egl_surface;
896
897 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200898 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800899 return -1;
900 }
901
902 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200903 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800904 return -1;
905 }
906
907 ec = (struct drm_compositor *)output_base->compositor;
908 output = (struct drm_output *)output_base;
909 drm_mode = choose_mode (output, mode);
910
911 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200912 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800913 return -1;
914 } else if (&drm_mode->base == output->base.current) {
915 return 0;
916 } else if (drm_mode->base.width == output->base.current->width &&
917 drm_mode->base.height == output->base.current->height) {
918 /* only change refresh value */
919 ret = drmModeSetCrtc(ec->drm.fd,
920 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300921 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800922 &output->connector_id, 1, &drm_mode->mode_info);
923
924 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200925 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800926 drm_mode->base.width,
927 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400928 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800929 ret = -1;
930 } else {
931 output->base.current->flags = 0;
932 output->base.current = &drm_mode->base;
933 drm_mode->base.flags =
934 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
935 ret = 0;
936 }
937
938 return ret;
939 }
940
941 drm_mode->base.flags =
942 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
943
944 surface = gbm_surface_create(ec->gbm,
945 drm_mode->base.width,
946 drm_mode->base.height,
947 GBM_FORMAT_XRGB8888,
948 GBM_BO_USE_SCANOUT |
949 GBM_BO_USE_RENDERING);
950 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200951 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800952 return -1;
953 }
954
955 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400956 eglCreateWindowSurface(ec->base.egl_display,
957 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800958 surface, NULL);
959
960 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200961 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800962 goto err;
963 }
964
965 ret = drmModeSetCrtc(ec->drm.fd,
966 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300967 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800968 &output->connector_id, 1, &drm_mode->mode_info);
969 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200970 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800971 goto err;
972 }
973
974 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300975 if (output->current) {
976 if (output->current->is_client_buffer)
977 gbm_bo_destroy(output->current->bo);
978 else
979 gbm_surface_release_buffer(output->surface,
980 output->current->bo);
981 }
982 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800983
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300984 if (output->next) {
985 if (output->next->is_client_buffer)
986 gbm_bo_destroy(output->next->bo);
987 else
988 gbm_surface_release_buffer(output->surface,
989 output->next->bo);
990 }
991 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800992
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400993 eglDestroySurface(ec->base.egl_display, output->base.egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +0800994 gbm_surface_destroy(output->surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400995 output->base.egl_surface = egl_surface;
Alex Wub7b8bda2012-04-17 17:20:48 +0800996 output->surface = surface;
997
998 /*update output*/
999 output->base.current = &drm_mode->base;
1000 output->base.dirty = 1;
1001 weston_output_move(&output->base, output->base.x, output->base.y);
1002 return 0;
1003
1004err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001005 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001006 gbm_surface_destroy(surface);
1007 return -1;
1008}
1009
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001010static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001011on_drm_input(int fd, uint32_t mask, void *data)
1012{
1013 drmEventContext evctx;
1014
1015 memset(&evctx, 0, sizeof evctx);
1016 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1017 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001018 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001019 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001020
1021 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001022}
1023
1024static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001025init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001026{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001027 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001028 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001029 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001030 static const EGLint config_attribs[] = {
1031 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1032 EGL_RED_SIZE, 1,
1033 EGL_GREEN_SIZE, 1,
1034 EGL_BLUE_SIZE, 1,
1035 EGL_ALPHA_SIZE, 0,
1036 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1037 EGL_NONE
1038 };
1039
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001040 sysnum = udev_device_get_sysnum(device);
1041 if (sysnum)
1042 ec->drm.id = atoi(sysnum);
1043 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001044 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001045 return -1;
1046 }
1047
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001048 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001049 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001050 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001051 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001052 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001053 udev_device_get_devnode(device));
1054 return -1;
1055 }
1056
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001057 weston_log("using %s\n", filename);
1058
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001059 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001060 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001061 ec->base.egl_display = eglGetDisplay(ec->gbm);
1062 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001063 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001064 return -1;
1065 }
1066
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001067 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001068 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001069 return -1;
1070 }
1071
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001072 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1073 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001074 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001075 return -1;
1076 }
1077
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001078 return 0;
1079}
1080
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001081static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001082drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1083{
1084 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001085 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001086
1087 mode = malloc(sizeof *mode);
1088 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001089 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001090
1091 mode->base.flags = 0;
1092 mode->base.width = info->hdisplay;
1093 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001094
1095 /* Calculate higher precision (mHz) refresh rate */
1096 refresh = (info->clock * 1000000LL / info->htotal +
1097 info->vtotal / 2) / info->vtotal;
1098
1099 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1100 refresh *= 2;
1101 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1102 refresh /= 2;
1103 if (info->vscan > 1)
1104 refresh /= info->vscan;
1105
1106 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001107 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001108
1109 if (info->type & DRM_MODE_TYPE_PREFERRED)
1110 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1111
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001112 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1113
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001114 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001115}
1116
1117static int
1118drm_subpixel_to_wayland(int drm_value)
1119{
1120 switch (drm_value) {
1121 default:
1122 case DRM_MODE_SUBPIXEL_UNKNOWN:
1123 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1124 case DRM_MODE_SUBPIXEL_NONE:
1125 return WL_OUTPUT_SUBPIXEL_NONE;
1126 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1127 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1128 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1129 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1130 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1131 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1132 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1133 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1134 }
1135}
1136
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001137static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001138sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001139{
1140 struct drm_sprite *sprite =
1141 container_of(listener, struct drm_sprite,
1142 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001143 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001144
1145 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001146 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1147 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001148}
1149
1150static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001151sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001152{
1153 struct drm_sprite *sprite =
1154 container_of(listener, struct drm_sprite,
1155 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001156 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001157
1158 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001159 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1160 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001161}
1162
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001163/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001164static uint32_t
1165drm_get_backlight(struct drm_output *output)
1166{
1167 long brightness, max_brightness, norm;
1168
1169 brightness = backlight_get_brightness(output->backlight);
1170 max_brightness = backlight_get_max_brightness(output->backlight);
1171
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001172 /* convert it on a scale of 0 to 255 */
1173 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001174
1175 return (uint32_t) norm;
1176}
1177
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001178/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001179static void
1180drm_set_backlight(struct weston_output *output_base, uint32_t value)
1181{
1182 struct drm_output *output = (struct drm_output *) output_base;
1183 long max_brightness, new_brightness;
1184
1185 if (!output->backlight)
1186 return;
1187
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001188 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001189 return;
1190
1191 max_brightness = backlight_get_max_brightness(output->backlight);
1192
1193 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001194 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001195
1196 backlight_set_brightness(output->backlight, new_brightness);
1197}
1198
1199static drmModePropertyPtr
1200drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1201{
1202 drmModePropertyPtr props;
1203 int i;
1204
1205 for (i = 0; i < connector->count_props; i++) {
1206 props = drmModeGetProperty(fd, connector->props[i]);
1207 if (!props)
1208 continue;
1209
1210 if (!strcmp(props->name, name))
1211 return props;
1212
1213 drmModeFreeProperty(props);
1214 }
1215
1216 return NULL;
1217}
1218
1219static void
1220drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1221{
1222 struct drm_output *output = (struct drm_output *) output_base;
1223 struct weston_compositor *ec = output_base->compositor;
1224 struct drm_compositor *c = (struct drm_compositor *) ec;
1225 drmModeConnectorPtr connector;
1226 drmModePropertyPtr prop;
1227
1228 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1229 if (!connector)
1230 return;
1231
1232 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1233 if (!prop) {
1234 drmModeFreeConnector(connector);
1235 return;
1236 }
1237
1238 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1239 prop->prop_id, level);
1240 drmModeFreeProperty(prop);
1241 drmModeFreeConnector(connector);
1242}
1243
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001244static const char *connector_type_names[] = {
1245 "None",
1246 "VGA",
1247 "DVI",
1248 "DVI",
1249 "DVI",
1250 "Composite",
1251 "TV",
1252 "LVDS",
1253 "CTV",
1254 "DIN",
1255 "DP",
1256 "HDMI",
1257 "HDMI",
1258 "TV",
1259 "eDP",
1260};
1261
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001263find_crtc_for_connector(struct drm_compositor *ec,
1264 drmModeRes *resources, drmModeConnector *connector)
1265{
1266 drmModeEncoder *encoder;
1267 uint32_t possible_crtcs;
1268 int i, j;
1269
1270 for (j = 0; j < connector->count_encoders; j++) {
1271 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1272 if (encoder == NULL) {
1273 weston_log("Failed to get encoder.\n");
1274 return -1;
1275 }
1276 possible_crtcs = encoder->possible_crtcs;
1277 drmModeFreeEncoder(encoder);
1278
1279 for (i = 0; i < resources->count_crtcs; i++) {
1280 if (possible_crtcs & (1 << i) &&
1281 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1282 return i;
1283 }
1284 }
1285
1286 return -1;
1287}
1288
1289static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001290create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001291 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001292 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001293 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001294{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001295 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001296 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1297 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001298 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001299 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001300 drmModeModeInfo crtc_mode;
1301 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001302 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001303 char name[32];
1304 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001305
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001306 i = find_crtc_for_connector(ec, resources, connector);
1307 if (i < 0) {
1308 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001309 return -1;
1310 }
1311
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001313 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001314 return -1;
1315
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001316 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001317 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1318 output->base.make = "unknown";
1319 output->base.model = "unknown";
1320 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001321
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001322 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1323 type_name = connector_type_names[connector->connector_type];
1324 else
1325 type_name = "UNKNOWN";
1326 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1327 output->name = strdup(name);
1328
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001329 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001330 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001331 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001332 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001333 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001334
Matt Roper361d2ad2011-08-29 13:52:23 -07001335 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1336
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001337 /* Get the current mode on the crtc that's currently driving
1338 * this connector. */
1339 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001340 memset(&crtc_mode, 0, sizeof crtc_mode);
1341 if (encoder != NULL) {
1342 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1343 drmModeFreeEncoder(encoder);
1344 if (crtc == NULL)
1345 goto err_free;
1346 if (crtc->mode_valid)
1347 crtc_mode = crtc->mode;
1348 drmModeFreeCrtc(crtc);
1349 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001350
David Herrmann0f0d54e2011-12-08 17:05:45 +01001351 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001352 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1353 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001354 goto err_free;
1355 }
1356
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001357 preferred = NULL;
1358 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001359 configured = NULL;
1360
1361 wl_list_for_each(temp, &configured_output_list, link) {
1362 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001363 if (temp->mode)
1364 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001365 temp->name, temp->mode);
1366 o = temp;
1367 break;
1368 }
1369 }
1370
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001371 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001372 weston_log("Disabling output %s\n", o->name);
1373
1374 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1375 0, 0, 0, 0, 0, NULL);
1376 goto err_free;
1377 }
1378
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001379 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001380 if (o && o->config == OUTPUT_CONFIG_MODE &&
1381 o->width == drm_mode->base.width &&
1382 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001383 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001384 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001385 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001386 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001387 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001388 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001389
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001390 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001391 configured = drm_output_add_mode(output, &o->crtc_mode);
1392 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001393 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001394 current = configured;
1395 }
1396
Wang Quanxianacb805a2012-07-30 18:09:46 -04001397 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001398 current = drm_output_add_mode(output, &crtc_mode);
1399 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001400 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001401 }
1402
Scott Moreau8ab5d452012-07-30 19:51:08 -06001403 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1404 configured = current;
1405
Wang Quanxianacb805a2012-07-30 18:09:46 -04001406 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001407 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001408 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001409 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001410 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001411 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001412 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001413 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001414
1415 if (output->base.current == NULL) {
1416 weston_log("no available modes for %s\n", output->name);
1417 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001418 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001419
Wang Quanxianacb805a2012-07-30 18:09:46 -04001420 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1421
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001422 output->surface = gbm_surface_create(ec->gbm,
1423 output->base.current->width,
1424 output->base.current->height,
1425 GBM_FORMAT_XRGB8888,
1426 GBM_BO_USE_SCANOUT |
1427 GBM_BO_USE_RENDERING);
1428 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001429 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001430 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001431 }
1432
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001433 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001434 eglCreateWindowSurface(ec->base.egl_display,
1435 ec->base.egl_config,
1436 output->surface,
1437 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001438 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001439 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001440 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001441 }
1442
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001443 output->cursor_bo[0] =
1444 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1445 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1446 output->cursor_bo[1] =
1447 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1448 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001449 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1450 weston_log("cursor buffers unavailable, using gl cursors\n");
1451 ec->cursors_are_broken = 1;
1452 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001453
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001454 output->backlight = backlight_init(drm_device,
1455 connector->connector_type);
1456 if (output->backlight) {
1457 output->base.set_backlight = drm_set_backlight;
1458 output->base.backlight_current = drm_get_backlight(output);
1459 }
1460
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001461 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001462 connector->mmWidth, connector->mmHeight,
1463 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001464
1465 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1466
Alex Wubd3354b2012-04-17 17:20:49 +08001467 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001468 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001469 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001470 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001471 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001472 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001473
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001474 weston_plane_init(&output->cursor_plane, 0, 0);
1475 weston_plane_init(&output->fb_plane, 0, 0);
1476
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001477 weston_log("Output %s, (connector %d, crtc %d)\n",
1478 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001479 wl_list_for_each(m, &output->base.mode_list, link)
1480 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1481 m->width, m->height, m->refresh / 1000.0,
1482 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1483 ", preferred" : "",
1484 m->flags & WL_OUTPUT_MODE_CURRENT ?
1485 ", current" : "",
1486 connector->count_modes == 0 ?
1487 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001488
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001489 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001490
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001491err_surface:
1492 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001493err_free:
1494 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1495 base.link) {
1496 wl_list_remove(&drm_mode->base.link);
1497 free(drm_mode);
1498 }
1499
1500 drmModeFreeCrtc(output->original_crtc);
1501 ec->crtc_allocator &= ~(1 << output->crtc_id);
1502 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001503 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001504 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001505
David Herrmann0f0d54e2011-12-08 17:05:45 +01001506 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001507}
1508
Jesse Barnes58ef3792012-02-23 09:45:49 -05001509static void
1510create_sprites(struct drm_compositor *ec)
1511{
1512 struct drm_sprite *sprite;
1513 drmModePlaneRes *plane_res;
1514 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001515 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001516
1517 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1518 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001519 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001520 strerror(errno));
1521 return;
1522 }
1523
1524 for (i = 0; i < plane_res->count_planes; i++) {
1525 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1526 if (!plane)
1527 continue;
1528
1529 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1530 plane->count_formats));
1531 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001532 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001533 __func__);
1534 free(plane);
1535 continue;
1536 }
1537
1538 memset(sprite, 0, sizeof *sprite);
1539
1540 sprite->possible_crtcs = plane->possible_crtcs;
1541 sprite->plane_id = plane->plane_id;
1542 sprite->surface = NULL;
1543 sprite->pending_surface = NULL;
1544 sprite->fb_id = 0;
1545 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001546 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1547 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001548 sprite_handle_pending_buffer_destroy;
1549 sprite->compositor = ec;
1550 sprite->count_formats = plane->count_formats;
1551 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001552 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001553 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001554 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001555
1556 wl_list_insert(&ec->sprite_list, &sprite->link);
1557 }
1558
1559 free(plane_res->planes);
1560 free(plane_res);
1561}
1562
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001563static void
1564destroy_sprites(struct drm_compositor *compositor)
1565{
1566 struct drm_sprite *sprite, *next;
1567 struct drm_output *output;
1568
1569 output = container_of(compositor->base.output_list.next,
1570 struct drm_output, base.link);
1571
1572 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1573 drmModeSetPlane(compositor->drm.fd,
1574 sprite->plane_id,
1575 output->crtc_id, 0, 0,
1576 0, 0, 0, 0, 0, 0, 0, 0);
1577 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001578 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001579 free(sprite);
1580 }
1581}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001582
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001583static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001584create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001585 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001586{
1587 drmModeConnector *connector;
1588 drmModeRes *resources;
1589 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001590 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001591
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001592 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001593 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001594 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001595 return -1;
1596 }
1597
Jesse Barnes58ef3792012-02-23 09:45:49 -05001598 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001599 if (!ec->crtcs) {
1600 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001601 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001602 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001603
Rob Clark4339add2012-08-09 14:18:28 -05001604 ec->min_width = resources->min_width;
1605 ec->max_width = resources->max_width;
1606 ec->min_height = resources->min_height;
1607 ec->max_height = resources->max_height;
1608
Jesse Barnes58ef3792012-02-23 09:45:49 -05001609 ec->num_crtcs = resources->count_crtcs;
1610 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1611
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001612 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001613 connector = drmModeGetConnector(ec->drm.fd,
1614 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001615 if (connector == NULL)
1616 continue;
1617
1618 if (connector->connection == DRM_MODE_CONNECTED &&
1619 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001620 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001621 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001622 connector, x, y,
1623 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001624 drmModeFreeConnector(connector);
1625 continue;
1626 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001627
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001628 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001629 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001630 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001631 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001632
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001633 drmModeFreeConnector(connector);
1634 }
1635
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001636 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001637 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001638 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001639 return -1;
1640 }
1641
1642 drmModeFreeResources(resources);
1643
1644 return 0;
1645}
1646
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001647static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001648update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001649{
1650 drmModeConnector *connector;
1651 drmModeRes *resources;
1652 struct drm_output *output, *next;
1653 int x = 0, y = 0;
1654 int x_offset = 0, y_offset = 0;
1655 uint32_t connected = 0, disconnects = 0;
1656 int i;
1657
1658 resources = drmModeGetResources(ec->drm.fd);
1659 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001660 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001661 return;
1662 }
1663
1664 /* collect new connects */
1665 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001666 int connector_id = resources->connectors[i];
1667
1668 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001669 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001670 continue;
1671
David Herrmann7551cff2011-12-08 17:05:43 +01001672 if (connector->connection != DRM_MODE_CONNECTED) {
1673 drmModeFreeConnector(connector);
1674 continue;
1675 }
1676
Benjamin Franzke117483d2011-08-30 11:38:26 +02001677 connected |= (1 << connector_id);
1678
1679 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001680 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001681 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001682 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001683
1684 /* XXX: not yet needed, we die with 0 outputs */
1685 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001686 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001687 else
1688 x = 0;
1689 y = 0;
1690 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001691 connector, x, y,
1692 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001693 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001694
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001695 }
1696 drmModeFreeConnector(connector);
1697 }
1698 drmModeFreeResources(resources);
1699
1700 disconnects = ec->connector_allocator & ~connected;
1701 if (disconnects) {
1702 wl_list_for_each_safe(output, next, &ec->base.output_list,
1703 base.link) {
1704 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001705 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001706 output->base.x - x_offset,
1707 output->base.y - y_offset);
1708 }
1709
1710 if (disconnects & (1 << output->connector_id)) {
1711 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001712 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001713 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001714 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001715 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001716 }
1717 }
1718 }
1719
1720 /* FIXME: handle zero outputs, without terminating */
1721 if (ec->connector_allocator == 0)
1722 wl_display_terminate(ec->base.wl_display);
1723}
1724
1725static int
David Herrmannd7488c22012-03-11 20:05:21 +01001726udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001727{
David Herrmannd7488c22012-03-11 20:05:21 +01001728 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001729 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001730
1731 sysnum = udev_device_get_sysnum(device);
1732 if (!sysnum || atoi(sysnum) != ec->drm.id)
1733 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001734
David Herrmann6ac52db2012-03-11 20:05:22 +01001735 val = udev_device_get_property_value(device, "HOTPLUG");
1736 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001737 return 0;
1738
David Herrmann6ac52db2012-03-11 20:05:22 +01001739 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001740}
1741
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001742static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001743udev_drm_event(int fd, uint32_t mask, void *data)
1744{
1745 struct drm_compositor *ec = data;
1746 struct udev_device *event;
1747
1748 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001749
David Herrmannd7488c22012-03-11 20:05:21 +01001750 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001751 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001752
1753 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001754
1755 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001756}
1757
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001758static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001759drm_restore(struct weston_compositor *ec)
1760{
1761 struct drm_compositor *d = (struct drm_compositor *) ec;
1762
1763 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1764 weston_log("failed to drop master: %m\n");
1765 tty_reset(d->tty);
1766}
1767
Pekka Paalanen33156972012-08-03 13:30:30 -04001768static const char default_seat[] = "seat0";
1769
1770static void
1771device_added(struct udev_device *udev_device, struct drm_seat *master)
1772{
1773 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001774 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001775 const char *devnode;
1776 const char *device_seat;
1777 int fd;
1778
1779 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1780 if (!device_seat)
1781 device_seat = default_seat;
1782
1783 if (strcmp(device_seat, master->seat_id))
1784 return;
1785
1786 c = master->base.compositor;
1787 devnode = udev_device_get_devnode(udev_device);
1788
1789 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001790 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001791 * read. mtdev_get() also expects this. */
1792 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1793 if (fd < 0) {
1794 weston_log("opening input device '%s' failed.\n", devnode);
1795 return;
1796 }
1797
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001798 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001799 if (!device) {
1800 close(fd);
1801 weston_log("not using input device '%s'.\n", devnode);
1802 return;
1803 }
1804
1805 wl_list_insert(master->devices_list.prev, &device->link);
1806}
1807
1808static void
1809evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1810{
1811 struct drm_seat *seat = (struct drm_seat *) seat_base;
1812 struct udev_enumerate *e;
1813 struct udev_list_entry *entry;
1814 struct udev_device *device;
1815 const char *path, *sysname;
1816
1817 e = udev_enumerate_new(udev);
1818 udev_enumerate_add_match_subsystem(e, "input");
1819 udev_enumerate_scan_devices(e);
1820 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1821 path = udev_list_entry_get_name(entry);
1822 device = udev_device_new_from_syspath(udev, path);
1823
1824 sysname = udev_device_get_sysname(device);
1825 if (strncmp("event", sysname, 5) != 0) {
1826 udev_device_unref(device);
1827 continue;
1828 }
1829
1830 device_added(device, seat);
1831
1832 udev_device_unref(device);
1833 }
1834 udev_enumerate_unref(e);
1835
1836 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1837
1838 if (wl_list_empty(&seat->devices_list)) {
1839 weston_log(
1840 "warning: no input devices on entering Weston. "
1841 "Possible causes:\n"
1842 "\t- no permissions to read /dev/input/event*\n"
1843 "\t- seats misconfigured "
1844 "(Weston backend option 'seat', "
1845 "udev device property ID_SEAT)\n");
1846 }
1847}
1848
1849static int
1850evdev_udev_handler(int fd, uint32_t mask, void *data)
1851{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001852 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001853 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001854 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001855 const char *action;
1856 const char *devnode;
1857
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001858 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001859 if (!udev_device)
1860 return 1;
1861
1862 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001863 if (!action)
1864 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001865
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001866 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1867 goto out;
1868
1869 if (!strcmp(action, "add")) {
1870 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001871 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001872 else if (!strcmp(action, "remove")) {
1873 devnode = udev_device_get_devnode(udev_device);
1874 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1875 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001876 weston_log("input device %s, %s removed\n",
1877 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001878 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001879 break;
1880 }
1881 }
1882
1883out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001884 udev_device_unref(udev_device);
1885
1886 return 0;
1887}
1888
1889static int
1890evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1891{
1892 struct drm_seat *master = (struct drm_seat *) seat_base;
1893 struct wl_event_loop *loop;
1894 struct weston_compositor *c = master->base.compositor;
1895 int fd;
1896
1897 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1898 if (!master->udev_monitor) {
1899 weston_log("udev: failed to create the udev monitor\n");
1900 return 0;
1901 }
1902
1903 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1904 "input", NULL);
1905
1906 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1907 weston_log("udev: failed to bind the udev monitor\n");
1908 udev_monitor_unref(master->udev_monitor);
1909 return 0;
1910 }
1911
1912 loop = wl_display_get_event_loop(c->wl_display);
1913 fd = udev_monitor_get_fd(master->udev_monitor);
1914 master->udev_monitor_source =
1915 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1916 evdev_udev_handler, master);
1917 if (!master->udev_monitor_source) {
1918 udev_monitor_unref(master->udev_monitor);
1919 return 0;
1920 }
1921
1922 return 1;
1923}
1924
1925static void
1926evdev_disable_udev_monitor(struct weston_seat *seat_base)
1927{
1928 struct drm_seat *seat = (struct drm_seat *) seat_base;
1929
1930 if (!seat->udev_monitor)
1931 return;
1932
1933 udev_monitor_unref(seat->udev_monitor);
1934 seat->udev_monitor = NULL;
1935 wl_event_source_remove(seat->udev_monitor_source);
1936 seat->udev_monitor_source = NULL;
1937}
1938
1939static void
1940drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1941{
1942 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001943 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001944
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001945 wl_list_for_each(device, &seat->devices_list, link)
1946 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001947}
1948
1949static void
1950evdev_input_create(struct weston_compositor *c, struct udev *udev,
1951 const char *seat_id)
1952{
1953 struct drm_seat *seat;
1954
1955 seat = malloc(sizeof *seat);
1956 if (seat == NULL)
1957 return;
1958
1959 memset(seat, 0, sizeof *seat);
1960 weston_seat_init(&seat->base, c);
1961 seat->base.led_update = drm_led_update;
1962
1963 wl_list_init(&seat->devices_list);
1964 seat->seat_id = strdup(seat_id);
1965 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1966 free(seat->seat_id);
1967 free(seat);
1968 return;
1969 }
1970
1971 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001972}
1973
1974static void
1975evdev_remove_devices(struct weston_seat *seat_base)
1976{
1977 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001978 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001979
1980 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001981 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001982
Pekka Paalanend8583512012-08-03 14:39:11 +03001983 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001984 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001985}
1986
1987static void
1988evdev_input_destroy(struct weston_seat *seat_base)
1989{
1990 struct drm_seat *seat = (struct drm_seat *) seat_base;
1991
1992 evdev_remove_devices(seat_base);
1993 evdev_disable_udev_monitor(&seat->base);
1994
1995 weston_seat_release(seat_base);
1996 free(seat->seat_id);
1997 free(seat);
1998}
1999
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002000static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002001drm_free_configured_output(struct drm_configured_output *output)
2002{
2003 free(output->name);
2004 free(output->mode);
2005 free(output);
2006}
2007
2008static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002009drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002010{
2011 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002012 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002013 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002014
Daniel Stone37816df2012-05-16 18:45:18 +01002015 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2016 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002017 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002018 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002019
2020 wl_event_source_remove(d->udev_drm_source);
2021 wl_event_source_remove(d->drm_source);
2022
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002023 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002024
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002025 gles2_renderer_destroy(ec);
2026
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002027 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002028 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002029 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002030 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002031 eglReleaseThread();
2032
Matt Roper361d2ad2011-08-29 13:52:23 -07002033 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002034 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002035 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002036 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002037 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002038
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002039 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002040}
2041
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002042static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002043drm_compositor_set_modes(struct drm_compositor *compositor)
2044{
2045 struct drm_output *output;
2046 struct drm_mode *drm_mode;
2047 int ret;
2048
2049 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2050 drm_mode = (struct drm_mode *) output->base.current;
2051 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002052 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002053 &output->connector_id, 1,
2054 &drm_mode->mode_info);
2055 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002056 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002057 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002058 drm_mode->base.width, drm_mode->base.height,
2059 output->base.x, output->base.y);
2060 }
2061 }
2062}
2063
2064static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002065vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002066{
2067 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002068 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002069 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002070 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002071
2072 switch (event) {
2073 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002074 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002075 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002076 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002077 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002078 wl_display_terminate(compositor->wl_display);
2079 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002080 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002081 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002082 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002083 wl_list_for_each(seat, &compositor->seat_list, link) {
2084 evdev_add_devices(ec->udev, seat);
2085 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002086 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002087 break;
2088 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002089 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002090 wl_list_for_each(seat, &compositor->seat_list, link) {
2091 evdev_disable_udev_monitor(seat);
2092 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002093 }
2094
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002095 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002096 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002097 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002098
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002099 /* If we have a repaint scheduled (either from a
2100 * pending pageflip or the idle handler), make sure we
2101 * cancel that so we don't try to pageflip when we're
2102 * vt switched away. The SLEEPING state will prevent
2103 * further attemps at repainting. When we switch
2104 * back, we schedule a repaint, which will process
2105 * pending frame callbacks. */
2106
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002107 wl_list_for_each(output, &ec->base.output_list, base.link) {
2108 output->base.repaint_needed = 0;
2109 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002110 }
2111
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002112 output = container_of(ec->base.output_list.next,
2113 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002114
2115 wl_list_for_each(sprite, &ec->sprite_list, link)
2116 drmModeSetPlane(ec->drm.fd,
2117 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002118 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002119 0, 0, 0, 0, 0, 0, 0, 0);
2120
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002121 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002122 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002123
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002124 break;
2125 };
2126}
2127
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002128static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002129switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002130{
2131 struct drm_compositor *ec = data;
2132
Daniel Stone325fc2d2012-05-30 16:31:58 +01002133 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002134}
2135
David Herrmann0af066f2012-10-29 19:21:16 +01002136/*
2137 * Find primary GPU
2138 * Some systems may have multiple DRM devices attached to a single seat. This
2139 * function loops over all devices and tries to find a PCI device with the
2140 * boot_vga sysfs attribute set to 1.
2141 * If no such device is found, the first DRM device reported by udev is used.
2142 */
2143static struct udev_device*
2144find_primary_gpu(struct drm_compositor *ec, const char *seat)
2145{
2146 struct udev_enumerate *e;
2147 struct udev_list_entry *entry;
2148 const char *path, *device_seat, *id;
2149 struct udev_device *device, *drm_device, *pci;
2150
2151 e = udev_enumerate_new(ec->udev);
2152 udev_enumerate_add_match_subsystem(e, "drm");
2153 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2154
2155 udev_enumerate_scan_devices(e);
2156 drm_device = NULL;
2157 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2158 path = udev_list_entry_get_name(entry);
2159 device = udev_device_new_from_syspath(ec->udev, path);
2160 if (!device)
2161 continue;
2162 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2163 if (!device_seat)
2164 device_seat = default_seat;
2165 if (strcmp(device_seat, seat)) {
2166 udev_device_unref(device);
2167 continue;
2168 }
2169
2170 pci = udev_device_get_parent_with_subsystem_devtype(device,
2171 "pci", NULL);
2172 if (pci) {
2173 id = udev_device_get_sysattr_value(pci, "boot_vga");
2174 if (id && !strcmp(id, "1")) {
2175 if (drm_device)
2176 udev_device_unref(drm_device);
2177 drm_device = device;
2178 break;
2179 }
2180 }
2181
2182 if (!drm_device)
2183 drm_device = device;
2184 else
2185 udev_device_unref(device);
2186 }
2187
2188 udev_enumerate_unref(e);
2189 return drm_device;
2190}
2191
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002192static void
2193hide_sprites_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
2194 void *data)
2195{
2196 struct drm_compositor *c = data;
2197
2198 c->sprites_hidden ^= 1;
2199}
2200
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002201static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002202drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002203 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002204 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002205{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002206 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002207 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002208 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002209 struct weston_seat *weston_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002210 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002211 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002212
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002213 weston_log("initializing drm backend\n");
2214
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002215 ec = malloc(sizeof *ec);
2216 if (ec == NULL)
2217 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002218 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002219
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002220 /* KMS support for sprites is not complete yet, so disable the
2221 * functionality for now. */
2222 ec->sprites_are_broken = 1;
2223
Daniel Stone725c2c32012-06-22 14:04:36 +01002224 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002225 config_file) < 0) {
2226 weston_log("weston_compositor_init failed\n");
2227 goto err_base;
2228 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002229
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002230 ec->udev = udev_new();
2231 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002232 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002233 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002234 }
2235
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002236 ec->base.wl_display = display;
2237 ec->tty = tty_create(&ec->base, vt_func, tty);
2238 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002239 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002240 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002241 }
2242
David Herrmann0af066f2012-10-29 19:21:16 +01002243 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002244 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002245 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002246 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002247 }
David Herrmann0af066f2012-10-29 19:21:16 +01002248 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002249
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002250 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002251 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002252 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002253 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002254
2255 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002256 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002257
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002258 ec->base.focus = 1;
2259
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002260 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002261
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002262 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002263 weston_compositor_add_key_binding(&ec->base, key,
2264 MODIFIER_CTRL | MODIFIER_ALT,
2265 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002266
Jesse Barnes58ef3792012-02-23 09:45:49 -05002267 wl_list_init(&ec->sprite_list);
2268 create_sprites(ec);
2269
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002270 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002271 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002272 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002273 }
2274
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002275 if (gles2_renderer_init(&ec->base) < 0)
2276 goto err_egl;
2277
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002278 path = NULL;
2279
Tiago Vignattice03ec32011-12-19 01:14:03 +02002280 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002281
2282 loop = wl_display_get_event_loop(ec->base.wl_display);
2283 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002284 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002285 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002286
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002287 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2288 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002289 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002290 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002291 }
2292 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2293 "drm", NULL);
2294 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002295 wl_event_loop_add_fd(loop,
2296 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002297 WL_EVENT_READABLE, udev_drm_event, ec);
2298
2299 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002300 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002301 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002302 }
2303
Daniel Stonea96b93c2012-06-22 14:04:37 +01002304 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002305
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002306 weston_compositor_add_debug_binding(&ec->base, KEY_O,
2307 hide_sprites_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002308
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002309 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002310
2311err_udev_monitor:
2312 wl_event_source_remove(ec->udev_drm_source);
2313 udev_monitor_unref(ec->udev_monitor);
2314err_drm_source:
2315 wl_event_source_remove(ec->drm_source);
2316 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2317 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002318err_egl:
2319 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2320 EGL_NO_CONTEXT);
2321 eglTerminate(ec->base.egl_display);
2322 eglReleaseThread();
2323 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002324err_sprite:
2325 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002326err_udev_dev:
2327 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002328err_tty:
Daniel Stonea96b93c2012-06-22 14:04:37 +01002329 tty_destroy(ec->tty);
2330err_udev:
2331 udev_unref(ec->udev);
2332err_compositor:
2333 weston_compositor_shutdown(&ec->base);
2334err_base:
2335 free(ec);
2336 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002337}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002338
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002339static int
2340set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2341{
2342 mode->flags = 0;
2343
2344 if (strcmp(hsync, "+hsync") == 0)
2345 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2346 else if (strcmp(hsync, "-hsync") == 0)
2347 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2348 else
2349 return -1;
2350
2351 if (strcmp(vsync, "+vsync") == 0)
2352 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2353 else if (strcmp(vsync, "-vsync") == 0)
2354 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2355 else
2356 return -1;
2357
2358 return 0;
2359}
2360
2361static int
2362check_for_modeline(struct drm_configured_output *output)
2363{
2364 drmModeModeInfo mode;
2365 char hsync[16];
2366 char vsync[16];
2367 char mode_name[16];
2368 float fclock;
2369
2370 mode.type = DRM_MODE_TYPE_USERDEF;
2371 mode.hskew = 0;
2372 mode.vscan = 0;
2373 mode.vrefresh = 0;
2374
2375 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2376 &fclock, &mode.hdisplay,
2377 &mode.hsync_start,
2378 &mode.hsync_end, &mode.htotal,
2379 &mode.vdisplay,
2380 &mode.vsync_start,
2381 &mode.vsync_end, &mode.vtotal,
2382 hsync, vsync) == 11) {
2383 if (set_sync_flags(&mode, hsync, vsync))
2384 return -1;
2385
2386 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2387 strcpy(mode.name, mode_name);
2388
2389 mode.clock = fclock * 1000;
2390 } else
2391 return -1;
2392
2393 output->crtc_mode = mode;
2394
2395 return 0;
2396}
2397
Scott Moreau8ab5d452012-07-30 19:51:08 -06002398static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002399drm_output_set_transform(struct drm_configured_output *output)
2400{
2401 if (!output_transform) {
2402 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2403 return;
2404 }
2405
2406 if (!strcmp(output_transform, "normal"))
2407 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2408 else if (!strcmp(output_transform, "90"))
2409 output->transform = WL_OUTPUT_TRANSFORM_90;
2410 else if (!strcmp(output_transform, "180"))
2411 output->transform = WL_OUTPUT_TRANSFORM_180;
2412 else if (!strcmp(output_transform, "270"))
2413 output->transform = WL_OUTPUT_TRANSFORM_270;
2414 else if (!strcmp(output_transform, "flipped"))
2415 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2416 else if (!strcmp(output_transform, "flipped-90"))
2417 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2418 else if (!strcmp(output_transform, "flipped-180"))
2419 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2420 else if (!strcmp(output_transform, "flipped-270"))
2421 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2422 else {
2423 weston_log("Invalid transform \"%s\" for output %s\n",
2424 output_transform, output_name);
2425 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2426 }
2427
2428 free(output_transform);
2429 output_transform = NULL;
2430}
2431
2432static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002433output_section_done(void *data)
2434{
2435 struct drm_configured_output *output;
2436
2437 output = malloc(sizeof *output);
2438
Scott Moreau1bad5db2012-08-18 01:04:05 -06002439 if (!output || !output_name || (output_name[0] == 'X') ||
2440 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002441 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002442 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002443 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002444 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002445 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002446 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002447 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002448 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002449 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002450
2451 output->config = OUTPUT_CONFIG_INVALID;
2452 output->name = output_name;
2453 output->mode = output_mode;
2454
Scott Moreau1bad5db2012-08-18 01:04:05 -06002455 if (output_mode) {
2456 if (strcmp(output_mode, "off") == 0)
2457 output->config = OUTPUT_CONFIG_OFF;
2458 else if (strcmp(output_mode, "preferred") == 0)
2459 output->config = OUTPUT_CONFIG_PREFERRED;
2460 else if (strcmp(output_mode, "current") == 0)
2461 output->config = OUTPUT_CONFIG_CURRENT;
2462 else if (sscanf(output_mode, "%dx%d",
2463 &output->width, &output->height) == 2)
2464 output->config = OUTPUT_CONFIG_MODE;
2465 else if (check_for_modeline(output) == 0)
2466 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002467
Scott Moreau1bad5db2012-08-18 01:04:05 -06002468 if (output->config == OUTPUT_CONFIG_INVALID)
2469 weston_log("Invalid mode \"%s\" for output %s\n",
2470 output_mode, output_name);
2471 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002472 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002473
2474 drm_output_set_transform(output);
2475
2476 wl_list_insert(&configured_output_list, &output->link);
2477
2478 if (output_transform)
2479 free(output_transform);
2480 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002481}
2482
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002483WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002484backend_init(struct wl_display *display, int argc, char *argv[],
2485 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002486{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002487 int connector = 0, tty = 0;
2488 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002489
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002490 const struct weston_option drm_options[] = {
2491 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2492 { WESTON_OPTION_STRING, "seat", 0, &seat },
2493 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002494 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002495 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002496
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002497 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002498
Scott Moreau8ab5d452012-07-30 19:51:08 -06002499 wl_list_init(&configured_output_list);
2500
2501 const struct config_key drm_config_keys[] = {
2502 { "name", CONFIG_KEY_STRING, &output_name },
2503 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002504 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002505 };
2506
2507 const struct config_section config_section[] = {
2508 { "output", drm_config_keys,
2509 ARRAY_LENGTH(drm_config_keys), output_section_done },
2510 };
2511
2512 parse_config_file(config_file, config_section,
2513 ARRAY_LENGTH(config_section), NULL);
2514
Daniel Stonec1be8e52012-06-01 11:14:02 -04002515 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2516 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002517}