blob: 0faf45c0b838233fc7f65ff988a3f91f9f546f19 [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;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500100
Rob Clarkab5b1e32012-08-09 13:24:45 -0500101 int cursors_are_broken;
102
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200103 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400104};
105
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400106struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500107 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400108 drmModeModeInfo mode_info;
109};
110
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300111struct drm_output;
112
113struct drm_fb {
114 struct gbm_bo *bo;
115 struct drm_output *output;
116 uint32_t fb_id;
117 int is_client_buffer;
118 struct wl_buffer *buffer;
119 struct wl_listener buffer_destroy_listener;
120};
121
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400122struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500123 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400124
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400125 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400126 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500127 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400128 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700129 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200130
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300131 int vblank_pending;
132 int page_flip_pending;
133
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400134 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400135 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400136 struct weston_plane cursor_plane;
137 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400138 struct weston_surface *cursor_surface;
139 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300140 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200141 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400142};
143
Jesse Barnes58ef3792012-02-23 09:45:49 -0500144/*
145 * An output has a primary display plane plus zero or more sprites for
146 * blending display contents.
147 */
148struct drm_sprite {
149 struct wl_list link;
150
151 uint32_t fb_id;
152 uint32_t pending_fb_id;
153 struct weston_surface *surface;
154 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400155 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500156
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300157 struct drm_output *output;
158
Jesse Barnes58ef3792012-02-23 09:45:49 -0500159 struct drm_compositor *compositor;
160
161 struct wl_listener destroy_listener;
162 struct wl_listener pending_destroy_listener;
163
164 uint32_t possible_crtcs;
165 uint32_t plane_id;
166 uint32_t count_formats;
167
168 int32_t src_x, src_y;
169 uint32_t src_w, src_h;
170 uint32_t dest_x, dest_y;
171 uint32_t dest_w, dest_h;
172
173 uint32_t formats[];
174};
175
Pekka Paalanen33156972012-08-03 13:30:30 -0400176struct drm_seat {
177 struct weston_seat base;
178 struct wl_list devices_list;
179 struct udev_monitor *udev_monitor;
180 struct wl_event_source *udev_monitor_source;
181 char *seat_id;
182};
183
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400184static void
185drm_output_set_cursor(struct drm_output *output);
186static void
187drm_disable_unused_sprites(struct weston_output *output_base);
188
Jesse Barnes58ef3792012-02-23 09:45:49 -0500189static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500190drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
191{
192 struct weston_compositor *ec = output_base->compositor;
193 struct drm_compositor *c =(struct drm_compositor *) ec;
194 struct drm_output *output = (struct drm_output *) output_base;
195 int crtc;
196
197 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
198 if (c->crtcs[crtc] != output->crtc_id)
199 continue;
200
201 if (supported & (1 << crtc))
202 return -1;
203 }
204
205 return 0;
206}
207
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300208static void
209drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
210{
211 struct drm_fb *fb = data;
212 struct gbm_device *gbm = gbm_bo_get_device(bo);
213
214 if (fb->fb_id)
215 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
216
217 if (fb->buffer) {
218 weston_buffer_post_release(fb->buffer);
219 wl_list_remove(&fb->buffer_destroy_listener.link);
220 }
221
222 free(data);
223}
224
225static struct drm_fb *
226drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
227{
228 struct drm_fb *fb = gbm_bo_get_user_data(bo);
229 struct drm_compositor *compositor =
230 (struct drm_compositor *) output->base.compositor;
231 uint32_t width, height, stride, handle;
232 int ret;
233
234 if (fb)
235 return fb;
236
237 fb = malloc(sizeof *fb);
238
239 fb->bo = bo;
240 fb->output = output;
241 fb->is_client_buffer = 0;
242 fb->buffer = NULL;
243
244 width = gbm_bo_get_width(bo);
245 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400246 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300247 handle = gbm_bo_get_handle(bo).u32;
248
249 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
250 stride, handle, &fb->fb_id);
251 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200252 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300253 free(fb);
254 return NULL;
255 }
256
257 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
258
259 return fb;
260}
261
262static void
263fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
264{
265 struct drm_fb *fb = container_of(listener, struct drm_fb,
266 buffer_destroy_listener);
267
268 fb->buffer = NULL;
269
270 if (fb == fb->output->next ||
271 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400272 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300273}
274
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400275static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400276drm_output_prepare_scanout_surface(struct weston_output *_output,
277 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500278{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400279 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500280 struct drm_compositor *c =
281 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300282 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500283
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500284 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200285 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200286 es->geometry.width != output->base.current->width ||
287 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200288 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400289 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400290 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500291
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400292 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
293 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500294
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300295 /* Need to verify output->region contained in surface opaque
296 * region. Or maybe just that format doesn't have alpha.
297 * For now, scanout only if format is XRGB8888. */
298 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
299 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400300 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300301 }
302
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300303 output->next = drm_fb_get_from_bo(bo, output);
304 if (!output->next) {
305 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400306 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300307 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500308
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300309 output->next->is_client_buffer = 1;
310 output->next->buffer = es->buffer;
311 output->next->buffer->busy_count++;
312 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
313
314 wl_signal_add(&output->next->buffer->resource.destroy_signal,
315 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500316
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400317 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500318}
319
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500320static void
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400321drm_output_render(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400322{
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400323 struct weston_compositor *ec = output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300324 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400325
Kristian Høgsbergfa1be022012-09-05 22:49:55 -0400326 ec->renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400327
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300328 bo = gbm_surface_lock_front_buffer(output->surface);
329 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200330 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400331 return;
332 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300333
334 output->next = drm_fb_get_from_bo(bo, output);
335 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200336 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300337 gbm_surface_release_buffer(output->surface, bo);
338 return;
339 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400340}
341
342static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500343drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400344 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100345{
346 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500347 struct drm_compositor *compositor =
348 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500349 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400350 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500351 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100352
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300353 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400354 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300355 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400356 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100357
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400358 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300359 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400360 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300361 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400362 &output->connector_id, 1,
363 &mode->mode_info);
364 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200365 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400366 return;
367 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200368 }
369
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500370 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300371 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500372 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200373 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500374 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500375 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100376
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300377 output->page_flip_pending = 1;
378
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400379 drm_output_set_cursor(output);
380
Jesse Barnes58ef3792012-02-23 09:45:49 -0500381 /*
382 * Now, update all the sprite surfaces
383 */
384 wl_list_for_each(s, &compositor->sprite_list, link) {
385 uint32_t flags = 0;
386 drmVBlank vbl = {
387 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
388 .request.sequence = 1,
389 };
390
391 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
392 continue;
393
394 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
395 output->crtc_id, s->pending_fb_id, flags,
396 s->dest_x, s->dest_y,
397 s->dest_w, s->dest_h,
398 s->src_x, s->src_y,
399 s->src_w, s->src_h);
400 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200401 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500402 ret, strerror(errno));
403
Rob Clark5ca1a472012-08-08 20:27:37 -0500404 if (output->pipe > 0)
405 vbl.request.type |= DRM_VBLANK_SECONDARY;
406
Jesse Barnes58ef3792012-02-23 09:45:49 -0500407 /*
408 * Queue a vblank signal so we know when the surface
409 * becomes active on the display or has been replaced.
410 */
411 vbl.request.signal = (unsigned long)s;
412 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
413 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200414 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500415 ret, strerror(errno));
416 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300417
418 s->output = output;
419 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500420 }
421
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400422 drm_disable_unused_sprites(&output->base);
423
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500424 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400425}
426
427static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500428vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
429 void *data)
430{
431 struct drm_sprite *s = (struct drm_sprite *)data;
432 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300433 struct drm_output *output = s->output;
434 uint32_t msecs;
435
436 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500437
438 if (s->surface) {
439 weston_buffer_post_release(s->surface->buffer);
440 wl_list_remove(&s->destroy_listener.link);
441 s->surface = NULL;
442 drmModeRmFB(c->drm.fd, s->fb_id);
443 s->fb_id = 0;
444 }
445
446 if (s->pending_surface) {
447 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400448 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
449 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500450 s->surface = s->pending_surface;
451 s->pending_surface = NULL;
452 s->fb_id = s->pending_fb_id;
453 s->pending_fb_id = 0;
454 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300455
456 if (!output->page_flip_pending) {
457 msecs = sec * 1000 + usec / 1000;
458 weston_output_finish_frame(&output->base, msecs);
459 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500460}
461
462static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400463page_flip_handler(int fd, unsigned int frame,
464 unsigned int sec, unsigned int usec, void *data)
465{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200466 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400467 uint32_t msecs;
468
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300469 output->page_flip_pending = 0;
470
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300471 if (output->current) {
472 if (output->current->is_client_buffer)
473 gbm_bo_destroy(output->current->bo);
474 else
475 gbm_surface_release_buffer(output->surface,
476 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200477 }
478
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300479 output->current = output->next;
480 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400481
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300482 if (!output->vblank_pending) {
483 msecs = sec * 1000 + usec / 1000;
484 weston_output_finish_frame(&output->base, msecs);
485 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200486}
487
488static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500489drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
490{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400491 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500492
493 for (i = 0; i < s->count_formats; i++)
494 if (s->formats[i] == format)
495 return 1;
496
497 return 0;
498}
499
500static int
501drm_surface_transform_supported(struct weston_surface *es)
502{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400503 struct weston_matrix *matrix = &es->transform.matrix;
504 int i;
505
506 if (!es->transform.enabled)
507 return 1;
508
509 for (i = 0; i < 16; i++) {
510 switch (i) {
511 case 10:
512 case 15:
513 if (matrix->d[i] != 1.0)
514 return 0;
515 break;
516 case 0:
517 case 5:
518 case 12:
519 case 13:
520 break;
521 default:
522 if (matrix->d[i] != 0.0)
523 return 0;
524 break;
525 }
526 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500527
528 return 1;
529}
530
Jesse Barnes58ef3792012-02-23 09:45:49 -0500531static void
532drm_disable_unused_sprites(struct weston_output *output_base)
533{
534 struct weston_compositor *ec = output_base->compositor;
535 struct drm_compositor *c =(struct drm_compositor *) ec;
536 struct drm_output *output = (struct drm_output *) output_base;
537 struct drm_sprite *s;
538 int ret;
539
540 wl_list_for_each(s, &c->sprite_list, link) {
541 if (s->pending_fb_id)
542 continue;
543
544 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
545 output->crtc_id, 0, 0,
546 0, 0, 0, 0, 0, 0, 0, 0);
547 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200548 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500549 ret, strerror(errno));
550 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300551
552 if (s->surface) {
553 s->surface = NULL;
554 wl_list_remove(&s->destroy_listener.link);
555 }
556
557 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500558 s->fb_id = 0;
559 s->pending_fb_id = 0;
560 }
561}
562
563/*
564 * This function must take care to damage any previously assigned surface
565 * if the sprite ends up binding to a different surface than in the
566 * previous frame.
567 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400568static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500569drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400570 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500571{
572 struct weston_compositor *ec = output_base->compositor;
573 struct drm_compositor *c =(struct drm_compositor *) ec;
574 struct drm_sprite *s;
575 int found = 0;
576 EGLint handle, stride;
577 struct gbm_bo *bo;
578 uint32_t fb_id = 0;
579 uint32_t handles[4], pitches[4], offsets[4];
580 int ret = 0;
581 pixman_region32_t dest_rect, src_rect;
582 pixman_box32_t *box;
583 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400584 wl_fixed_t sx1, sy1, sx2, sy2;
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400585 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500586
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500587 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400588 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500589
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300590 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400591 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300592
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400593 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400594 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500595
Rob Clark702ffae2012-08-09 14:18:27 -0500596 if (wl_buffer_is_shm(es->buffer))
597 return NULL;
598
Jesse Barnes58ef3792012-02-23 09:45:49 -0500599 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400600 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500601
Jesse Barnes58ef3792012-02-23 09:45:49 -0500602 wl_list_for_each(s, &c->sprite_list, link) {
603 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
604 continue;
605
606 if (!s->pending_fb_id) {
607 found = 1;
608 break;
609 }
610 }
611
612 /* No sprites available */
613 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400614 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615
Rob Clark4339add2012-08-09 14:18:28 -0500616 width = es->geometry.width;
617 height = es->geometry.height;
618
619 /* If geometry is out of bounds, don't even bother trying because
620 * we know the AddFB2() call will fail:
621 */
622 if (c->min_width > width || width > c->max_width ||
623 c->min_height > height || height > c->max_height)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400624 return NULL;
Rob Clark4339add2012-08-09 14:18:28 -0500625
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400626 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
627 es->buffer, GBM_BO_USE_SCANOUT);
628 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400629 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400630
Jesse Barnes58ef3792012-02-23 09:45:49 -0500631 format = gbm_bo_get_format(bo);
632 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400633 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634
635 gbm_bo_destroy(bo);
636
637 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400638 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639
640 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400641 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500642
643 handles[0] = handle;
644 pitches[0] = stride;
645 offsets[0] = 0;
646
Rob Clark4339add2012-08-09 14:18:28 -0500647 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500648 format, handles, pitches, offsets,
649 &fb_id, 0);
650 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200651 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500652 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400653 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 }
655
Jesse Barnes58ef3792012-02-23 09:45:49 -0500656 s->pending_fb_id = fb_id;
657 s->pending_surface = es;
658 es->buffer->busy_count++;
659
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400660 box = pixman_region32_extents(&es->transform.boundingbox);
661 s->plane.x = box->x1;
662 s->plane.y = box->y1;
663
Jesse Barnes58ef3792012-02-23 09:45:49 -0500664 /*
665 * Calculate the source & dest rects properly based on actual
666 * postion (note the caller has called weston_surface_update_transform()
667 * for us already).
668 */
669 pixman_region32_init(&dest_rect);
670 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
671 &output_base->region);
672 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
673 box = pixman_region32_extents(&dest_rect);
674 s->dest_x = box->x1;
675 s->dest_y = box->y1;
676 s->dest_w = box->x2 - box->x1;
677 s->dest_h = box->y2 - box->y1;
678 pixman_region32_fini(&dest_rect);
679
680 pixman_region32_init(&src_rect);
681 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
682 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500683 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400684
685 weston_surface_from_global_fixed(es,
686 wl_fixed_from_int(box->x1),
687 wl_fixed_from_int(box->y1),
688 &sx1, &sy1);
689 weston_surface_from_global_fixed(es,
690 wl_fixed_from_int(box->x2),
691 wl_fixed_from_int(box->y2),
692 &sx2, &sy2);
693
694 if (sx1 < 0)
695 sx1 = 0;
696 if (sy1 < 0)
697 sy1 = 0;
698 if (sx2 > wl_fixed_from_int(es->geometry.width))
699 sx2 = wl_fixed_from_int(es->geometry.width);
700 if (sy2 > wl_fixed_from_int(es->geometry.height))
701 sy2 = wl_fixed_from_int(es->geometry.height);
702
703 s->src_x = sx1 << 8;
704 s->src_y = sy1 << 8;
705 s->src_w = (sx2 - sx1) << 8;
706 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500707 pixman_region32_fini(&src_rect);
708
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400709 wl_signal_add(&es->buffer->resource.destroy_signal,
710 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400711
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400712 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500713}
714
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400715static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400716drm_output_prepare_cursor_surface(struct weston_output *output_base,
717 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500718{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400719 struct drm_compositor *c =
720 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400721 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400722
723 if (output->cursor_surface)
724 return NULL;
725 if (es->output_mask != (1u << output_base->id))
726 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500727 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400728 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400729 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
730 es->geometry.width > 64 || es->geometry.height > 64)
731 return NULL;
732
733 output->cursor_surface = es;
734
735 return &output->cursor_plane;
736}
737
738static void
739drm_output_set_cursor(struct drm_output *output)
740{
741 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400742 struct drm_compositor *c =
743 (struct drm_compositor *) output->base.compositor;
744 EGLint handle, stride;
745 struct gbm_bo *bo;
746 uint32_t buf[64 * 64];
747 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400748 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500749
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400750 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400751 if (es == NULL) {
752 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
753 return;
754 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500755
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400756 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
757 pixman_region32_fini(&output->cursor_plane.damage);
758 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400759 output->current_cursor ^= 1;
760 bo = output->cursor_bo[output->current_cursor];
761 memset(buf, 0, sizeof buf);
762 stride = wl_shm_buffer_get_stride(es->buffer);
763 s = wl_shm_buffer_get_data(es->buffer);
764 for (i = 0; i < es->geometry.height; i++)
765 memcpy(buf + i * 64, s + i * stride,
766 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500767
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400768 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300769 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400770
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400771 handle = gbm_bo_get_handle(bo).s32;
772 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500773 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300774 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500775 c->cursors_are_broken = 1;
776 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400777 }
778
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400779 x = es->geometry.x - output->base.x;
780 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400781 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500782 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400783 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500784 c->cursors_are_broken = 1;
785 }
786
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400787 output->cursor_plane.x = x;
788 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400789 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500790}
791
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792static void
793drm_assign_planes(struct weston_output *output)
794{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400795 struct drm_compositor *c =
796 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400797 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400799 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800
801 /*
802 * Find a surface for each sprite in the output using some heuristics:
803 * 1) size
804 * 2) frequency of update
805 * 3) opacity (though some hw might support alpha blending)
806 * 4) clipping (this can be fixed with color keys)
807 *
808 * The idea is to save on blitting since this should save power.
809 * If we can get a large video surface on the sprite for example,
810 * the main display surface may not need to update at all, and
811 * the client buffer can be used directly for the sprite surface
812 * as we do for flipping full screen surfaces.
813 */
814 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400815 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400816 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817 pixman_region32_init(&surface_overlap);
818 pixman_region32_intersect(&surface_overlap, &overlap,
819 &es->transform.boundingbox);
820
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400821 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400822 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400823 next_plane = primary;
824 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400825 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400826 if (next_plane == NULL)
827 next_plane = drm_output_prepare_scanout_surface(output, es);
828 if (next_plane == NULL)
829 next_plane = drm_output_prepare_overlay_surface(output, es);
830 if (next_plane == NULL)
831 next_plane = primary;
832 weston_surface_move_to_plane(es, next_plane);
833 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834 pixman_region32_union(&overlap, &overlap,
835 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400836
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837 pixman_region32_fini(&surface_overlap);
838 }
839 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840}
841
Matt Roper361d2ad2011-08-29 13:52:23 -0700842static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500843drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700844{
845 struct drm_output *output = (struct drm_output *) output_base;
846 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200847 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700848 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700849
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200850 if (output->backlight)
851 backlight_destroy(output->backlight);
852
Matt Roper361d2ad2011-08-29 13:52:23 -0700853 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400854 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700855
856 /* Restore original CRTC state */
857 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200858 origcrtc->x, origcrtc->y,
859 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700860 drmModeFreeCrtc(origcrtc);
861
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200862 c->crtc_allocator &= ~(1 << output->crtc_id);
863 c->connector_allocator &= ~(1 << output->connector_id);
864
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400865 eglDestroySurface(c->base.egl_display, output->base.egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400866 gbm_surface_destroy(output->surface);
867
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400868 weston_plane_release(&output->fb_plane);
869 weston_plane_release(&output->cursor_plane);
870
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500871 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200872 wl_list_remove(&output->base.link);
873
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400874 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700875 free(output);
876}
877
Alex Wub7b8bda2012-04-17 17:20:48 +0800878static struct drm_mode *
879choose_mode (struct drm_output *output, struct weston_mode *target_mode)
880{
881 struct drm_mode *tmp_mode = NULL, *mode;
882
883 if (output->base.current->width == target_mode->width &&
884 output->base.current->height == target_mode->height &&
885 (output->base.current->refresh == target_mode->refresh ||
886 target_mode->refresh == 0))
887 return (struct drm_mode *)output->base.current;
888
889 wl_list_for_each(mode, &output->base.mode_list, base.link) {
890 if (mode->mode_info.hdisplay == target_mode->width &&
891 mode->mode_info.vdisplay == target_mode->height) {
892 if (mode->mode_info.vrefresh == target_mode->refresh ||
893 target_mode->refresh == 0) {
894 return mode;
895 } else if (!tmp_mode)
896 tmp_mode = mode;
897 }
898 }
899
900 return tmp_mode;
901}
902
903static int
904drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
905{
906 struct drm_output *output;
907 struct drm_mode *drm_mode;
908 int ret;
909 struct drm_compositor *ec;
910 struct gbm_surface *surface;
911 EGLSurface egl_surface;
912
913 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200914 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800915 return -1;
916 }
917
918 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200919 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800920 return -1;
921 }
922
923 ec = (struct drm_compositor *)output_base->compositor;
924 output = (struct drm_output *)output_base;
925 drm_mode = choose_mode (output, mode);
926
927 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200928 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800929 return -1;
930 } else if (&drm_mode->base == output->base.current) {
931 return 0;
932 } else if (drm_mode->base.width == output->base.current->width &&
933 drm_mode->base.height == output->base.current->height) {
934 /* only change refresh value */
935 ret = drmModeSetCrtc(ec->drm.fd,
936 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300937 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800938 &output->connector_id, 1, &drm_mode->mode_info);
939
940 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200941 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800942 drm_mode->base.width,
943 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400944 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800945 ret = -1;
946 } else {
947 output->base.current->flags = 0;
948 output->base.current = &drm_mode->base;
949 drm_mode->base.flags =
950 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
951 ret = 0;
952 }
953
954 return ret;
955 }
956
957 drm_mode->base.flags =
958 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
959
960 surface = gbm_surface_create(ec->gbm,
961 drm_mode->base.width,
962 drm_mode->base.height,
963 GBM_FORMAT_XRGB8888,
964 GBM_BO_USE_SCANOUT |
965 GBM_BO_USE_RENDERING);
966 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200967 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800968 return -1;
969 }
970
971 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400972 eglCreateWindowSurface(ec->base.egl_display,
973 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800974 surface, NULL);
975
976 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +0200977 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800978 goto err;
979 }
980
981 ret = drmModeSetCrtc(ec->drm.fd,
982 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300983 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800984 &output->connector_id, 1, &drm_mode->mode_info);
985 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200986 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800987 goto err;
988 }
989
990 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300991 if (output->current) {
992 if (output->current->is_client_buffer)
993 gbm_bo_destroy(output->current->bo);
994 else
995 gbm_surface_release_buffer(output->surface,
996 output->current->bo);
997 }
998 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +0800999
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001000 if (output->next) {
1001 if (output->next->is_client_buffer)
1002 gbm_bo_destroy(output->next->bo);
1003 else
1004 gbm_surface_release_buffer(output->surface,
1005 output->next->bo);
1006 }
1007 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001008
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001009 eglDestroySurface(ec->base.egl_display, output->base.egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001010 gbm_surface_destroy(output->surface);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001011 output->base.egl_surface = egl_surface;
Alex Wub7b8bda2012-04-17 17:20:48 +08001012 output->surface = surface;
1013
1014 /*update output*/
1015 output->base.current = &drm_mode->base;
1016 output->base.dirty = 1;
1017 weston_output_move(&output->base, output->base.x, output->base.y);
1018 return 0;
1019
1020err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001021 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001022 gbm_surface_destroy(surface);
1023 return -1;
1024}
1025
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001026static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001027on_drm_input(int fd, uint32_t mask, void *data)
1028{
1029 drmEventContext evctx;
1030
1031 memset(&evctx, 0, sizeof evctx);
1032 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1033 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001034 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001035 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001036
1037 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001038}
1039
1040static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001041init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001042{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001043 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001044 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001045 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001046 static const EGLint config_attribs[] = {
1047 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1048 EGL_RED_SIZE, 1,
1049 EGL_GREEN_SIZE, 1,
1050 EGL_BLUE_SIZE, 1,
1051 EGL_ALPHA_SIZE, 0,
1052 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1053 EGL_NONE
1054 };
1055
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001056 sysnum = udev_device_get_sysnum(device);
1057 if (sysnum)
1058 ec->drm.id = atoi(sysnum);
1059 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001060 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001061 return -1;
1062 }
1063
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001064 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001065 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001066 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001067 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001068 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001069 udev_device_get_devnode(device));
1070 return -1;
1071 }
1072
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001073 weston_log("using %s\n", filename);
1074
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001075 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001076 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001077 ec->base.egl_display = eglGetDisplay(ec->gbm);
1078 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001079 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001080 return -1;
1081 }
1082
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001083 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001084 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001085 return -1;
1086 }
1087
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001088 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1089 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001090 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001091 return -1;
1092 }
1093
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001094 return 0;
1095}
1096
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001097static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001098drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1099{
1100 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001101 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001102
1103 mode = malloc(sizeof *mode);
1104 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001105 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001106
1107 mode->base.flags = 0;
1108 mode->base.width = info->hdisplay;
1109 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001110
1111 /* Calculate higher precision (mHz) refresh rate */
1112 refresh = (info->clock * 1000000LL / info->htotal +
1113 info->vtotal / 2) / info->vtotal;
1114
1115 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1116 refresh *= 2;
1117 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1118 refresh /= 2;
1119 if (info->vscan > 1)
1120 refresh /= info->vscan;
1121
1122 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001123 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001124
1125 if (info->type & DRM_MODE_TYPE_PREFERRED)
1126 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1127
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001128 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1129
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001130 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001131}
1132
1133static int
1134drm_subpixel_to_wayland(int drm_value)
1135{
1136 switch (drm_value) {
1137 default:
1138 case DRM_MODE_SUBPIXEL_UNKNOWN:
1139 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1140 case DRM_MODE_SUBPIXEL_NONE:
1141 return WL_OUTPUT_SUBPIXEL_NONE;
1142 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1143 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1144 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1145 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1146 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1147 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1148 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1149 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1150 }
1151}
1152
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001153static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001154sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001155{
1156 struct drm_sprite *sprite =
1157 container_of(listener, struct drm_sprite,
1158 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001159 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001160
1161 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001162 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1163 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001164}
1165
1166static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001167sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001168{
1169 struct drm_sprite *sprite =
1170 container_of(listener, struct drm_sprite,
1171 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001172 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001173
1174 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001175 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1176 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001177}
1178
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001179/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001180static uint32_t
1181drm_get_backlight(struct drm_output *output)
1182{
1183 long brightness, max_brightness, norm;
1184
1185 brightness = backlight_get_brightness(output->backlight);
1186 max_brightness = backlight_get_max_brightness(output->backlight);
1187
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001188 /* convert it on a scale of 0 to 255 */
1189 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001190
1191 return (uint32_t) norm;
1192}
1193
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001194/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001195static void
1196drm_set_backlight(struct weston_output *output_base, uint32_t value)
1197{
1198 struct drm_output *output = (struct drm_output *) output_base;
1199 long max_brightness, new_brightness;
1200
1201 if (!output->backlight)
1202 return;
1203
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001204 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001205 return;
1206
1207 max_brightness = backlight_get_max_brightness(output->backlight);
1208
1209 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001210 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001211
1212 backlight_set_brightness(output->backlight, new_brightness);
1213}
1214
1215static drmModePropertyPtr
1216drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1217{
1218 drmModePropertyPtr props;
1219 int i;
1220
1221 for (i = 0; i < connector->count_props; i++) {
1222 props = drmModeGetProperty(fd, connector->props[i]);
1223 if (!props)
1224 continue;
1225
1226 if (!strcmp(props->name, name))
1227 return props;
1228
1229 drmModeFreeProperty(props);
1230 }
1231
1232 return NULL;
1233}
1234
1235static void
1236drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1237{
1238 struct drm_output *output = (struct drm_output *) output_base;
1239 struct weston_compositor *ec = output_base->compositor;
1240 struct drm_compositor *c = (struct drm_compositor *) ec;
1241 drmModeConnectorPtr connector;
1242 drmModePropertyPtr prop;
1243
1244 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1245 if (!connector)
1246 return;
1247
1248 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1249 if (!prop) {
1250 drmModeFreeConnector(connector);
1251 return;
1252 }
1253
1254 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1255 prop->prop_id, level);
1256 drmModeFreeProperty(prop);
1257 drmModeFreeConnector(connector);
1258}
1259
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001260static const char *connector_type_names[] = {
1261 "None",
1262 "VGA",
1263 "DVI",
1264 "DVI",
1265 "DVI",
1266 "Composite",
1267 "TV",
1268 "LVDS",
1269 "CTV",
1270 "DIN",
1271 "DP",
1272 "HDMI",
1273 "HDMI",
1274 "TV",
1275 "eDP",
1276};
1277
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001278static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001279find_crtc_for_connector(struct drm_compositor *ec,
1280 drmModeRes *resources, drmModeConnector *connector)
1281{
1282 drmModeEncoder *encoder;
1283 uint32_t possible_crtcs;
1284 int i, j;
1285
1286 for (j = 0; j < connector->count_encoders; j++) {
1287 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1288 if (encoder == NULL) {
1289 weston_log("Failed to get encoder.\n");
1290 return -1;
1291 }
1292 possible_crtcs = encoder->possible_crtcs;
1293 drmModeFreeEncoder(encoder);
1294
1295 for (i = 0; i < resources->count_crtcs; i++) {
1296 if (possible_crtcs & (1 << i) &&
1297 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1298 return i;
1299 }
1300 }
1301
1302 return -1;
1303}
1304
1305static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001306create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001307 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001308 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001309 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001310{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001311 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001312 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1313 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001314 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001315 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001316 drmModeModeInfo crtc_mode;
1317 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001318 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001319 char name[32];
1320 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001321
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001322 i = find_crtc_for_connector(ec, resources, connector);
1323 if (i < 0) {
1324 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001325 return -1;
1326 }
1327
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001328 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001329 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001330 return -1;
1331
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001332 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001333 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1334 output->base.make = "unknown";
1335 output->base.model = "unknown";
1336 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001337
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001338 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1339 type_name = connector_type_names[connector->connector_type];
1340 else
1341 type_name = "UNKNOWN";
1342 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1343 output->name = strdup(name);
1344
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001345 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001346 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001347 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001348 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001349 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001350
Matt Roper361d2ad2011-08-29 13:52:23 -07001351 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1352
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001353 /* Get the current mode on the crtc that's currently driving
1354 * this connector. */
1355 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001356 memset(&crtc_mode, 0, sizeof crtc_mode);
1357 if (encoder != NULL) {
1358 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1359 drmModeFreeEncoder(encoder);
1360 if (crtc == NULL)
1361 goto err_free;
1362 if (crtc->mode_valid)
1363 crtc_mode = crtc->mode;
1364 drmModeFreeCrtc(crtc);
1365 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001366
David Herrmann0f0d54e2011-12-08 17:05:45 +01001367 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001368 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1369 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001370 goto err_free;
1371 }
1372
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001373 preferred = NULL;
1374 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001375 configured = NULL;
1376
1377 wl_list_for_each(temp, &configured_output_list, link) {
1378 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001379 if (temp->mode)
1380 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001381 temp->name, temp->mode);
1382 o = temp;
1383 break;
1384 }
1385 }
1386
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001387 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001388 weston_log("Disabling output %s\n", o->name);
1389
1390 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1391 0, 0, 0, 0, 0, NULL);
1392 goto err_free;
1393 }
1394
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001395 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001396 if (o && o->config == OUTPUT_CONFIG_MODE &&
1397 o->width == drm_mode->base.width &&
1398 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001399 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001400 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001401 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001402 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001403 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001404 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001405
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001406 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001407 configured = drm_output_add_mode(output, &o->crtc_mode);
1408 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001409 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001410 current = configured;
1411 }
1412
Wang Quanxianacb805a2012-07-30 18:09:46 -04001413 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001414 current = drm_output_add_mode(output, &crtc_mode);
1415 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001416 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001417 }
1418
Scott Moreau8ab5d452012-07-30 19:51:08 -06001419 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1420 configured = current;
1421
Wang Quanxianacb805a2012-07-30 18:09:46 -04001422 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001423 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001424 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001425 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001426 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001427 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001428 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001429 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001430
1431 if (output->base.current == NULL) {
1432 weston_log("no available modes for %s\n", output->name);
1433 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001434 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001435
Wang Quanxianacb805a2012-07-30 18:09:46 -04001436 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1437
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001438 output->surface = gbm_surface_create(ec->gbm,
1439 output->base.current->width,
1440 output->base.current->height,
1441 GBM_FORMAT_XRGB8888,
1442 GBM_BO_USE_SCANOUT |
1443 GBM_BO_USE_RENDERING);
1444 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001445 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001446 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001447 }
1448
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001449 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001450 eglCreateWindowSurface(ec->base.egl_display,
1451 ec->base.egl_config,
1452 output->surface,
1453 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001454 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001455 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001456 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001457 }
1458
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001459 output->cursor_bo[0] =
1460 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1461 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1462 output->cursor_bo[1] =
1463 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1464 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1465
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001466 output->backlight = backlight_init(drm_device,
1467 connector->connector_type);
1468 if (output->backlight) {
1469 output->base.set_backlight = drm_set_backlight;
1470 output->base.backlight_current = drm_get_backlight(output);
1471 }
1472
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001473 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001474 connector->mmWidth, connector->mmHeight,
1475 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001476
1477 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1478
Alex Wubd3354b2012-04-17 17:20:49 +08001479 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001480 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001481 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001482 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001483 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001484 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001485
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001486 weston_plane_init(&output->cursor_plane, 0, 0);
1487 weston_plane_init(&output->fb_plane, 0, 0);
1488
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001489 weston_log("Output %s, (connector %d, crtc %d)\n",
1490 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001491 wl_list_for_each(m, &output->base.mode_list, link)
1492 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1493 m->width, m->height, m->refresh / 1000.0,
1494 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1495 ", preferred" : "",
1496 m->flags & WL_OUTPUT_MODE_CURRENT ?
1497 ", current" : "",
1498 connector->count_modes == 0 ?
1499 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001500
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001501 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001502
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001503err_surface:
1504 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001505err_free:
1506 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1507 base.link) {
1508 wl_list_remove(&drm_mode->base.link);
1509 free(drm_mode);
1510 }
1511
1512 drmModeFreeCrtc(output->original_crtc);
1513 ec->crtc_allocator &= ~(1 << output->crtc_id);
1514 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001515 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001516 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001517
David Herrmann0f0d54e2011-12-08 17:05:45 +01001518 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001519}
1520
Jesse Barnes58ef3792012-02-23 09:45:49 -05001521static void
1522create_sprites(struct drm_compositor *ec)
1523{
1524 struct drm_sprite *sprite;
1525 drmModePlaneRes *plane_res;
1526 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001527 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001528
1529 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1530 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001531 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001532 strerror(errno));
1533 return;
1534 }
1535
1536 for (i = 0; i < plane_res->count_planes; i++) {
1537 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1538 if (!plane)
1539 continue;
1540
1541 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1542 plane->count_formats));
1543 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001544 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001545 __func__);
1546 free(plane);
1547 continue;
1548 }
1549
1550 memset(sprite, 0, sizeof *sprite);
1551
1552 sprite->possible_crtcs = plane->possible_crtcs;
1553 sprite->plane_id = plane->plane_id;
1554 sprite->surface = NULL;
1555 sprite->pending_surface = NULL;
1556 sprite->fb_id = 0;
1557 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001558 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1559 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001560 sprite_handle_pending_buffer_destroy;
1561 sprite->compositor = ec;
1562 sprite->count_formats = plane->count_formats;
1563 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001564 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001565 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001566 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001567
1568 wl_list_insert(&ec->sprite_list, &sprite->link);
1569 }
1570
1571 free(plane_res->planes);
1572 free(plane_res);
1573}
1574
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001575static void
1576destroy_sprites(struct drm_compositor *compositor)
1577{
1578 struct drm_sprite *sprite, *next;
1579 struct drm_output *output;
1580
1581 output = container_of(compositor->base.output_list.next,
1582 struct drm_output, base.link);
1583
1584 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1585 drmModeSetPlane(compositor->drm.fd,
1586 sprite->plane_id,
1587 output->crtc_id, 0, 0,
1588 0, 0, 0, 0, 0, 0, 0, 0);
1589 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001590 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001591 free(sprite);
1592 }
1593}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001594
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001595static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001596create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001597 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001598{
1599 drmModeConnector *connector;
1600 drmModeRes *resources;
1601 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001602 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001603
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001604 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001605 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001606 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001607 return -1;
1608 }
1609
Jesse Barnes58ef3792012-02-23 09:45:49 -05001610 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001611 if (!ec->crtcs) {
1612 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001613 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001614 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001615
Rob Clark4339add2012-08-09 14:18:28 -05001616 ec->min_width = resources->min_width;
1617 ec->max_width = resources->max_width;
1618 ec->min_height = resources->min_height;
1619 ec->max_height = resources->max_height;
1620
Jesse Barnes58ef3792012-02-23 09:45:49 -05001621 ec->num_crtcs = resources->count_crtcs;
1622 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1623
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001624 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001625 connector = drmModeGetConnector(ec->drm.fd,
1626 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001627 if (connector == NULL)
1628 continue;
1629
1630 if (connector->connection == DRM_MODE_CONNECTED &&
1631 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001632 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001633 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001634 connector, x, y,
1635 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001636 drmModeFreeConnector(connector);
1637 continue;
1638 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001639
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001640 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001641 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001642 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001643 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001644
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001645 drmModeFreeConnector(connector);
1646 }
1647
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001648 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001649 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001650 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001651 return -1;
1652 }
1653
1654 drmModeFreeResources(resources);
1655
1656 return 0;
1657}
1658
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001659static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001660update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001661{
1662 drmModeConnector *connector;
1663 drmModeRes *resources;
1664 struct drm_output *output, *next;
1665 int x = 0, y = 0;
1666 int x_offset = 0, y_offset = 0;
1667 uint32_t connected = 0, disconnects = 0;
1668 int i;
1669
1670 resources = drmModeGetResources(ec->drm.fd);
1671 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001672 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001673 return;
1674 }
1675
1676 /* collect new connects */
1677 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001678 int connector_id = resources->connectors[i];
1679
1680 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001681 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001682 continue;
1683
David Herrmann7551cff2011-12-08 17:05:43 +01001684 if (connector->connection != DRM_MODE_CONNECTED) {
1685 drmModeFreeConnector(connector);
1686 continue;
1687 }
1688
Benjamin Franzke117483d2011-08-30 11:38:26 +02001689 connected |= (1 << connector_id);
1690
1691 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001692 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001693 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001694 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001695
1696 /* XXX: not yet needed, we die with 0 outputs */
1697 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001698 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001699 else
1700 x = 0;
1701 y = 0;
1702 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001703 connector, x, y,
1704 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001705 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001706
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001707 }
1708 drmModeFreeConnector(connector);
1709 }
1710 drmModeFreeResources(resources);
1711
1712 disconnects = ec->connector_allocator & ~connected;
1713 if (disconnects) {
1714 wl_list_for_each_safe(output, next, &ec->base.output_list,
1715 base.link) {
1716 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001717 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001718 output->base.x - x_offset,
1719 output->base.y - y_offset);
1720 }
1721
1722 if (disconnects & (1 << output->connector_id)) {
1723 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001724 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001725 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001726 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001727 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001728 }
1729 }
1730 }
1731
1732 /* FIXME: handle zero outputs, without terminating */
1733 if (ec->connector_allocator == 0)
1734 wl_display_terminate(ec->base.wl_display);
1735}
1736
1737static int
David Herrmannd7488c22012-03-11 20:05:21 +01001738udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001739{
David Herrmannd7488c22012-03-11 20:05:21 +01001740 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001741 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001742
1743 sysnum = udev_device_get_sysnum(device);
1744 if (!sysnum || atoi(sysnum) != ec->drm.id)
1745 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001746
David Herrmann6ac52db2012-03-11 20:05:22 +01001747 val = udev_device_get_property_value(device, "HOTPLUG");
1748 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001749 return 0;
1750
David Herrmann6ac52db2012-03-11 20:05:22 +01001751 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001752}
1753
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001754static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001755udev_drm_event(int fd, uint32_t mask, void *data)
1756{
1757 struct drm_compositor *ec = data;
1758 struct udev_device *event;
1759
1760 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001761
David Herrmannd7488c22012-03-11 20:05:21 +01001762 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001763 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001764
1765 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001766
1767 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001768}
1769
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001770static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001771drm_restore(struct weston_compositor *ec)
1772{
1773 struct drm_compositor *d = (struct drm_compositor *) ec;
1774
1775 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1776 weston_log("failed to drop master: %m\n");
1777 tty_reset(d->tty);
1778}
1779
Pekka Paalanen33156972012-08-03 13:30:30 -04001780static const char default_seat[] = "seat0";
1781
1782static void
1783device_added(struct udev_device *udev_device, struct drm_seat *master)
1784{
1785 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001786 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001787 const char *devnode;
1788 const char *device_seat;
1789 int fd;
1790
1791 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1792 if (!device_seat)
1793 device_seat = default_seat;
1794
1795 if (strcmp(device_seat, master->seat_id))
1796 return;
1797
1798 c = master->base.compositor;
1799 devnode = udev_device_get_devnode(udev_device);
1800
1801 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001802 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001803 * read. mtdev_get() also expects this. */
1804 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1805 if (fd < 0) {
1806 weston_log("opening input device '%s' failed.\n", devnode);
1807 return;
1808 }
1809
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001810 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001811 if (!device) {
1812 close(fd);
1813 weston_log("not using input device '%s'.\n", devnode);
1814 return;
1815 }
1816
1817 wl_list_insert(master->devices_list.prev, &device->link);
1818}
1819
1820static void
1821evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1822{
1823 struct drm_seat *seat = (struct drm_seat *) seat_base;
1824 struct udev_enumerate *e;
1825 struct udev_list_entry *entry;
1826 struct udev_device *device;
1827 const char *path, *sysname;
1828
1829 e = udev_enumerate_new(udev);
1830 udev_enumerate_add_match_subsystem(e, "input");
1831 udev_enumerate_scan_devices(e);
1832 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1833 path = udev_list_entry_get_name(entry);
1834 device = udev_device_new_from_syspath(udev, path);
1835
1836 sysname = udev_device_get_sysname(device);
1837 if (strncmp("event", sysname, 5) != 0) {
1838 udev_device_unref(device);
1839 continue;
1840 }
1841
1842 device_added(device, seat);
1843
1844 udev_device_unref(device);
1845 }
1846 udev_enumerate_unref(e);
1847
1848 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1849
1850 if (wl_list_empty(&seat->devices_list)) {
1851 weston_log(
1852 "warning: no input devices on entering Weston. "
1853 "Possible causes:\n"
1854 "\t- no permissions to read /dev/input/event*\n"
1855 "\t- seats misconfigured "
1856 "(Weston backend option 'seat', "
1857 "udev device property ID_SEAT)\n");
1858 }
1859}
1860
1861static int
1862evdev_udev_handler(int fd, uint32_t mask, void *data)
1863{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001864 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001865 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001866 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001867 const char *action;
1868 const char *devnode;
1869
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001870 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001871 if (!udev_device)
1872 return 1;
1873
1874 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001875 if (!action)
1876 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001877
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001878 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1879 goto out;
1880
1881 if (!strcmp(action, "add")) {
1882 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001883 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001884 else if (!strcmp(action, "remove")) {
1885 devnode = udev_device_get_devnode(udev_device);
1886 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1887 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001888 weston_log("input device %s, %s removed\n",
1889 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001890 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001891 break;
1892 }
1893 }
1894
1895out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001896 udev_device_unref(udev_device);
1897
1898 return 0;
1899}
1900
1901static int
1902evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1903{
1904 struct drm_seat *master = (struct drm_seat *) seat_base;
1905 struct wl_event_loop *loop;
1906 struct weston_compositor *c = master->base.compositor;
1907 int fd;
1908
1909 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1910 if (!master->udev_monitor) {
1911 weston_log("udev: failed to create the udev monitor\n");
1912 return 0;
1913 }
1914
1915 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1916 "input", NULL);
1917
1918 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1919 weston_log("udev: failed to bind the udev monitor\n");
1920 udev_monitor_unref(master->udev_monitor);
1921 return 0;
1922 }
1923
1924 loop = wl_display_get_event_loop(c->wl_display);
1925 fd = udev_monitor_get_fd(master->udev_monitor);
1926 master->udev_monitor_source =
1927 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1928 evdev_udev_handler, master);
1929 if (!master->udev_monitor_source) {
1930 udev_monitor_unref(master->udev_monitor);
1931 return 0;
1932 }
1933
1934 return 1;
1935}
1936
1937static void
1938evdev_disable_udev_monitor(struct weston_seat *seat_base)
1939{
1940 struct drm_seat *seat = (struct drm_seat *) seat_base;
1941
1942 if (!seat->udev_monitor)
1943 return;
1944
1945 udev_monitor_unref(seat->udev_monitor);
1946 seat->udev_monitor = NULL;
1947 wl_event_source_remove(seat->udev_monitor_source);
1948 seat->udev_monitor_source = NULL;
1949}
1950
1951static void
1952drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1953{
1954 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001955 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001956
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001957 wl_list_for_each(device, &seat->devices_list, link)
1958 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001959}
1960
1961static void
1962evdev_input_create(struct weston_compositor *c, struct udev *udev,
1963 const char *seat_id)
1964{
1965 struct drm_seat *seat;
1966
1967 seat = malloc(sizeof *seat);
1968 if (seat == NULL)
1969 return;
1970
1971 memset(seat, 0, sizeof *seat);
1972 weston_seat_init(&seat->base, c);
1973 seat->base.led_update = drm_led_update;
1974
1975 wl_list_init(&seat->devices_list);
1976 seat->seat_id = strdup(seat_id);
1977 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1978 free(seat->seat_id);
1979 free(seat);
1980 return;
1981 }
1982
1983 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001984}
1985
1986static void
1987evdev_remove_devices(struct weston_seat *seat_base)
1988{
1989 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001990 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001991
1992 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001993 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04001994
Pekka Paalanend8583512012-08-03 14:39:11 +03001995 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04001996 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04001997}
1998
1999static void
2000evdev_input_destroy(struct weston_seat *seat_base)
2001{
2002 struct drm_seat *seat = (struct drm_seat *) seat_base;
2003
2004 evdev_remove_devices(seat_base);
2005 evdev_disable_udev_monitor(&seat->base);
2006
2007 weston_seat_release(seat_base);
2008 free(seat->seat_id);
2009 free(seat);
2010}
2011
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002012static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002013drm_free_configured_output(struct drm_configured_output *output)
2014{
2015 free(output->name);
2016 free(output->mode);
2017 free(output);
2018}
2019
2020static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002021drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002022{
2023 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002024 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002025 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002026
Daniel Stone37816df2012-05-16 18:45:18 +01002027 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2028 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002029 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002030 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002031
2032 wl_event_source_remove(d->udev_drm_source);
2033 wl_event_source_remove(d->drm_source);
2034
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002035 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002036
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002037 gles2_renderer_destroy(ec);
2038
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002039 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002040 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002041 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002042 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002043 eglReleaseThread();
2044
Matt Roper361d2ad2011-08-29 13:52:23 -07002045 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002046 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002047 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002048 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002049 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002050
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002051 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002052}
2053
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002054static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002055drm_compositor_set_modes(struct drm_compositor *compositor)
2056{
2057 struct drm_output *output;
2058 struct drm_mode *drm_mode;
2059 int ret;
2060
2061 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2062 drm_mode = (struct drm_mode *) output->base.current;
2063 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002064 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002065 &output->connector_id, 1,
2066 &drm_mode->mode_info);
2067 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002068 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002069 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002070 drm_mode->base.width, drm_mode->base.height,
2071 output->base.x, output->base.y);
2072 }
2073 }
2074}
2075
2076static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002077vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002078{
2079 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002080 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002081 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002082 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002083
2084 switch (event) {
2085 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002086 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002087 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002088 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002089 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002090 wl_display_terminate(compositor->wl_display);
2091 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002092 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002093 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002094 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002095 wl_list_for_each(seat, &compositor->seat_list, link) {
2096 evdev_add_devices(ec->udev, seat);
2097 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002098 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002099 break;
2100 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002101 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002102 wl_list_for_each(seat, &compositor->seat_list, link) {
2103 evdev_disable_udev_monitor(seat);
2104 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002105 }
2106
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002107 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002108 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002109 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002110
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002111 /* If we have a repaint scheduled (either from a
2112 * pending pageflip or the idle handler), make sure we
2113 * cancel that so we don't try to pageflip when we're
2114 * vt switched away. The SLEEPING state will prevent
2115 * further attemps at repainting. When we switch
2116 * back, we schedule a repaint, which will process
2117 * pending frame callbacks. */
2118
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002119 wl_list_for_each(output, &ec->base.output_list, base.link) {
2120 output->base.repaint_needed = 0;
2121 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002122 }
2123
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002124 output = container_of(ec->base.output_list.next,
2125 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002126
2127 wl_list_for_each(sprite, &ec->sprite_list, link)
2128 drmModeSetPlane(ec->drm.fd,
2129 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002130 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002131 0, 0, 0, 0, 0, 0, 0, 0);
2132
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002133 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002134 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002135
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002136 break;
2137 };
2138}
2139
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002140static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002141switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002142{
2143 struct drm_compositor *ec = data;
2144
Daniel Stone325fc2d2012-05-30 16:31:58 +01002145 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002146}
2147
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002148static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002149drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002150 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002151 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002152{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002153 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002154 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002155 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002156 struct udev_device *device, *drm_device;
2157 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002158 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002159 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002160 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002161
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002162 weston_log("initializing drm backend\n");
2163
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002164 ec = malloc(sizeof *ec);
2165 if (ec == NULL)
2166 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002167 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002168
2169 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002170 config_file) < 0) {
2171 weston_log("weston_compositor_init failed\n");
2172 goto err_base;
2173 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002174
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002175 ec->udev = udev_new();
2176 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002177 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002178 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002179 }
2180
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002181 ec->base.wl_display = display;
2182 ec->tty = tty_create(&ec->base, vt_func, tty);
2183 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002184 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002185 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002186 }
2187
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002188 e = udev_enumerate_new(ec->udev);
2189 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002190 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002191
Benjamin Franzke117483d2011-08-30 11:38:26 +02002192 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002193 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002194 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002195 path = udev_list_entry_get_name(entry);
2196 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002197 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002198 udev_device_get_property_value(device, "ID_SEAT");
2199 if (!device_seat)
2200 device_seat = default_seat;
2201 if (strcmp(device_seat, seat) == 0) {
2202 drm_device = device;
2203 break;
2204 }
2205 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002206 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002207
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002208 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002209 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002210 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002211 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002212
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002213 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002214 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002215 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002216 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002217
2218 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002219 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002220
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002221 ec->base.focus = 1;
2222
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002223 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002224
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002225 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002226 weston_compositor_add_key_binding(&ec->base, key,
2227 MODIFIER_CTRL | MODIFIER_ALT,
2228 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002229
Jesse Barnes58ef3792012-02-23 09:45:49 -05002230 wl_list_init(&ec->sprite_list);
2231 create_sprites(ec);
2232
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002233 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002234 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002235 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002236 }
2237
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002238 if (gles2_renderer_init(&ec->base) < 0)
2239 goto err_egl;
2240
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002241 path = NULL;
2242
Tiago Vignattice03ec32011-12-19 01:14:03 +02002243 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002244
2245 loop = wl_display_get_event_loop(ec->base.wl_display);
2246 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002247 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002248 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002249
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002250 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2251 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002252 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002253 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002254 }
2255 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2256 "drm", NULL);
2257 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002258 wl_event_loop_add_fd(loop,
2259 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002260 WL_EVENT_READABLE, udev_drm_event, ec);
2261
2262 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002263 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002264 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002265 }
2266
Daniel Stonea96b93c2012-06-22 14:04:37 +01002267 udev_device_unref(drm_device);
2268 udev_enumerate_unref(e);
2269
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002270 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002271
2272err_udev_monitor:
2273 wl_event_source_remove(ec->udev_drm_source);
2274 udev_monitor_unref(ec->udev_monitor);
2275err_drm_source:
2276 wl_event_source_remove(ec->drm_source);
2277 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2278 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002279err_egl:
2280 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2281 EGL_NO_CONTEXT);
2282 eglTerminate(ec->base.egl_display);
2283 eglReleaseThread();
2284 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002285err_sprite:
2286 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002287err_udev_dev:
2288 udev_device_unref(drm_device);
2289err_udev_enum:
2290 udev_enumerate_unref(e);
2291 tty_destroy(ec->tty);
2292err_udev:
2293 udev_unref(ec->udev);
2294err_compositor:
2295 weston_compositor_shutdown(&ec->base);
2296err_base:
2297 free(ec);
2298 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002299}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002300
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002301static int
2302set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2303{
2304 mode->flags = 0;
2305
2306 if (strcmp(hsync, "+hsync") == 0)
2307 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2308 else if (strcmp(hsync, "-hsync") == 0)
2309 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2310 else
2311 return -1;
2312
2313 if (strcmp(vsync, "+vsync") == 0)
2314 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2315 else if (strcmp(vsync, "-vsync") == 0)
2316 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2317 else
2318 return -1;
2319
2320 return 0;
2321}
2322
2323static int
2324check_for_modeline(struct drm_configured_output *output)
2325{
2326 drmModeModeInfo mode;
2327 char hsync[16];
2328 char vsync[16];
2329 char mode_name[16];
2330 float fclock;
2331
2332 mode.type = DRM_MODE_TYPE_USERDEF;
2333 mode.hskew = 0;
2334 mode.vscan = 0;
2335 mode.vrefresh = 0;
2336
2337 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2338 &fclock, &mode.hdisplay,
2339 &mode.hsync_start,
2340 &mode.hsync_end, &mode.htotal,
2341 &mode.vdisplay,
2342 &mode.vsync_start,
2343 &mode.vsync_end, &mode.vtotal,
2344 hsync, vsync) == 11) {
2345 if (set_sync_flags(&mode, hsync, vsync))
2346 return -1;
2347
2348 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2349 strcpy(mode.name, mode_name);
2350
2351 mode.clock = fclock * 1000;
2352 } else
2353 return -1;
2354
2355 output->crtc_mode = mode;
2356
2357 return 0;
2358}
2359
Scott Moreau8ab5d452012-07-30 19:51:08 -06002360static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002361drm_output_set_transform(struct drm_configured_output *output)
2362{
2363 if (!output_transform) {
2364 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2365 return;
2366 }
2367
2368 if (!strcmp(output_transform, "normal"))
2369 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2370 else if (!strcmp(output_transform, "90"))
2371 output->transform = WL_OUTPUT_TRANSFORM_90;
2372 else if (!strcmp(output_transform, "180"))
2373 output->transform = WL_OUTPUT_TRANSFORM_180;
2374 else if (!strcmp(output_transform, "270"))
2375 output->transform = WL_OUTPUT_TRANSFORM_270;
2376 else if (!strcmp(output_transform, "flipped"))
2377 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2378 else if (!strcmp(output_transform, "flipped-90"))
2379 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2380 else if (!strcmp(output_transform, "flipped-180"))
2381 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2382 else if (!strcmp(output_transform, "flipped-270"))
2383 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2384 else {
2385 weston_log("Invalid transform \"%s\" for output %s\n",
2386 output_transform, output_name);
2387 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2388 }
2389
2390 free(output_transform);
2391 output_transform = NULL;
2392}
2393
2394static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002395output_section_done(void *data)
2396{
2397 struct drm_configured_output *output;
2398
2399 output = malloc(sizeof *output);
2400
Scott Moreau1bad5db2012-08-18 01:04:05 -06002401 if (!output || !output_name || (output_name[0] == 'X') ||
2402 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002403 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002404 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002405 free(output_transform);
2406 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002407 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002408 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002409 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002410 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002411
2412 output->config = OUTPUT_CONFIG_INVALID;
2413 output->name = output_name;
2414 output->mode = output_mode;
2415
Scott Moreau1bad5db2012-08-18 01:04:05 -06002416 if (output_mode) {
2417 if (strcmp(output_mode, "off") == 0)
2418 output->config = OUTPUT_CONFIG_OFF;
2419 else if (strcmp(output_mode, "preferred") == 0)
2420 output->config = OUTPUT_CONFIG_PREFERRED;
2421 else if (strcmp(output_mode, "current") == 0)
2422 output->config = OUTPUT_CONFIG_CURRENT;
2423 else if (sscanf(output_mode, "%dx%d",
2424 &output->width, &output->height) == 2)
2425 output->config = OUTPUT_CONFIG_MODE;
2426 else if (check_for_modeline(output) == 0)
2427 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002428
Scott Moreau1bad5db2012-08-18 01:04:05 -06002429 if (output->config == OUTPUT_CONFIG_INVALID)
2430 weston_log("Invalid mode \"%s\" for output %s\n",
2431 output_mode, output_name);
2432 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002433 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002434
2435 drm_output_set_transform(output);
2436
2437 wl_list_insert(&configured_output_list, &output->link);
2438
2439 if (output_transform)
2440 free(output_transform);
2441 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002442}
2443
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002444WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002445backend_init(struct wl_display *display, int argc, char *argv[],
2446 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002447{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002448 int connector = 0, tty = 0;
2449 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002450
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002451 const struct weston_option drm_options[] = {
2452 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2453 { WESTON_OPTION_STRING, "seat", 0, &seat },
2454 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002455 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002456 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002457
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002458 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002459
Scott Moreau8ab5d452012-07-30 19:51:08 -06002460 wl_list_init(&configured_output_list);
2461
2462 const struct config_key drm_config_keys[] = {
2463 { "name", CONFIG_KEY_STRING, &output_name },
2464 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002465 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002466 };
2467
2468 const struct config_section config_section[] = {
2469 { "output", drm_config_keys,
2470 ARRAY_LENGTH(drm_config_keys), output_section_done },
2471 };
2472
2473 parse_config_file(config_file, config_section,
2474 ARRAY_LENGTH(config_section), NULL);
2475
Daniel Stonec1be8e52012-06-01 11:14:02 -04002476 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2477 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002478}