blob: d3101942f23adb0f8a66922c40af94aa6d214957 [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øgsberg2c28aa52010-07-28 23:47:54 -04001046 static const EGLint context_attribs[] = {
1047 EGL_CONTEXT_CLIENT_VERSION, 2,
1048 EGL_NONE
1049 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001050
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001051 static const EGLint config_attribs[] = {
1052 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1053 EGL_RED_SIZE, 1,
1054 EGL_GREEN_SIZE, 1,
1055 EGL_BLUE_SIZE, 1,
1056 EGL_ALPHA_SIZE, 0,
1057 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1058 EGL_NONE
1059 };
1060
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001061 sysnum = udev_device_get_sysnum(device);
1062 if (sysnum)
1063 ec->drm.id = atoi(sysnum);
1064 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001065 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001066 return -1;
1067 }
1068
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001069 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001070 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001071 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001072 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001073 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001074 udev_device_get_devnode(device));
1075 return -1;
1076 }
1077
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001078 weston_log("using %s\n", filename);
1079
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001080 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001081 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001082 ec->base.egl_display = eglGetDisplay(ec->gbm);
1083 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001084 weston_log("failed to create 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 (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001089 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001090 return -1;
1091 }
1092
Darxus55973f22010-11-22 21:24:39 -05001093 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001094 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001095 return -1;
1096 }
1097
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001098 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1099 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001100 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001101 return -1;
1102 }
1103
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001104 ec->base.egl_context =
1105 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1106 EGL_NO_CONTEXT, context_attribs);
1107 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001108 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001109 return -1;
1110 }
1111
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001112 return 0;
1113}
1114
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001115static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001116drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1117{
1118 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001119 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001120
1121 mode = malloc(sizeof *mode);
1122 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001123 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001124
1125 mode->base.flags = 0;
1126 mode->base.width = info->hdisplay;
1127 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001128
1129 /* Calculate higher precision (mHz) refresh rate */
1130 refresh = (info->clock * 1000000LL / info->htotal +
1131 info->vtotal / 2) / info->vtotal;
1132
1133 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1134 refresh *= 2;
1135 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1136 refresh /= 2;
1137 if (info->vscan > 1)
1138 refresh /= info->vscan;
1139
1140 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001141 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001142
1143 if (info->type & DRM_MODE_TYPE_PREFERRED)
1144 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1145
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001146 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1147
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001148 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001149}
1150
1151static int
1152drm_subpixel_to_wayland(int drm_value)
1153{
1154 switch (drm_value) {
1155 default:
1156 case DRM_MODE_SUBPIXEL_UNKNOWN:
1157 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1158 case DRM_MODE_SUBPIXEL_NONE:
1159 return WL_OUTPUT_SUBPIXEL_NONE;
1160 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1161 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1162 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1163 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1164 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1165 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1166 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1167 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1168 }
1169}
1170
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001171static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001172sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001173{
1174 struct drm_sprite *sprite =
1175 container_of(listener, struct drm_sprite,
1176 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001177 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001178
1179 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001180 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1181 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001182}
1183
1184static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001185sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001186{
1187 struct drm_sprite *sprite =
1188 container_of(listener, struct drm_sprite,
1189 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001190 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001191
1192 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001193 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1194 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001195}
1196
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001197/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001198static uint32_t
1199drm_get_backlight(struct drm_output *output)
1200{
1201 long brightness, max_brightness, norm;
1202
1203 brightness = backlight_get_brightness(output->backlight);
1204 max_brightness = backlight_get_max_brightness(output->backlight);
1205
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001206 /* convert it on a scale of 0 to 255 */
1207 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001208
1209 return (uint32_t) norm;
1210}
1211
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001212/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001213static void
1214drm_set_backlight(struct weston_output *output_base, uint32_t value)
1215{
1216 struct drm_output *output = (struct drm_output *) output_base;
1217 long max_brightness, new_brightness;
1218
1219 if (!output->backlight)
1220 return;
1221
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001222 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001223 return;
1224
1225 max_brightness = backlight_get_max_brightness(output->backlight);
1226
1227 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001228 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001229
1230 backlight_set_brightness(output->backlight, new_brightness);
1231}
1232
1233static drmModePropertyPtr
1234drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1235{
1236 drmModePropertyPtr props;
1237 int i;
1238
1239 for (i = 0; i < connector->count_props; i++) {
1240 props = drmModeGetProperty(fd, connector->props[i]);
1241 if (!props)
1242 continue;
1243
1244 if (!strcmp(props->name, name))
1245 return props;
1246
1247 drmModeFreeProperty(props);
1248 }
1249
1250 return NULL;
1251}
1252
1253static void
1254drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1255{
1256 struct drm_output *output = (struct drm_output *) output_base;
1257 struct weston_compositor *ec = output_base->compositor;
1258 struct drm_compositor *c = (struct drm_compositor *) ec;
1259 drmModeConnectorPtr connector;
1260 drmModePropertyPtr prop;
1261
1262 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1263 if (!connector)
1264 return;
1265
1266 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1267 if (!prop) {
1268 drmModeFreeConnector(connector);
1269 return;
1270 }
1271
1272 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1273 prop->prop_id, level);
1274 drmModeFreeProperty(prop);
1275 drmModeFreeConnector(connector);
1276}
1277
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001278static const char *connector_type_names[] = {
1279 "None",
1280 "VGA",
1281 "DVI",
1282 "DVI",
1283 "DVI",
1284 "Composite",
1285 "TV",
1286 "LVDS",
1287 "CTV",
1288 "DIN",
1289 "DP",
1290 "HDMI",
1291 "HDMI",
1292 "TV",
1293 "eDP",
1294};
1295
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001296static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001297find_crtc_for_connector(struct drm_compositor *ec,
1298 drmModeRes *resources, drmModeConnector *connector)
1299{
1300 drmModeEncoder *encoder;
1301 uint32_t possible_crtcs;
1302 int i, j;
1303
1304 for (j = 0; j < connector->count_encoders; j++) {
1305 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1306 if (encoder == NULL) {
1307 weston_log("Failed to get encoder.\n");
1308 return -1;
1309 }
1310 possible_crtcs = encoder->possible_crtcs;
1311 drmModeFreeEncoder(encoder);
1312
1313 for (i = 0; i < resources->count_crtcs; i++) {
1314 if (possible_crtcs & (1 << i) &&
1315 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1316 return i;
1317 }
1318 }
1319
1320 return -1;
1321}
1322
1323static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001324create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001325 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001326 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001327 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001328{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001329 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001330 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1331 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001332 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001333 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001334 drmModeModeInfo crtc_mode;
1335 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001336 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001337 char name[32];
1338 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001339
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001340 i = find_crtc_for_connector(ec, resources, connector);
1341 if (i < 0) {
1342 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001343 return -1;
1344 }
1345
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001346 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001347 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001348 return -1;
1349
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001350 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001351 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1352 output->base.make = "unknown";
1353 output->base.model = "unknown";
1354 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001355
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001356 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1357 type_name = connector_type_names[connector->connector_type];
1358 else
1359 type_name = "UNKNOWN";
1360 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1361 output->name = strdup(name);
1362
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001363 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001364 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001365 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001366 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001367 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001368
Matt Roper361d2ad2011-08-29 13:52:23 -07001369 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1370
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001371 /* Get the current mode on the crtc that's currently driving
1372 * this connector. */
1373 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001374 memset(&crtc_mode, 0, sizeof crtc_mode);
1375 if (encoder != NULL) {
1376 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1377 drmModeFreeEncoder(encoder);
1378 if (crtc == NULL)
1379 goto err_free;
1380 if (crtc->mode_valid)
1381 crtc_mode = crtc->mode;
1382 drmModeFreeCrtc(crtc);
1383 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001384
David Herrmann0f0d54e2011-12-08 17:05:45 +01001385 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001386 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1387 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001388 goto err_free;
1389 }
1390
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001391 preferred = NULL;
1392 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001393 configured = NULL;
1394
1395 wl_list_for_each(temp, &configured_output_list, link) {
1396 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001397 if (temp->mode)
1398 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001399 temp->name, temp->mode);
1400 o = temp;
1401 break;
1402 }
1403 }
1404
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001405 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001406 weston_log("Disabling output %s\n", o->name);
1407
1408 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1409 0, 0, 0, 0, 0, NULL);
1410 goto err_free;
1411 }
1412
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001413 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001414 if (o && o->config == OUTPUT_CONFIG_MODE &&
1415 o->width == drm_mode->base.width &&
1416 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001417 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001418 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001419 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001420 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001421 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001422 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001423
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001424 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001425 configured = drm_output_add_mode(output, &o->crtc_mode);
1426 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001427 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001428 current = configured;
1429 }
1430
Wang Quanxianacb805a2012-07-30 18:09:46 -04001431 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001432 current = drm_output_add_mode(output, &crtc_mode);
1433 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001434 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001435 }
1436
Scott Moreau8ab5d452012-07-30 19:51:08 -06001437 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1438 configured = current;
1439
Wang Quanxianacb805a2012-07-30 18:09:46 -04001440 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001441 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001442 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001443 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001444 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001445 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001446 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001447 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001448
1449 if (output->base.current == NULL) {
1450 weston_log("no available modes for %s\n", output->name);
1451 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001452 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001453
Wang Quanxianacb805a2012-07-30 18:09:46 -04001454 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1455
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001456 output->surface = gbm_surface_create(ec->gbm,
1457 output->base.current->width,
1458 output->base.current->height,
1459 GBM_FORMAT_XRGB8888,
1460 GBM_BO_USE_SCANOUT |
1461 GBM_BO_USE_RENDERING);
1462 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001463 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001464 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001465 }
1466
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001467 output->base.egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001468 eglCreateWindowSurface(ec->base.egl_display,
1469 ec->base.egl_config,
1470 output->surface,
1471 NULL);
Kristian Høgsbergd7c17262012-09-05 21:54:15 -04001472 if (output->base.egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001473 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001474 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001475 }
1476
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001477 output->cursor_bo[0] =
1478 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1479 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1480 output->cursor_bo[1] =
1481 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1482 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1483
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001484 output->backlight = backlight_init(drm_device,
1485 connector->connector_type);
1486 if (output->backlight) {
1487 output->base.set_backlight = drm_set_backlight;
1488 output->base.backlight_current = drm_get_backlight(output);
1489 }
1490
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001491 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001492 connector->mmWidth, connector->mmHeight,
1493 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001494
1495 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1496
Alex Wubd3354b2012-04-17 17:20:49 +08001497 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001498 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001499 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001500 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001501 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001502 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001503
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001504 weston_plane_init(&output->cursor_plane, 0, 0);
1505 weston_plane_init(&output->fb_plane, 0, 0);
1506
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001507 weston_log("Output %s, (connector %d, crtc %d)\n",
1508 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001509 wl_list_for_each(m, &output->base.mode_list, link)
1510 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1511 m->width, m->height, m->refresh / 1000.0,
1512 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1513 ", preferred" : "",
1514 m->flags & WL_OUTPUT_MODE_CURRENT ?
1515 ", current" : "",
1516 connector->count_modes == 0 ?
1517 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001518
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001519 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001520
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001521err_surface:
1522 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001523err_free:
1524 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1525 base.link) {
1526 wl_list_remove(&drm_mode->base.link);
1527 free(drm_mode);
1528 }
1529
1530 drmModeFreeCrtc(output->original_crtc);
1531 ec->crtc_allocator &= ~(1 << output->crtc_id);
1532 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001533 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001534 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001535
David Herrmann0f0d54e2011-12-08 17:05:45 +01001536 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001537}
1538
Jesse Barnes58ef3792012-02-23 09:45:49 -05001539static void
1540create_sprites(struct drm_compositor *ec)
1541{
1542 struct drm_sprite *sprite;
1543 drmModePlaneRes *plane_res;
1544 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001545 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001546
1547 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1548 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001549 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001550 strerror(errno));
1551 return;
1552 }
1553
1554 for (i = 0; i < plane_res->count_planes; i++) {
1555 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1556 if (!plane)
1557 continue;
1558
1559 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1560 plane->count_formats));
1561 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001562 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001563 __func__);
1564 free(plane);
1565 continue;
1566 }
1567
1568 memset(sprite, 0, sizeof *sprite);
1569
1570 sprite->possible_crtcs = plane->possible_crtcs;
1571 sprite->plane_id = plane->plane_id;
1572 sprite->surface = NULL;
1573 sprite->pending_surface = NULL;
1574 sprite->fb_id = 0;
1575 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001576 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1577 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001578 sprite_handle_pending_buffer_destroy;
1579 sprite->compositor = ec;
1580 sprite->count_formats = plane->count_formats;
1581 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001582 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001583 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001584 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001585
1586 wl_list_insert(&ec->sprite_list, &sprite->link);
1587 }
1588
1589 free(plane_res->planes);
1590 free(plane_res);
1591}
1592
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001593static void
1594destroy_sprites(struct drm_compositor *compositor)
1595{
1596 struct drm_sprite *sprite, *next;
1597 struct drm_output *output;
1598
1599 output = container_of(compositor->base.output_list.next,
1600 struct drm_output, base.link);
1601
1602 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1603 drmModeSetPlane(compositor->drm.fd,
1604 sprite->plane_id,
1605 output->crtc_id, 0, 0,
1606 0, 0, 0, 0, 0, 0, 0, 0);
1607 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001608 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001609 free(sprite);
1610 }
1611}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001612
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001613static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001614create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001615 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001616{
1617 drmModeConnector *connector;
1618 drmModeRes *resources;
1619 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001620 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001621
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001622 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001623 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001624 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001625 return -1;
1626 }
1627
Jesse Barnes58ef3792012-02-23 09:45:49 -05001628 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001629 if (!ec->crtcs) {
1630 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001631 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001632 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001633
Rob Clark4339add2012-08-09 14:18:28 -05001634 ec->min_width = resources->min_width;
1635 ec->max_width = resources->max_width;
1636 ec->min_height = resources->min_height;
1637 ec->max_height = resources->max_height;
1638
Jesse Barnes58ef3792012-02-23 09:45:49 -05001639 ec->num_crtcs = resources->count_crtcs;
1640 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1641
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001642 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001643 connector = drmModeGetConnector(ec->drm.fd,
1644 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001645 if (connector == NULL)
1646 continue;
1647
1648 if (connector->connection == DRM_MODE_CONNECTED &&
1649 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001650 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001651 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001652 connector, x, y,
1653 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001654 drmModeFreeConnector(connector);
1655 continue;
1656 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001657
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001658 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001659 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001660 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001661 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001662
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001663 drmModeFreeConnector(connector);
1664 }
1665
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001666 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001667 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001668 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001669 return -1;
1670 }
1671
1672 drmModeFreeResources(resources);
1673
1674 return 0;
1675}
1676
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001677static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001678update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001679{
1680 drmModeConnector *connector;
1681 drmModeRes *resources;
1682 struct drm_output *output, *next;
1683 int x = 0, y = 0;
1684 int x_offset = 0, y_offset = 0;
1685 uint32_t connected = 0, disconnects = 0;
1686 int i;
1687
1688 resources = drmModeGetResources(ec->drm.fd);
1689 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001690 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001691 return;
1692 }
1693
1694 /* collect new connects */
1695 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001696 int connector_id = resources->connectors[i];
1697
1698 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001699 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001700 continue;
1701
David Herrmann7551cff2011-12-08 17:05:43 +01001702 if (connector->connection != DRM_MODE_CONNECTED) {
1703 drmModeFreeConnector(connector);
1704 continue;
1705 }
1706
Benjamin Franzke117483d2011-08-30 11:38:26 +02001707 connected |= (1 << connector_id);
1708
1709 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001710 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001711 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001712 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001713
1714 /* XXX: not yet needed, we die with 0 outputs */
1715 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001716 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001717 else
1718 x = 0;
1719 y = 0;
1720 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001721 connector, x, y,
1722 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001723 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001724
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001725 }
1726 drmModeFreeConnector(connector);
1727 }
1728 drmModeFreeResources(resources);
1729
1730 disconnects = ec->connector_allocator & ~connected;
1731 if (disconnects) {
1732 wl_list_for_each_safe(output, next, &ec->base.output_list,
1733 base.link) {
1734 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001735 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001736 output->base.x - x_offset,
1737 output->base.y - y_offset);
1738 }
1739
1740 if (disconnects & (1 << output->connector_id)) {
1741 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001742 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001743 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001744 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001745 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001746 }
1747 }
1748 }
1749
1750 /* FIXME: handle zero outputs, without terminating */
1751 if (ec->connector_allocator == 0)
1752 wl_display_terminate(ec->base.wl_display);
1753}
1754
1755static int
David Herrmannd7488c22012-03-11 20:05:21 +01001756udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001757{
David Herrmannd7488c22012-03-11 20:05:21 +01001758 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001759 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001760
1761 sysnum = udev_device_get_sysnum(device);
1762 if (!sysnum || atoi(sysnum) != ec->drm.id)
1763 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001764
David Herrmann6ac52db2012-03-11 20:05:22 +01001765 val = udev_device_get_property_value(device, "HOTPLUG");
1766 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001767 return 0;
1768
David Herrmann6ac52db2012-03-11 20:05:22 +01001769 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001770}
1771
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001772static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001773udev_drm_event(int fd, uint32_t mask, void *data)
1774{
1775 struct drm_compositor *ec = data;
1776 struct udev_device *event;
1777
1778 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001779
David Herrmannd7488c22012-03-11 20:05:21 +01001780 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001781 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001782
1783 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001784
1785 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001786}
1787
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001788static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001789drm_restore(struct weston_compositor *ec)
1790{
1791 struct drm_compositor *d = (struct drm_compositor *) ec;
1792
1793 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1794 weston_log("failed to drop master: %m\n");
1795 tty_reset(d->tty);
1796}
1797
Pekka Paalanen33156972012-08-03 13:30:30 -04001798static const char default_seat[] = "seat0";
1799
1800static void
1801device_added(struct udev_device *udev_device, struct drm_seat *master)
1802{
1803 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001804 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001805 const char *devnode;
1806 const char *device_seat;
1807 int fd;
1808
1809 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1810 if (!device_seat)
1811 device_seat = default_seat;
1812
1813 if (strcmp(device_seat, master->seat_id))
1814 return;
1815
1816 c = master->base.compositor;
1817 devnode = udev_device_get_devnode(udev_device);
1818
1819 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001820 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001821 * read. mtdev_get() also expects this. */
1822 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1823 if (fd < 0) {
1824 weston_log("opening input device '%s' failed.\n", devnode);
1825 return;
1826 }
1827
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001828 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001829 if (!device) {
1830 close(fd);
1831 weston_log("not using input device '%s'.\n", devnode);
1832 return;
1833 }
1834
1835 wl_list_insert(master->devices_list.prev, &device->link);
1836}
1837
1838static void
1839evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1840{
1841 struct drm_seat *seat = (struct drm_seat *) seat_base;
1842 struct udev_enumerate *e;
1843 struct udev_list_entry *entry;
1844 struct udev_device *device;
1845 const char *path, *sysname;
1846
1847 e = udev_enumerate_new(udev);
1848 udev_enumerate_add_match_subsystem(e, "input");
1849 udev_enumerate_scan_devices(e);
1850 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1851 path = udev_list_entry_get_name(entry);
1852 device = udev_device_new_from_syspath(udev, path);
1853
1854 sysname = udev_device_get_sysname(device);
1855 if (strncmp("event", sysname, 5) != 0) {
1856 udev_device_unref(device);
1857 continue;
1858 }
1859
1860 device_added(device, seat);
1861
1862 udev_device_unref(device);
1863 }
1864 udev_enumerate_unref(e);
1865
1866 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1867
1868 if (wl_list_empty(&seat->devices_list)) {
1869 weston_log(
1870 "warning: no input devices on entering Weston. "
1871 "Possible causes:\n"
1872 "\t- no permissions to read /dev/input/event*\n"
1873 "\t- seats misconfigured "
1874 "(Weston backend option 'seat', "
1875 "udev device property ID_SEAT)\n");
1876 }
1877}
1878
1879static int
1880evdev_udev_handler(int fd, uint32_t mask, void *data)
1881{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001882 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001883 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001884 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001885 const char *action;
1886 const char *devnode;
1887
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001888 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001889 if (!udev_device)
1890 return 1;
1891
1892 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001893 if (!action)
1894 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001895
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001896 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1897 goto out;
1898
1899 if (!strcmp(action, "add")) {
1900 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001901 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001902 else if (!strcmp(action, "remove")) {
1903 devnode = udev_device_get_devnode(udev_device);
1904 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1905 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001906 weston_log("input device %s, %s removed\n",
1907 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001908 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001909 break;
1910 }
1911 }
1912
1913out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001914 udev_device_unref(udev_device);
1915
1916 return 0;
1917}
1918
1919static int
1920evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1921{
1922 struct drm_seat *master = (struct drm_seat *) seat_base;
1923 struct wl_event_loop *loop;
1924 struct weston_compositor *c = master->base.compositor;
1925 int fd;
1926
1927 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1928 if (!master->udev_monitor) {
1929 weston_log("udev: failed to create the udev monitor\n");
1930 return 0;
1931 }
1932
1933 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1934 "input", NULL);
1935
1936 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1937 weston_log("udev: failed to bind the udev monitor\n");
1938 udev_monitor_unref(master->udev_monitor);
1939 return 0;
1940 }
1941
1942 loop = wl_display_get_event_loop(c->wl_display);
1943 fd = udev_monitor_get_fd(master->udev_monitor);
1944 master->udev_monitor_source =
1945 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1946 evdev_udev_handler, master);
1947 if (!master->udev_monitor_source) {
1948 udev_monitor_unref(master->udev_monitor);
1949 return 0;
1950 }
1951
1952 return 1;
1953}
1954
1955static void
1956evdev_disable_udev_monitor(struct weston_seat *seat_base)
1957{
1958 struct drm_seat *seat = (struct drm_seat *) seat_base;
1959
1960 if (!seat->udev_monitor)
1961 return;
1962
1963 udev_monitor_unref(seat->udev_monitor);
1964 seat->udev_monitor = NULL;
1965 wl_event_source_remove(seat->udev_monitor_source);
1966 seat->udev_monitor_source = NULL;
1967}
1968
1969static void
1970drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
1971{
1972 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001973 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001974
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03001975 wl_list_for_each(device, &seat->devices_list, link)
1976 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04001977}
1978
1979static void
1980evdev_input_create(struct weston_compositor *c, struct udev *udev,
1981 const char *seat_id)
1982{
1983 struct drm_seat *seat;
1984
1985 seat = malloc(sizeof *seat);
1986 if (seat == NULL)
1987 return;
1988
1989 memset(seat, 0, sizeof *seat);
1990 weston_seat_init(&seat->base, c);
1991 seat->base.led_update = drm_led_update;
1992
1993 wl_list_init(&seat->devices_list);
1994 seat->seat_id = strdup(seat_id);
1995 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
1996 free(seat->seat_id);
1997 free(seat);
1998 return;
1999 }
2000
2001 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002002}
2003
2004static void
2005evdev_remove_devices(struct weston_seat *seat_base)
2006{
2007 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002008 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002009
2010 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002011 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002012
Pekka Paalanend8583512012-08-03 14:39:11 +03002013 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002014 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002015}
2016
2017static void
2018evdev_input_destroy(struct weston_seat *seat_base)
2019{
2020 struct drm_seat *seat = (struct drm_seat *) seat_base;
2021
2022 evdev_remove_devices(seat_base);
2023 evdev_disable_udev_monitor(&seat->base);
2024
2025 weston_seat_release(seat_base);
2026 free(seat->seat_id);
2027 free(seat);
2028}
2029
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002030static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002031drm_free_configured_output(struct drm_configured_output *output)
2032{
2033 free(output->name);
2034 free(output->mode);
2035 free(output);
2036}
2037
2038static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002039drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002040{
2041 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002042 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002043 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002044
Daniel Stone37816df2012-05-16 18:45:18 +01002045 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2046 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002047 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002048 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002049
2050 wl_event_source_remove(d->udev_drm_source);
2051 wl_event_source_remove(d->drm_source);
2052
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002053 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002054
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002055 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002056 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002057 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002058 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002059 eglReleaseThread();
2060
Matt Roper361d2ad2011-08-29 13:52:23 -07002061 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002062 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002063 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002064 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002065 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002066
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002067 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002068}
2069
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002070static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002071drm_compositor_set_modes(struct drm_compositor *compositor)
2072{
2073 struct drm_output *output;
2074 struct drm_mode *drm_mode;
2075 int ret;
2076
2077 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2078 drm_mode = (struct drm_mode *) output->base.current;
2079 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002080 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002081 &output->connector_id, 1,
2082 &drm_mode->mode_info);
2083 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002084 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002085 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002086 drm_mode->base.width, drm_mode->base.height,
2087 output->base.x, output->base.y);
2088 }
2089 }
2090}
2091
2092static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002093vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002094{
2095 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002096 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002097 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002098 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002099
2100 switch (event) {
2101 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002102 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002103 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002104 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002105 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002106 wl_display_terminate(compositor->wl_display);
2107 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002108 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002109 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002110 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002111 wl_list_for_each(seat, &compositor->seat_list, link) {
2112 evdev_add_devices(ec->udev, seat);
2113 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002114 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002115 break;
2116 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002117 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002118 wl_list_for_each(seat, &compositor->seat_list, link) {
2119 evdev_disable_udev_monitor(seat);
2120 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002121 }
2122
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002123 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002124 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002125 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002126
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002127 /* If we have a repaint scheduled (either from a
2128 * pending pageflip or the idle handler), make sure we
2129 * cancel that so we don't try to pageflip when we're
2130 * vt switched away. The SLEEPING state will prevent
2131 * further attemps at repainting. When we switch
2132 * back, we schedule a repaint, which will process
2133 * pending frame callbacks. */
2134
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002135 wl_list_for_each(output, &ec->base.output_list, base.link) {
2136 output->base.repaint_needed = 0;
2137 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002138 }
2139
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002140 output = container_of(ec->base.output_list.next,
2141 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002142
2143 wl_list_for_each(sprite, &ec->sprite_list, link)
2144 drmModeSetPlane(ec->drm.fd,
2145 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002146 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002147 0, 0, 0, 0, 0, 0, 0, 0);
2148
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002149 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002150 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002151
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002152 break;
2153 };
2154}
2155
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002156static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002157switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002158{
2159 struct drm_compositor *ec = data;
2160
Daniel Stone325fc2d2012-05-30 16:31:58 +01002161 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002162}
2163
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002164static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002165drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002166 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002167 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002168{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002169 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002170 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002171 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002172 struct udev_device *device, *drm_device;
2173 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002174 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002175 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002176 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002177
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002178 weston_log("initializing drm backend\n");
2179
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002180 ec = malloc(sizeof *ec);
2181 if (ec == NULL)
2182 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002183 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002184
2185 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002186 config_file) < 0) {
2187 weston_log("weston_compositor_init failed\n");
2188 goto err_base;
2189 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002190
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002191 ec->udev = udev_new();
2192 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002193 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002194 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002195 }
2196
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002197 ec->base.wl_display = display;
2198 ec->tty = tty_create(&ec->base, vt_func, tty);
2199 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002200 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002201 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002202 }
2203
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204 e = udev_enumerate_new(ec->udev);
2205 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002206 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002207
Benjamin Franzke117483d2011-08-30 11:38:26 +02002208 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002209 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002210 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002211 path = udev_list_entry_get_name(entry);
2212 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002213 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002214 udev_device_get_property_value(device, "ID_SEAT");
2215 if (!device_seat)
2216 device_seat = default_seat;
2217 if (strcmp(device_seat, seat) == 0) {
2218 drm_device = device;
2219 break;
2220 }
2221 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002222 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002223
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002224 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002225 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002226 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002227 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002228
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002229 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002230 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002231 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002232 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002233
2234 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002235 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002236
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002237 ec->base.focus = 1;
2238
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002239 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002240
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002241 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002242 weston_compositor_add_key_binding(&ec->base, key,
2243 MODIFIER_CTRL | MODIFIER_ALT,
2244 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002245
Jesse Barnes58ef3792012-02-23 09:45:49 -05002246 wl_list_init(&ec->sprite_list);
2247 create_sprites(ec);
2248
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002249 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002250 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002251 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002252 }
2253
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002254 if (gles2_renderer_init(&ec->base) < 0)
2255 goto err_egl;
2256
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002257 path = NULL;
2258
Tiago Vignattice03ec32011-12-19 01:14:03 +02002259 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002260
2261 loop = wl_display_get_event_loop(ec->base.wl_display);
2262 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002263 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002264 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002265
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002266 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2267 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002268 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002269 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002270 }
2271 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2272 "drm", NULL);
2273 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002274 wl_event_loop_add_fd(loop,
2275 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002276 WL_EVENT_READABLE, udev_drm_event, ec);
2277
2278 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002279 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002280 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002281 }
2282
Daniel Stonea96b93c2012-06-22 14:04:37 +01002283 udev_device_unref(drm_device);
2284 udev_enumerate_unref(e);
2285
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002286 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002287
2288err_udev_monitor:
2289 wl_event_source_remove(ec->udev_drm_source);
2290 udev_monitor_unref(ec->udev_monitor);
2291err_drm_source:
2292 wl_event_source_remove(ec->drm_source);
2293 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2294 evdev_input_destroy(weston_seat);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002295err_egl:
2296 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2297 EGL_NO_CONTEXT);
2298 eglTerminate(ec->base.egl_display);
2299 eglReleaseThread();
2300 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002301err_sprite:
2302 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002303err_udev_dev:
2304 udev_device_unref(drm_device);
2305err_udev_enum:
2306 udev_enumerate_unref(e);
2307 tty_destroy(ec->tty);
2308err_udev:
2309 udev_unref(ec->udev);
2310err_compositor:
2311 weston_compositor_shutdown(&ec->base);
2312err_base:
2313 free(ec);
2314 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002315}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002316
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002317static int
2318set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2319{
2320 mode->flags = 0;
2321
2322 if (strcmp(hsync, "+hsync") == 0)
2323 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2324 else if (strcmp(hsync, "-hsync") == 0)
2325 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2326 else
2327 return -1;
2328
2329 if (strcmp(vsync, "+vsync") == 0)
2330 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2331 else if (strcmp(vsync, "-vsync") == 0)
2332 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2333 else
2334 return -1;
2335
2336 return 0;
2337}
2338
2339static int
2340check_for_modeline(struct drm_configured_output *output)
2341{
2342 drmModeModeInfo mode;
2343 char hsync[16];
2344 char vsync[16];
2345 char mode_name[16];
2346 float fclock;
2347
2348 mode.type = DRM_MODE_TYPE_USERDEF;
2349 mode.hskew = 0;
2350 mode.vscan = 0;
2351 mode.vrefresh = 0;
2352
2353 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2354 &fclock, &mode.hdisplay,
2355 &mode.hsync_start,
2356 &mode.hsync_end, &mode.htotal,
2357 &mode.vdisplay,
2358 &mode.vsync_start,
2359 &mode.vsync_end, &mode.vtotal,
2360 hsync, vsync) == 11) {
2361 if (set_sync_flags(&mode, hsync, vsync))
2362 return -1;
2363
2364 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2365 strcpy(mode.name, mode_name);
2366
2367 mode.clock = fclock * 1000;
2368 } else
2369 return -1;
2370
2371 output->crtc_mode = mode;
2372
2373 return 0;
2374}
2375
Scott Moreau8ab5d452012-07-30 19:51:08 -06002376static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002377drm_output_set_transform(struct drm_configured_output *output)
2378{
2379 if (!output_transform) {
2380 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2381 return;
2382 }
2383
2384 if (!strcmp(output_transform, "normal"))
2385 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2386 else if (!strcmp(output_transform, "90"))
2387 output->transform = WL_OUTPUT_TRANSFORM_90;
2388 else if (!strcmp(output_transform, "180"))
2389 output->transform = WL_OUTPUT_TRANSFORM_180;
2390 else if (!strcmp(output_transform, "270"))
2391 output->transform = WL_OUTPUT_TRANSFORM_270;
2392 else if (!strcmp(output_transform, "flipped"))
2393 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2394 else if (!strcmp(output_transform, "flipped-90"))
2395 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2396 else if (!strcmp(output_transform, "flipped-180"))
2397 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2398 else if (!strcmp(output_transform, "flipped-270"))
2399 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2400 else {
2401 weston_log("Invalid transform \"%s\" for output %s\n",
2402 output_transform, output_name);
2403 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2404 }
2405
2406 free(output_transform);
2407 output_transform = NULL;
2408}
2409
2410static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002411output_section_done(void *data)
2412{
2413 struct drm_configured_output *output;
2414
2415 output = malloc(sizeof *output);
2416
Scott Moreau1bad5db2012-08-18 01:04:05 -06002417 if (!output || !output_name || (output_name[0] == 'X') ||
2418 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002419 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002420 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002421 free(output_transform);
2422 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002423 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002424 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002425 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002426 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002427
2428 output->config = OUTPUT_CONFIG_INVALID;
2429 output->name = output_name;
2430 output->mode = output_mode;
2431
Scott Moreau1bad5db2012-08-18 01:04:05 -06002432 if (output_mode) {
2433 if (strcmp(output_mode, "off") == 0)
2434 output->config = OUTPUT_CONFIG_OFF;
2435 else if (strcmp(output_mode, "preferred") == 0)
2436 output->config = OUTPUT_CONFIG_PREFERRED;
2437 else if (strcmp(output_mode, "current") == 0)
2438 output->config = OUTPUT_CONFIG_CURRENT;
2439 else if (sscanf(output_mode, "%dx%d",
2440 &output->width, &output->height) == 2)
2441 output->config = OUTPUT_CONFIG_MODE;
2442 else if (check_for_modeline(output) == 0)
2443 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002444
Scott Moreau1bad5db2012-08-18 01:04:05 -06002445 if (output->config == OUTPUT_CONFIG_INVALID)
2446 weston_log("Invalid mode \"%s\" for output %s\n",
2447 output_mode, output_name);
2448 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002449 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002450
2451 drm_output_set_transform(output);
2452
2453 wl_list_insert(&configured_output_list, &output->link);
2454
2455 if (output_transform)
2456 free(output_transform);
2457 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002458}
2459
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002460WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002461backend_init(struct wl_display *display, int argc, char *argv[],
2462 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002463{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002464 int connector = 0, tty = 0;
2465 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002466
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002467 const struct weston_option drm_options[] = {
2468 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2469 { WESTON_OPTION_STRING, "seat", 0, &seat },
2470 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002471 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002472 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002473
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002474 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002475
Scott Moreau8ab5d452012-07-30 19:51:08 -06002476 wl_list_init(&configured_output_list);
2477
2478 const struct config_key drm_config_keys[] = {
2479 { "name", CONFIG_KEY_STRING, &output_name },
2480 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002481 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002482 };
2483
2484 const struct config_section config_section[] = {
2485 { "output", drm_config_keys,
2486 ARRAY_LENGTH(drm_config_keys), output_section_done },
2487 };
2488
2489 parse_config_file(config_file, config_section,
2490 ARRAY_LENGTH(config_section), NULL);
2491
Daniel Stonec1be8e52012-06-01 11:14:02 -04002492 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2493 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002494}