blob: c6634a0b0079c75d8bb2bc004f928862028ef7f6 [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
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -040091 struct gbm_surface *dummy_surface;
92 EGLSurface dummy_egl_surface;
93
Rob Clark4339add2012-08-09 14:18:28 -050094 /* we need these parameters in order to not fail drmModeAddFB2()
95 * due to out of bounds dimensions, and then mistakenly set
96 * sprites_are_broken:
97 */
Kristian Høgsberg8a015802012-08-09 17:19:23 -040098 int32_t min_width, max_width;
99 int32_t min_height, max_height;
Rob Clark4339add2012-08-09 14:18:28 -0500100
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500102 int sprites_are_broken;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500103
Rob Clarkab5b1e32012-08-09 13:24:45 -0500104 int cursors_are_broken;
105
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400107};
108
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400109struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500110 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400111 drmModeModeInfo mode_info;
112};
113
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300114struct drm_output;
115
116struct drm_fb {
117 struct gbm_bo *bo;
118 struct drm_output *output;
119 uint32_t fb_id;
120 int is_client_buffer;
121 struct wl_buffer *buffer;
122 struct wl_listener buffer_destroy_listener;
123};
124
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400125struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500126 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400127
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -0400128 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400129 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500130 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400131 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700132 drmModeCrtcPtr original_crtc;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200133
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300134 int vblank_pending;
135 int page_flip_pending;
136
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400137 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400138 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400139 struct weston_plane cursor_plane;
140 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400141 struct weston_surface *cursor_surface;
142 int current_cursor;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400143 EGLSurface egl_surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300144 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200145 struct backlight *backlight;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146};
147
Jesse Barnes58ef3792012-02-23 09:45:49 -0500148/*
149 * An output has a primary display plane plus zero or more sprites for
150 * blending display contents.
151 */
152struct drm_sprite {
153 struct wl_list link;
154
155 uint32_t fb_id;
156 uint32_t pending_fb_id;
157 struct weston_surface *surface;
158 struct weston_surface *pending_surface;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400159 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500160
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300161 struct drm_output *output;
162
Jesse Barnes58ef3792012-02-23 09:45:49 -0500163 struct drm_compositor *compositor;
164
165 struct wl_listener destroy_listener;
166 struct wl_listener pending_destroy_listener;
167
168 uint32_t possible_crtcs;
169 uint32_t plane_id;
170 uint32_t count_formats;
171
172 int32_t src_x, src_y;
173 uint32_t src_w, src_h;
174 uint32_t dest_x, dest_y;
175 uint32_t dest_w, dest_h;
176
177 uint32_t formats[];
178};
179
Pekka Paalanen33156972012-08-03 13:30:30 -0400180struct drm_seat {
181 struct weston_seat base;
182 struct wl_list devices_list;
183 struct udev_monitor *udev_monitor;
184 struct wl_event_source *udev_monitor_source;
185 char *seat_id;
186};
187
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400188static void
189drm_output_set_cursor(struct drm_output *output);
190static void
191drm_disable_unused_sprites(struct weston_output *output_base);
192
Jesse Barnes58ef3792012-02-23 09:45:49 -0500193static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500194drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
195{
196 struct weston_compositor *ec = output_base->compositor;
197 struct drm_compositor *c =(struct drm_compositor *) ec;
198 struct drm_output *output = (struct drm_output *) output_base;
199 int crtc;
200
201 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
202 if (c->crtcs[crtc] != output->crtc_id)
203 continue;
204
205 if (supported & (1 << crtc))
206 return -1;
207 }
208
209 return 0;
210}
211
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300212static void
213drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
214{
215 struct drm_fb *fb = data;
216 struct gbm_device *gbm = gbm_bo_get_device(bo);
217
218 if (fb->fb_id)
219 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
220
221 if (fb->buffer) {
222 weston_buffer_post_release(fb->buffer);
223 wl_list_remove(&fb->buffer_destroy_listener.link);
224 }
225
226 free(data);
227}
228
229static struct drm_fb *
230drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_output *output)
231{
232 struct drm_fb *fb = gbm_bo_get_user_data(bo);
233 struct drm_compositor *compositor =
234 (struct drm_compositor *) output->base.compositor;
235 uint32_t width, height, stride, handle;
236 int ret;
237
238 if (fb)
239 return fb;
240
241 fb = malloc(sizeof *fb);
242
243 fb->bo = bo;
244 fb->output = output;
245 fb->is_client_buffer = 0;
246 fb->buffer = NULL;
247
248 width = gbm_bo_get_width(bo);
249 height = gbm_bo_get_height(bo);
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400250 stride = gbm_bo_get_stride(bo);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300251 handle = gbm_bo_get_handle(bo).u32;
252
253 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
254 stride, handle, &fb->fb_id);
255 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200256 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300257 free(fb);
258 return NULL;
259 }
260
261 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
262
263 return fb;
264}
265
266static void
267fb_handle_buffer_destroy(struct wl_listener *listener, void *data)
268{
269 struct drm_fb *fb = container_of(listener, struct drm_fb,
270 buffer_destroy_listener);
271
272 fb->buffer = NULL;
273
274 if (fb == fb->output->next ||
275 (fb == fb->output->current && !fb->output->next))
Kristian Høgsberg49952d12012-06-20 00:35:59 -0400276 weston_output_schedule_repaint(&fb->output->base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300277}
278
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400279static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400280drm_output_prepare_scanout_surface(struct weston_output *_output,
281 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500282{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400283 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500284 struct drm_compositor *c =
285 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300286 struct gbm_bo *bo;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500287
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500288 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200289 es->geometry.y != output->base.y ||
Pekka Paalanen60921e52012-01-25 15:55:43 +0200290 es->geometry.width != output->base.current->width ||
291 es->geometry.height != output->base.current->height ||
Pekka Paalanenf1f5b362012-01-25 14:33:33 +0200292 es->transform.enabled ||
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400293 es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400294 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500295
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400296 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
297 es->buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500298
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300299 /* Need to verify output->region contained in surface opaque
300 * region. Or maybe just that format doesn't have alpha.
301 * For now, scanout only if format is XRGB8888. */
302 if (gbm_bo_get_format(bo) != GBM_FORMAT_XRGB8888) {
303 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400304 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300305 }
306
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300307 output->next = drm_fb_get_from_bo(bo, output);
308 if (!output->next) {
309 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400310 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300311 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500312
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300313 output->next->is_client_buffer = 1;
314 output->next->buffer = es->buffer;
315 output->next->buffer->busy_count++;
316 output->next->buffer_destroy_listener.notify = fb_handle_buffer_destroy;
317
318 wl_signal_add(&output->next->buffer->resource.destroy_signal,
319 &output->next->buffer_destroy_listener);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500320
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400321 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500322}
323
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500324static void
Pekka Paalanen07c91f82012-08-30 16:47:21 -0500325drm_output_render(struct drm_output *output, pixman_region32_t *damage, int flip)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400326{
327 struct drm_compositor *compositor =
328 (struct drm_compositor *) output->base.compositor;
329 struct weston_surface *surface;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300330 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400331
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400332 if (!eglMakeCurrent(compositor->base.egl_display, output->egl_surface,
333 output->egl_surface,
334 compositor->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +0200335 weston_log("failed to make current\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400336 return;
337 }
338
339 wl_list_for_each_reverse(surface, &compositor->base.surface_list, link)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400340 if (surface->plane == &compositor->base.primary_plane)
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400341 weston_surface_draw(surface, &output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400342
Pekka Paalanen07c91f82012-08-30 16:47:21 -0500343 if (!flip)
344 return;
345
Kristian Høgsberge0f832b2012-06-20 00:13:18 -0400346 wl_signal_emit(&output->base.frame_signal, output);
Scott Moreau062be7e2012-04-20 13:37:33 -0600347
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400348 eglSwapBuffers(compositor->base.egl_display, output->egl_surface);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300349 bo = gbm_surface_lock_front_buffer(output->surface);
350 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200351 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400352 return;
353 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300354
355 output->next = drm_fb_get_from_bo(bo, output);
356 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200357 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300358 gbm_surface_release_buffer(output->surface, bo);
359 return;
360 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400361}
362
363static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500364drm_output_repaint(struct weston_output *output_base,
Pekka Paalanen07c91f82012-08-30 16:47:21 -0500365 pixman_region32_t *damage, int flip)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100366{
367 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500368 struct drm_compositor *compositor =
369 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500370 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400371 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500372 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100373
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300374 if (!output->next)
Pekka Paalanen07c91f82012-08-30 16:47:21 -0500375 drm_output_render(output, damage, flip);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300376 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400377 return;
Pekka Paalanen07c91f82012-08-30 16:47:21 -0500378 if (!flip)
379 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100380
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400381 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300382 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400383 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300384 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400385 &output->connector_id, 1,
386 &mode->mode_info);
387 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200388 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400389 return;
390 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200391 }
392
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500393 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300394 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500395 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200396 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500397 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500398 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100399
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300400 output->page_flip_pending = 1;
401
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400402 drm_output_set_cursor(output);
403
Jesse Barnes58ef3792012-02-23 09:45:49 -0500404 /*
405 * Now, update all the sprite surfaces
406 */
407 wl_list_for_each(s, &compositor->sprite_list, link) {
408 uint32_t flags = 0;
409 drmVBlank vbl = {
410 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
411 .request.sequence = 1,
412 };
413
414 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
415 continue;
416
417 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
418 output->crtc_id, s->pending_fb_id, flags,
419 s->dest_x, s->dest_y,
420 s->dest_w, s->dest_h,
421 s->src_x, s->src_y,
422 s->src_w, s->src_h);
423 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200424 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500425 ret, strerror(errno));
426
Rob Clark5ca1a472012-08-08 20:27:37 -0500427 if (output->pipe > 0)
428 vbl.request.type |= DRM_VBLANK_SECONDARY;
429
Jesse Barnes58ef3792012-02-23 09:45:49 -0500430 /*
431 * Queue a vblank signal so we know when the surface
432 * becomes active on the display or has been replaced.
433 */
434 vbl.request.signal = (unsigned long)s;
435 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
436 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200437 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500438 ret, strerror(errno));
439 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300440
441 s->output = output;
442 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500443 }
444
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400445 drm_disable_unused_sprites(&output->base);
446
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500447 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400448}
449
450static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500451vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
452 void *data)
453{
454 struct drm_sprite *s = (struct drm_sprite *)data;
455 struct drm_compositor *c = s->compositor;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300456 struct drm_output *output = s->output;
457 uint32_t msecs;
458
459 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500460
461 if (s->surface) {
462 weston_buffer_post_release(s->surface->buffer);
463 wl_list_remove(&s->destroy_listener.link);
464 s->surface = NULL;
465 drmModeRmFB(c->drm.fd, s->fb_id);
466 s->fb_id = 0;
467 }
468
469 if (s->pending_surface) {
470 wl_list_remove(&s->pending_destroy_listener.link);
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400471 wl_signal_add(&s->pending_surface->buffer->resource.destroy_signal,
472 &s->destroy_listener);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500473 s->surface = s->pending_surface;
474 s->pending_surface = NULL;
475 s->fb_id = s->pending_fb_id;
476 s->pending_fb_id = 0;
477 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300478
479 if (!output->page_flip_pending) {
480 msecs = sec * 1000 + usec / 1000;
481 weston_output_finish_frame(&output->base, msecs);
482 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500483}
484
485static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400486page_flip_handler(int fd, unsigned int frame,
487 unsigned int sec, unsigned int usec, void *data)
488{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200489 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400490 uint32_t msecs;
491
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300492 output->page_flip_pending = 0;
493
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300494 if (output->current) {
495 if (output->current->is_client_buffer)
496 gbm_bo_destroy(output->current->bo);
497 else
498 gbm_surface_release_buffer(output->surface,
499 output->current->bo);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200500 }
501
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300502 output->current = output->next;
503 output->next = NULL;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400504
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300505 if (!output->vblank_pending) {
506 msecs = sec * 1000 + usec / 1000;
507 weston_output_finish_frame(&output->base, msecs);
508 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200509}
510
511static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500512drm_surface_format_supported(struct drm_sprite *s, uint32_t format)
513{
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -0400514 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500515
516 for (i = 0; i < s->count_formats; i++)
517 if (s->formats[i] == format)
518 return 1;
519
520 return 0;
521}
522
523static int
524drm_surface_transform_supported(struct weston_surface *es)
525{
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400526 struct weston_matrix *matrix = &es->transform.matrix;
527 int i;
528
529 if (!es->transform.enabled)
530 return 1;
531
532 for (i = 0; i < 16; i++) {
533 switch (i) {
534 case 10:
535 case 15:
536 if (matrix->d[i] != 1.0)
537 return 0;
538 break;
539 case 0:
540 case 5:
541 case 12:
542 case 13:
543 break;
544 default:
545 if (matrix->d[i] != 0.0)
546 return 0;
547 break;
548 }
549 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500550
551 return 1;
552}
553
Jesse Barnes58ef3792012-02-23 09:45:49 -0500554static void
555drm_disable_unused_sprites(struct weston_output *output_base)
556{
557 struct weston_compositor *ec = output_base->compositor;
558 struct drm_compositor *c =(struct drm_compositor *) ec;
559 struct drm_output *output = (struct drm_output *) output_base;
560 struct drm_sprite *s;
561 int ret;
562
563 wl_list_for_each(s, &c->sprite_list, link) {
564 if (s->pending_fb_id)
565 continue;
566
567 ret = drmModeSetPlane(c->drm.fd, s->plane_id,
568 output->crtc_id, 0, 0,
569 0, 0, 0, 0, 0, 0, 0, 0);
570 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200571 weston_log("failed to disable plane: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500572 ret, strerror(errno));
573 drmModeRmFB(c->drm.fd, s->fb_id);
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +0300574
575 if (s->surface) {
576 s->surface = NULL;
577 wl_list_remove(&s->destroy_listener.link);
578 }
579
580 assert(!s->pending_surface);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500581 s->fb_id = 0;
582 s->pending_fb_id = 0;
583 }
584}
585
586/*
587 * This function must take care to damage any previously assigned surface
588 * if the sprite ends up binding to a different surface than in the
589 * previous frame.
590 */
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400591static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500592drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400593 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500594{
595 struct weston_compositor *ec = output_base->compositor;
596 struct drm_compositor *c =(struct drm_compositor *) ec;
597 struct drm_sprite *s;
598 int found = 0;
599 EGLint handle, stride;
600 struct gbm_bo *bo;
601 uint32_t fb_id = 0;
602 uint32_t handles[4], pitches[4], offsets[4];
603 int ret = 0;
604 pixman_region32_t dest_rect, src_rect;
605 pixman_box32_t *box;
606 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400607 wl_fixed_t sx1, sy1, sx2, sy2;
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400608 int32_t width, height;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500610 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400611 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500612
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300613 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400614 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300615
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400616 if (es->buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400617 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618
Rob Clark702ffae2012-08-09 14:18:27 -0500619 if (wl_buffer_is_shm(es->buffer))
620 return NULL;
621
Jesse Barnes58ef3792012-02-23 09:45:49 -0500622 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400623 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624
Jesse Barnes58ef3792012-02-23 09:45:49 -0500625 wl_list_for_each(s, &c->sprite_list, link) {
626 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
627 continue;
628
629 if (!s->pending_fb_id) {
630 found = 1;
631 break;
632 }
633 }
634
635 /* No sprites available */
636 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400637 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638
Rob Clark4339add2012-08-09 14:18:28 -0500639 width = es->geometry.width;
640 height = es->geometry.height;
641
642 /* If geometry is out of bounds, don't even bother trying because
643 * we know the AddFB2() call will fail:
644 */
645 if (c->min_width > width || width > c->max_width ||
646 c->min_height > height || height > c->max_height)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400647 return NULL;
Rob Clark4339add2012-08-09 14:18:28 -0500648
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400649 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
650 es->buffer, GBM_BO_USE_SCANOUT);
651 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400652 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400653
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 format = gbm_bo_get_format(bo);
655 handle = gbm_bo_get_handle(bo).s32;
Kristian Høgsberg270a7cb2012-07-16 16:44:16 -0400656 stride = gbm_bo_get_stride(bo);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500657
658 gbm_bo_destroy(bo);
659
660 if (!drm_surface_format_supported(s, format))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400661 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500662
663 if (!handle)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400664 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500665
666 handles[0] = handle;
667 pitches[0] = stride;
668 offsets[0] = 0;
669
Rob Clark4339add2012-08-09 14:18:28 -0500670 ret = drmModeAddFB2(c->drm.fd, width, height,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500671 format, handles, pitches, offsets,
672 &fb_id, 0);
673 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200674 weston_log("addfb2 failed: %d\n", ret);
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500675 c->sprites_are_broken = 1;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400676 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500677 }
678
Jesse Barnes58ef3792012-02-23 09:45:49 -0500679 s->pending_fb_id = fb_id;
680 s->pending_surface = es;
681 es->buffer->busy_count++;
682
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400683 box = pixman_region32_extents(&es->transform.boundingbox);
684 s->plane.x = box->x1;
685 s->plane.y = box->y1;
686
Jesse Barnes58ef3792012-02-23 09:45:49 -0500687 /*
688 * Calculate the source & dest rects properly based on actual
689 * postion (note the caller has called weston_surface_update_transform()
690 * for us already).
691 */
692 pixman_region32_init(&dest_rect);
693 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
694 &output_base->region);
695 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
696 box = pixman_region32_extents(&dest_rect);
697 s->dest_x = box->x1;
698 s->dest_y = box->y1;
699 s->dest_w = box->x2 - box->x1;
700 s->dest_h = box->y2 - box->y1;
701 pixman_region32_fini(&dest_rect);
702
703 pixman_region32_init(&src_rect);
704 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
705 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500706 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400707
708 weston_surface_from_global_fixed(es,
709 wl_fixed_from_int(box->x1),
710 wl_fixed_from_int(box->y1),
711 &sx1, &sy1);
712 weston_surface_from_global_fixed(es,
713 wl_fixed_from_int(box->x2),
714 wl_fixed_from_int(box->y2),
715 &sx2, &sy2);
716
717 if (sx1 < 0)
718 sx1 = 0;
719 if (sy1 < 0)
720 sy1 = 0;
721 if (sx2 > wl_fixed_from_int(es->geometry.width))
722 sx2 = wl_fixed_from_int(es->geometry.width);
723 if (sy2 > wl_fixed_from_int(es->geometry.height))
724 sy2 = wl_fixed_from_int(es->geometry.height);
725
726 s->src_x = sx1 << 8;
727 s->src_y = sy1 << 8;
728 s->src_w = (sx2 - sx1) << 8;
729 s->src_h = (sy2 - sy1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500730 pixman_region32_fini(&src_rect);
731
Kristian Høgsberg27e30522012-04-11 23:18:23 -0400732 wl_signal_add(&es->buffer->resource.destroy_signal,
733 &s->pending_destroy_listener);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400734
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400735 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500736}
737
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400738static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400739drm_output_prepare_cursor_surface(struct weston_output *output_base,
740 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500741{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400742 struct drm_compositor *c =
743 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400744 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400745
746 if (output->cursor_surface)
747 return NULL;
748 if (es->output_mask != (1u << output_base->id))
749 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500750 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400751 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400752 if (es->buffer == NULL || !wl_buffer_is_shm(es->buffer) ||
753 es->geometry.width > 64 || es->geometry.height > 64)
754 return NULL;
755
756 output->cursor_surface = es;
757
758 return &output->cursor_plane;
759}
760
761static void
762drm_output_set_cursor(struct drm_output *output)
763{
764 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400765 struct drm_compositor *c =
766 (struct drm_compositor *) output->base.compositor;
767 EGLint handle, stride;
768 struct gbm_bo *bo;
769 uint32_t buf[64 * 64];
770 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400771 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500772
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400773 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400774 if (es == NULL) {
775 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
776 return;
777 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500778
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400779 if (es->buffer && pixman_region32_not_empty(&output->cursor_plane.damage)) {
780 pixman_region32_fini(&output->cursor_plane.damage);
781 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400782 output->current_cursor ^= 1;
783 bo = output->cursor_bo[output->current_cursor];
784 memset(buf, 0, sizeof buf);
785 stride = wl_shm_buffer_get_stride(es->buffer);
786 s = wl_shm_buffer_get_data(es->buffer);
787 for (i = 0; i < es->geometry.height; i++)
788 memcpy(buf + i * 64, s + i * stride,
789 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500790
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400791 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300792 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400793
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400794 handle = gbm_bo_get_handle(bo).s32;
795 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500796 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300797 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500798 c->cursors_are_broken = 1;
799 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400800 }
801
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400802 x = es->geometry.x - output->base.x;
803 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400804 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500805 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400806 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500807 c->cursors_are_broken = 1;
808 }
809
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 output->cursor_plane.x = x;
811 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400812 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500813}
814
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815static void
816drm_assign_planes(struct weston_output *output)
817{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400818 struct drm_compositor *c =
819 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400820 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400822 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823
824 /*
825 * Find a surface for each sprite in the output using some heuristics:
826 * 1) size
827 * 2) frequency of update
828 * 3) opacity (though some hw might support alpha blending)
829 * 4) clipping (this can be fixed with color keys)
830 *
831 * The idea is to save on blitting since this should save power.
832 * If we can get a large video surface on the sprite for example,
833 * the main display surface may not need to update at all, and
834 * the client buffer can be used directly for the sprite surface
835 * as we do for flipping full screen surfaces.
836 */
837 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400838 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400839 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840 pixman_region32_init(&surface_overlap);
841 pixman_region32_intersect(&surface_overlap, &overlap,
842 &es->transform.boundingbox);
843
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400844 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400845 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400846 next_plane = primary;
847 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400848 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400849 if (next_plane == NULL)
850 next_plane = drm_output_prepare_scanout_surface(output, es);
851 if (next_plane == NULL)
852 next_plane = drm_output_prepare_overlay_surface(output, es);
853 if (next_plane == NULL)
854 next_plane = primary;
855 weston_surface_move_to_plane(es, next_plane);
856 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500857 pixman_region32_union(&overlap, &overlap,
858 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400859
Jesse Barnes58ef3792012-02-23 09:45:49 -0500860 pixman_region32_fini(&surface_overlap);
861 }
862 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500863}
864
Matt Roper361d2ad2011-08-29 13:52:23 -0700865static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500866drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -0700867{
868 struct drm_output *output = (struct drm_output *) output_base;
869 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +0200870 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -0700871 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -0700872
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200873 if (output->backlight)
874 backlight_destroy(output->backlight);
875
Matt Roper361d2ad2011-08-29 13:52:23 -0700876 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400877 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -0700878
879 /* Restore original CRTC state */
880 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +0200881 origcrtc->x, origcrtc->y,
882 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -0700883 drmModeFreeCrtc(origcrtc);
884
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200885 c->crtc_allocator &= ~(1 << output->crtc_id);
886 c->connector_allocator &= ~(1 << output->connector_id);
887
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400888 eglDestroySurface(c->base.egl_display, output->egl_surface);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400889 gbm_surface_destroy(output->surface);
890
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400891 weston_plane_release(&output->fb_plane);
892 weston_plane_release(&output->cursor_plane);
893
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500894 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +0200895 wl_list_remove(&output->base.link);
896
Kristian Høgsberg148ef012012-07-26 23:03:57 -0400897 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -0700898 free(output);
899}
900
Alex Wub7b8bda2012-04-17 17:20:48 +0800901static struct drm_mode *
902choose_mode (struct drm_output *output, struct weston_mode *target_mode)
903{
904 struct drm_mode *tmp_mode = NULL, *mode;
905
906 if (output->base.current->width == target_mode->width &&
907 output->base.current->height == target_mode->height &&
908 (output->base.current->refresh == target_mode->refresh ||
909 target_mode->refresh == 0))
910 return (struct drm_mode *)output->base.current;
911
912 wl_list_for_each(mode, &output->base.mode_list, base.link) {
913 if (mode->mode_info.hdisplay == target_mode->width &&
914 mode->mode_info.vdisplay == target_mode->height) {
915 if (mode->mode_info.vrefresh == target_mode->refresh ||
916 target_mode->refresh == 0) {
917 return mode;
918 } else if (!tmp_mode)
919 tmp_mode = mode;
920 }
921 }
922
923 return tmp_mode;
924}
925
926static int
927drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
928{
929 struct drm_output *output;
930 struct drm_mode *drm_mode;
931 int ret;
932 struct drm_compositor *ec;
933 struct gbm_surface *surface;
934 EGLSurface egl_surface;
935
936 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200937 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800938 return -1;
939 }
940
941 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +0200942 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800943 return -1;
944 }
945
946 ec = (struct drm_compositor *)output_base->compositor;
947 output = (struct drm_output *)output_base;
948 drm_mode = choose_mode (output, mode);
949
950 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +0200951 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +0800952 return -1;
953 } else if (&drm_mode->base == output->base.current) {
954 return 0;
955 } else if (drm_mode->base.width == output->base.current->width &&
956 drm_mode->base.height == output->base.current->height) {
957 /* only change refresh value */
958 ret = drmModeSetCrtc(ec->drm.fd,
959 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300960 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +0800961 &output->connector_id, 1, &drm_mode->mode_info);
962
963 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200964 weston_log("failed to set mode (%dx%d) %u Hz\n",
Alex Wub7b8bda2012-04-17 17:20:48 +0800965 drm_mode->base.width,
966 drm_mode->base.height,
Kristian Høgsbergc4621b02012-05-10 12:23:53 -0400967 drm_mode->base.refresh / 1000);
Alex Wub7b8bda2012-04-17 17:20:48 +0800968 ret = -1;
969 } else {
970 output->base.current->flags = 0;
971 output->base.current = &drm_mode->base;
972 drm_mode->base.flags =
973 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
974 ret = 0;
975 }
976
977 return ret;
978 }
979
980 drm_mode->base.flags =
981 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
982
983 surface = gbm_surface_create(ec->gbm,
984 drm_mode->base.width,
985 drm_mode->base.height,
986 GBM_FORMAT_XRGB8888,
987 GBM_BO_USE_SCANOUT |
988 GBM_BO_USE_RENDERING);
989 if (!surface) {
Martin Minarik6d118362012-06-07 18:01:59 +0200990 weston_log("failed to create gbm surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +0800991 return -1;
992 }
993
994 egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -0400995 eglCreateWindowSurface(ec->base.egl_display,
996 ec->base.egl_config,
Alex Wub7b8bda2012-04-17 17:20:48 +0800997 surface, NULL);
998
999 if (egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001000 weston_log("failed to create egl surface\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001001 goto err;
1002 }
1003
1004 ret = drmModeSetCrtc(ec->drm.fd,
1005 output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001006 output->current->fb_id, 0, 0,
Alex Wub7b8bda2012-04-17 17:20:48 +08001007 &output->connector_id, 1, &drm_mode->mode_info);
1008 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +02001009 weston_log("failed to set mode\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001010 goto err;
1011 }
1012
1013 /* reset rendering stuff. */
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001014 if (output->current) {
1015 if (output->current->is_client_buffer)
1016 gbm_bo_destroy(output->current->bo);
1017 else
1018 gbm_surface_release_buffer(output->surface,
1019 output->current->bo);
1020 }
1021 output->current = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001022
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03001023 if (output->next) {
1024 if (output->next->is_client_buffer)
1025 gbm_bo_destroy(output->next->bo);
1026 else
1027 gbm_surface_release_buffer(output->surface,
1028 output->next->bo);
1029 }
1030 output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001031
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001032 eglDestroySurface(ec->base.egl_display, output->egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001033 gbm_surface_destroy(output->surface);
1034 output->egl_surface = egl_surface;
1035 output->surface = surface;
1036
1037 /*update output*/
1038 output->base.current = &drm_mode->base;
1039 output->base.dirty = 1;
1040 weston_output_move(&output->base, output->base.x, output->base.y);
1041 return 0;
1042
1043err:
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001044 eglDestroySurface(ec->base.egl_display, egl_surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001045 gbm_surface_destroy(surface);
1046 return -1;
1047}
1048
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001049static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001050on_drm_input(int fd, uint32_t mask, void *data)
1051{
1052 drmEventContext evctx;
1053
1054 memset(&evctx, 0, sizeof evctx);
1055 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1056 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001057 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001058 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001059
1060 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001061}
1062
1063static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001064init_egl(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001065{
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001066 EGLint major, minor, n;
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001067 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001068 int fd;
Kristian Høgsberg2c28aa52010-07-28 23:47:54 -04001069 static const EGLint context_attribs[] = {
1070 EGL_CONTEXT_CLIENT_VERSION, 2,
1071 EGL_NONE
1072 };
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001073
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001074 static const EGLint config_attribs[] = {
1075 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1076 EGL_RED_SIZE, 1,
1077 EGL_GREEN_SIZE, 1,
1078 EGL_BLUE_SIZE, 1,
1079 EGL_ALPHA_SIZE, 0,
1080 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1081 EGL_NONE
1082 };
1083
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001084 sysnum = udev_device_get_sysnum(device);
1085 if (sysnum)
1086 ec->drm.id = atoi(sysnum);
1087 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001088 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001089 return -1;
1090 }
1091
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001092 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001093 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001094 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001095 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001096 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001097 udev_device_get_devnode(device));
1098 return -1;
1099 }
1100
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001101 weston_log("using %s\n", filename);
1102
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001103 ec->drm.fd = fd;
Benjamin Franzke060cf802011-04-30 09:32:11 +02001104 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001105 ec->base.egl_display = eglGetDisplay(ec->gbm);
1106 if (ec->base.egl_display == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001107 weston_log("failed to create display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001108 return -1;
1109 }
1110
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001111 if (!eglInitialize(ec->base.egl_display, &major, &minor)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001112 weston_log("failed to initialize display\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001113 return -1;
1114 }
1115
Darxus55973f22010-11-22 21:24:39 -05001116 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001117 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
Darxus55973f22010-11-22 21:24:39 -05001118 return -1;
1119 }
1120
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001121 if (!eglChooseConfig(ec->base.egl_display, config_attribs,
1122 &ec->base.egl_config, 1, &n) || n != 1) {
Martin Minarik6d118362012-06-07 18:01:59 +02001123 weston_log("failed to choose config: %d\n", n);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001124 return -1;
1125 }
1126
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001127 ec->base.egl_context =
1128 eglCreateContext(ec->base.egl_display, ec->base.egl_config,
1129 EGL_NO_CONTEXT, context_attribs);
1130 if (ec->base.egl_context == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001131 weston_log("failed to create context\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001132 return -1;
1133 }
1134
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001135 ec->dummy_surface = gbm_surface_create(ec->gbm, 10, 10,
1136 GBM_FORMAT_XRGB8888,
1137 GBM_BO_USE_RENDERING);
1138 if (!ec->dummy_surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001139 weston_log("failed to create dummy gbm surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001140 return -1;
1141 }
1142
1143 ec->dummy_egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001144 eglCreateWindowSurface(ec->base.egl_display,
1145 ec->base.egl_config,
1146 ec->dummy_surface,
1147 NULL);
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001148 if (ec->dummy_egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001149 weston_log("failed to create egl surface\n");
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001150 return -1;
1151 }
1152
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001153 if (!eglMakeCurrent(ec->base.egl_display, ec->dummy_egl_surface,
1154 ec->dummy_egl_surface, ec->base.egl_context)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001155 weston_log("failed to make context current\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001156 return -1;
1157 }
1158
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001159 return 0;
1160}
1161
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001162static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001163drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1164{
1165 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001166 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001167
1168 mode = malloc(sizeof *mode);
1169 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001170 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001171
1172 mode->base.flags = 0;
1173 mode->base.width = info->hdisplay;
1174 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001175
1176 /* Calculate higher precision (mHz) refresh rate */
1177 refresh = (info->clock * 1000000LL / info->htotal +
1178 info->vtotal / 2) / info->vtotal;
1179
1180 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1181 refresh *= 2;
1182 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1183 refresh /= 2;
1184 if (info->vscan > 1)
1185 refresh /= info->vscan;
1186
1187 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001188 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001189
1190 if (info->type & DRM_MODE_TYPE_PREFERRED)
1191 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1192
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001193 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1194
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001195 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001196}
1197
1198static int
1199drm_subpixel_to_wayland(int drm_value)
1200{
1201 switch (drm_value) {
1202 default:
1203 case DRM_MODE_SUBPIXEL_UNKNOWN:
1204 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1205 case DRM_MODE_SUBPIXEL_NONE:
1206 return WL_OUTPUT_SUBPIXEL_NONE;
1207 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1208 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1209 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1210 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1211 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1212 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1213 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1214 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1215 }
1216}
1217
Kristian Høgsberg9f404b72012-01-26 00:11:01 -05001218static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001219sprite_handle_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001220{
1221 struct drm_sprite *sprite =
1222 container_of(listener, struct drm_sprite,
1223 destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001224 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001225
1226 sprite->surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001227 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
1228 sprite->fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001229}
1230
1231static void
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001232sprite_handle_pending_buffer_destroy(struct wl_listener *listener, void *data)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001233{
1234 struct drm_sprite *sprite =
1235 container_of(listener, struct drm_sprite,
1236 pending_destroy_listener);
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001237 struct drm_compositor *compositor = sprite->compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001238
1239 sprite->pending_surface = NULL;
Ander Conselvan de Oliveira01a57ed2012-06-26 17:09:15 +03001240 drmModeRmFB(compositor->drm.fd, sprite->pending_fb_id);
1241 sprite->pending_fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001242}
1243
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001244/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001245static uint32_t
1246drm_get_backlight(struct drm_output *output)
1247{
1248 long brightness, max_brightness, norm;
1249
1250 brightness = backlight_get_brightness(output->backlight);
1251 max_brightness = backlight_get_max_brightness(output->backlight);
1252
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001253 /* convert it on a scale of 0 to 255 */
1254 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001255
1256 return (uint32_t) norm;
1257}
1258
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001259/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001260static void
1261drm_set_backlight(struct weston_output *output_base, uint32_t value)
1262{
1263 struct drm_output *output = (struct drm_output *) output_base;
1264 long max_brightness, new_brightness;
1265
1266 if (!output->backlight)
1267 return;
1268
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001269 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001270 return;
1271
1272 max_brightness = backlight_get_max_brightness(output->backlight);
1273
1274 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001275 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001276
1277 backlight_set_brightness(output->backlight, new_brightness);
1278}
1279
1280static drmModePropertyPtr
1281drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1282{
1283 drmModePropertyPtr props;
1284 int i;
1285
1286 for (i = 0; i < connector->count_props; i++) {
1287 props = drmModeGetProperty(fd, connector->props[i]);
1288 if (!props)
1289 continue;
1290
1291 if (!strcmp(props->name, name))
1292 return props;
1293
1294 drmModeFreeProperty(props);
1295 }
1296
1297 return NULL;
1298}
1299
1300static void
1301drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1302{
1303 struct drm_output *output = (struct drm_output *) output_base;
1304 struct weston_compositor *ec = output_base->compositor;
1305 struct drm_compositor *c = (struct drm_compositor *) ec;
1306 drmModeConnectorPtr connector;
1307 drmModePropertyPtr prop;
1308
1309 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1310 if (!connector)
1311 return;
1312
1313 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1314 if (!prop) {
1315 drmModeFreeConnector(connector);
1316 return;
1317 }
1318
1319 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1320 prop->prop_id, level);
1321 drmModeFreeProperty(prop);
1322 drmModeFreeConnector(connector);
1323}
1324
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001325static const char *connector_type_names[] = {
1326 "None",
1327 "VGA",
1328 "DVI",
1329 "DVI",
1330 "DVI",
1331 "Composite",
1332 "TV",
1333 "LVDS",
1334 "CTV",
1335 "DIN",
1336 "DP",
1337 "HDMI",
1338 "HDMI",
1339 "TV",
1340 "eDP",
1341};
1342
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001343static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001344find_crtc_for_connector(struct drm_compositor *ec,
1345 drmModeRes *resources, drmModeConnector *connector)
1346{
1347 drmModeEncoder *encoder;
1348 uint32_t possible_crtcs;
1349 int i, j;
1350
1351 for (j = 0; j < connector->count_encoders; j++) {
1352 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1353 if (encoder == NULL) {
1354 weston_log("Failed to get encoder.\n");
1355 return -1;
1356 }
1357 possible_crtcs = encoder->possible_crtcs;
1358 drmModeFreeEncoder(encoder);
1359
1360 for (i = 0; i < resources->count_crtcs; i++) {
1361 if (possible_crtcs & (1 << i) &&
1362 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1363 return i;
1364 }
1365 }
1366
1367 return -1;
1368}
1369
1370static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001371create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001372 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001373 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001374 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001375{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001376 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001377 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1378 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001379 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001380 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001381 drmModeModeInfo crtc_mode;
1382 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001383 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001384 char name[32];
1385 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001386
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001387 i = find_crtc_for_connector(ec, resources, connector);
1388 if (i < 0) {
1389 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001390 return -1;
1391 }
1392
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001393 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001394 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001395 return -1;
1396
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001397 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001398 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1399 output->base.make = "unknown";
1400 output->base.model = "unknown";
1401 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001402
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001403 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1404 type_name = connector_type_names[connector->connector_type];
1405 else
1406 type_name = "UNKNOWN";
1407 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1408 output->name = strdup(name);
1409
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001410 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001411 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001412 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001413 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001414 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001415
Matt Roper361d2ad2011-08-29 13:52:23 -07001416 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1417
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001418 /* Get the current mode on the crtc that's currently driving
1419 * this connector. */
1420 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001421 memset(&crtc_mode, 0, sizeof crtc_mode);
1422 if (encoder != NULL) {
1423 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1424 drmModeFreeEncoder(encoder);
1425 if (crtc == NULL)
1426 goto err_free;
1427 if (crtc->mode_valid)
1428 crtc_mode = crtc->mode;
1429 drmModeFreeCrtc(crtc);
1430 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001431
David Herrmann0f0d54e2011-12-08 17:05:45 +01001432 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001433 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1434 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001435 goto err_free;
1436 }
1437
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001438 preferred = NULL;
1439 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001440 configured = NULL;
1441
1442 wl_list_for_each(temp, &configured_output_list, link) {
1443 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001444 if (temp->mode)
1445 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001446 temp->name, temp->mode);
1447 o = temp;
1448 break;
1449 }
1450 }
1451
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001452 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001453 weston_log("Disabling output %s\n", o->name);
1454
1455 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1456 0, 0, 0, 0, 0, NULL);
1457 goto err_free;
1458 }
1459
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001460 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001461 if (o && o->config == OUTPUT_CONFIG_MODE &&
1462 o->width == drm_mode->base.width &&
1463 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001464 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001465 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001466 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001467 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001468 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001469 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001470
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001471 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001472 configured = drm_output_add_mode(output, &o->crtc_mode);
1473 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001474 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001475 current = configured;
1476 }
1477
Wang Quanxianacb805a2012-07-30 18:09:46 -04001478 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001479 current = drm_output_add_mode(output, &crtc_mode);
1480 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001481 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001482 }
1483
Scott Moreau8ab5d452012-07-30 19:51:08 -06001484 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1485 configured = current;
1486
Wang Quanxianacb805a2012-07-30 18:09:46 -04001487 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001488 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001489 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001490 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001491 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001492 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001493 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001494 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001495
1496 if (output->base.current == NULL) {
1497 weston_log("no available modes for %s\n", output->name);
1498 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001499 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001500
Wang Quanxianacb805a2012-07-30 18:09:46 -04001501 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1502
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001503 output->surface = gbm_surface_create(ec->gbm,
1504 output->base.current->width,
1505 output->base.current->height,
1506 GBM_FORMAT_XRGB8888,
1507 GBM_BO_USE_SCANOUT |
1508 GBM_BO_USE_RENDERING);
1509 if (!output->surface) {
Martin Minarik6d118362012-06-07 18:01:59 +02001510 weston_log("failed to create gbm surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001511 goto err_free;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001512 }
1513
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001514 output->egl_surface =
Kristian Høgsberg362b6722012-06-18 15:13:51 -04001515 eglCreateWindowSurface(ec->base.egl_display,
1516 ec->base.egl_config,
1517 output->surface,
1518 NULL);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001519 if (output->egl_surface == EGL_NO_SURFACE) {
Martin Minarik6d118362012-06-07 18:01:59 +02001520 weston_log("failed to create egl surface\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001521 goto err_surface;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001522 }
1523
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001524 output->cursor_bo[0] =
1525 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1526 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1527 output->cursor_bo[1] =
1528 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1529 GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
1530
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001531 output->backlight = backlight_init(drm_device,
1532 connector->connector_type);
1533 if (output->backlight) {
1534 output->base.set_backlight = drm_set_backlight;
1535 output->base.backlight_current = drm_get_backlight(output);
1536 }
1537
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001538 weston_output_init(&output->base, &ec->base, x, y,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001539 connector->mmWidth, connector->mmHeight,
1540 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001541
1542 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1543
Alex Wubd3354b2012-04-17 17:20:49 +08001544 output->base.origin = output->base.current;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001545 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001546 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001547 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001548 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001549 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001550
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001551 weston_plane_init(&output->cursor_plane, 0, 0);
1552 weston_plane_init(&output->fb_plane, 0, 0);
1553
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001554 weston_log("Output %s, (connector %d, crtc %d)\n",
1555 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001556 wl_list_for_each(m, &output->base.mode_list, link)
1557 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1558 m->width, m->height, m->refresh / 1000.0,
1559 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1560 ", preferred" : "",
1561 m->flags & WL_OUTPUT_MODE_CURRENT ?
1562 ", current" : "",
1563 connector->count_modes == 0 ?
1564 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001565
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001566 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001567
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001568err_surface:
1569 gbm_surface_destroy(output->surface);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001570err_free:
1571 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1572 base.link) {
1573 wl_list_remove(&drm_mode->base.link);
1574 free(drm_mode);
1575 }
1576
1577 drmModeFreeCrtc(output->original_crtc);
1578 ec->crtc_allocator &= ~(1 << output->crtc_id);
1579 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001580 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001581 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001582
David Herrmann0f0d54e2011-12-08 17:05:45 +01001583 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001584}
1585
Jesse Barnes58ef3792012-02-23 09:45:49 -05001586static void
1587create_sprites(struct drm_compositor *ec)
1588{
1589 struct drm_sprite *sprite;
1590 drmModePlaneRes *plane_res;
1591 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001592 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001593
1594 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1595 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001596 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001597 strerror(errno));
1598 return;
1599 }
1600
1601 for (i = 0; i < plane_res->count_planes; i++) {
1602 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1603 if (!plane)
1604 continue;
1605
1606 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1607 plane->count_formats));
1608 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001609 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001610 __func__);
1611 free(plane);
1612 continue;
1613 }
1614
1615 memset(sprite, 0, sizeof *sprite);
1616
1617 sprite->possible_crtcs = plane->possible_crtcs;
1618 sprite->plane_id = plane->plane_id;
1619 sprite->surface = NULL;
1620 sprite->pending_surface = NULL;
1621 sprite->fb_id = 0;
1622 sprite->pending_fb_id = 0;
Kristian Høgsberg27e30522012-04-11 23:18:23 -04001623 sprite->destroy_listener.notify = sprite_handle_buffer_destroy;
1624 sprite->pending_destroy_listener.notify =
Jesse Barnes58ef3792012-02-23 09:45:49 -05001625 sprite_handle_pending_buffer_destroy;
1626 sprite->compositor = ec;
1627 sprite->count_formats = plane->count_formats;
1628 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001629 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001630 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001631 weston_plane_init(&sprite->plane, 0, 0);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001632
1633 wl_list_insert(&ec->sprite_list, &sprite->link);
1634 }
1635
1636 free(plane_res->planes);
1637 free(plane_res);
1638}
1639
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001640static void
1641destroy_sprites(struct drm_compositor *compositor)
1642{
1643 struct drm_sprite *sprite, *next;
1644 struct drm_output *output;
1645
1646 output = container_of(compositor->base.output_list.next,
1647 struct drm_output, base.link);
1648
1649 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1650 drmModeSetPlane(compositor->drm.fd,
1651 sprite->plane_id,
1652 output->crtc_id, 0, 0,
1653 0, 0, 0, 0, 0, 0, 0, 0);
1654 drmModeRmFB(compositor->drm.fd, sprite->fb_id);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001655 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001656 free(sprite);
1657 }
1658}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001659
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001660static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001661create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001662 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001663{
1664 drmModeConnector *connector;
1665 drmModeRes *resources;
1666 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001667 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001668
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001669 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001670 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001671 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001672 return -1;
1673 }
1674
Jesse Barnes58ef3792012-02-23 09:45:49 -05001675 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001676 if (!ec->crtcs) {
1677 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001678 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001679 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001680
Rob Clark4339add2012-08-09 14:18:28 -05001681 ec->min_width = resources->min_width;
1682 ec->max_width = resources->max_width;
1683 ec->min_height = resources->min_height;
1684 ec->max_height = resources->max_height;
1685
Jesse Barnes58ef3792012-02-23 09:45:49 -05001686 ec->num_crtcs = resources->count_crtcs;
1687 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1688
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001689 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001690 connector = drmModeGetConnector(ec->drm.fd,
1691 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001692 if (connector == NULL)
1693 continue;
1694
1695 if (connector->connection == DRM_MODE_CONNECTED &&
1696 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001697 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001698 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001699 connector, x, y,
1700 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001701 drmModeFreeConnector(connector);
1702 continue;
1703 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001704
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001705 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001706 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001707 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001708 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001709
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001710 drmModeFreeConnector(connector);
1711 }
1712
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001713 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001714 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001715 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001716 return -1;
1717 }
1718
1719 drmModeFreeResources(resources);
1720
1721 return 0;
1722}
1723
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001724static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001725update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001726{
1727 drmModeConnector *connector;
1728 drmModeRes *resources;
1729 struct drm_output *output, *next;
1730 int x = 0, y = 0;
1731 int x_offset = 0, y_offset = 0;
1732 uint32_t connected = 0, disconnects = 0;
1733 int i;
1734
1735 resources = drmModeGetResources(ec->drm.fd);
1736 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001737 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001738 return;
1739 }
1740
1741 /* collect new connects */
1742 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001743 int connector_id = resources->connectors[i];
1744
1745 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01001746 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001747 continue;
1748
David Herrmann7551cff2011-12-08 17:05:43 +01001749 if (connector->connection != DRM_MODE_CONNECTED) {
1750 drmModeFreeConnector(connector);
1751 continue;
1752 }
1753
Benjamin Franzke117483d2011-08-30 11:38:26 +02001754 connected |= (1 << connector_id);
1755
1756 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001757 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001758 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001759 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001760
1761 /* XXX: not yet needed, we die with 0 outputs */
1762 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06001763 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001764 else
1765 x = 0;
1766 y = 0;
1767 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001768 connector, x, y,
1769 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02001770 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001771
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001772 }
1773 drmModeFreeConnector(connector);
1774 }
1775 drmModeFreeResources(resources);
1776
1777 disconnects = ec->connector_allocator & ~connected;
1778 if (disconnects) {
1779 wl_list_for_each_safe(output, next, &ec->base.output_list,
1780 base.link) {
1781 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001782 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001783 output->base.x - x_offset,
1784 output->base.y - y_offset);
1785 }
1786
1787 if (disconnects & (1 << output->connector_id)) {
1788 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02001789 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001790 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06001791 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001792 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001793 }
1794 }
1795 }
1796
1797 /* FIXME: handle zero outputs, without terminating */
1798 if (ec->connector_allocator == 0)
1799 wl_display_terminate(ec->base.wl_display);
1800}
1801
1802static int
David Herrmannd7488c22012-03-11 20:05:21 +01001803udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001804{
David Herrmannd7488c22012-03-11 20:05:21 +01001805 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01001806 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01001807
1808 sysnum = udev_device_get_sysnum(device);
1809 if (!sysnum || atoi(sysnum) != ec->drm.id)
1810 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02001811
David Herrmann6ac52db2012-03-11 20:05:22 +01001812 val = udev_device_get_property_value(device, "HOTPLUG");
1813 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001814 return 0;
1815
David Herrmann6ac52db2012-03-11 20:05:22 +01001816 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001817}
1818
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001819static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001820udev_drm_event(int fd, uint32_t mask, void *data)
1821{
1822 struct drm_compositor *ec = data;
1823 struct udev_device *event;
1824
1825 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02001826
David Herrmannd7488c22012-03-11 20:05:21 +01001827 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001828 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001829
1830 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001831
1832 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001833}
1834
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05001835static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04001836drm_restore(struct weston_compositor *ec)
1837{
1838 struct drm_compositor *d = (struct drm_compositor *) ec;
1839
1840 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
1841 weston_log("failed to drop master: %m\n");
1842 tty_reset(d->tty);
1843}
1844
Pekka Paalanen33156972012-08-03 13:30:30 -04001845static const char default_seat[] = "seat0";
1846
1847static void
1848device_added(struct udev_device *udev_device, struct drm_seat *master)
1849{
1850 struct weston_compositor *c;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001851 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04001852 const char *devnode;
1853 const char *device_seat;
1854 int fd;
1855
1856 device_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
1857 if (!device_seat)
1858 device_seat = default_seat;
1859
1860 if (strcmp(device_seat, master->seat_id))
1861 return;
1862
1863 c = master->base.compositor;
1864 devnode = udev_device_get_devnode(udev_device);
1865
1866 /* Use non-blocking mode so that we can loop on read on
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001867 * evdev_device_data() until all events on the fd are
Pekka Paalanen33156972012-08-03 13:30:30 -04001868 * read. mtdev_get() also expects this. */
1869 fd = weston_launcher_open(c, devnode, O_RDWR | O_NONBLOCK);
1870 if (fd < 0) {
1871 weston_log("opening input device '%s' failed.\n", devnode);
1872 return;
1873 }
1874
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001875 device = evdev_device_create(&master->base, devnode, fd);
Pekka Paalanen33156972012-08-03 13:30:30 -04001876 if (!device) {
1877 close(fd);
1878 weston_log("not using input device '%s'.\n", devnode);
1879 return;
1880 }
1881
1882 wl_list_insert(master->devices_list.prev, &device->link);
1883}
1884
1885static void
1886evdev_add_devices(struct udev *udev, struct weston_seat *seat_base)
1887{
1888 struct drm_seat *seat = (struct drm_seat *) seat_base;
1889 struct udev_enumerate *e;
1890 struct udev_list_entry *entry;
1891 struct udev_device *device;
1892 const char *path, *sysname;
1893
1894 e = udev_enumerate_new(udev);
1895 udev_enumerate_add_match_subsystem(e, "input");
1896 udev_enumerate_scan_devices(e);
1897 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
1898 path = udev_list_entry_get_name(entry);
1899 device = udev_device_new_from_syspath(udev, path);
1900
1901 sysname = udev_device_get_sysname(device);
1902 if (strncmp("event", sysname, 5) != 0) {
1903 udev_device_unref(device);
1904 continue;
1905 }
1906
1907 device_added(device, seat);
1908
1909 udev_device_unref(device);
1910 }
1911 udev_enumerate_unref(e);
1912
1913 evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
1914
1915 if (wl_list_empty(&seat->devices_list)) {
1916 weston_log(
1917 "warning: no input devices on entering Weston. "
1918 "Possible causes:\n"
1919 "\t- no permissions to read /dev/input/event*\n"
1920 "\t- seats misconfigured "
1921 "(Weston backend option 'seat', "
1922 "udev device property ID_SEAT)\n");
1923 }
1924}
1925
1926static int
1927evdev_udev_handler(int fd, uint32_t mask, void *data)
1928{
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001929 struct drm_seat *seat = data;
Pekka Paalanen33156972012-08-03 13:30:30 -04001930 struct udev_device *udev_device;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001931 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04001932 const char *action;
1933 const char *devnode;
1934
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001935 udev_device = udev_monitor_receive_device(seat->udev_monitor);
Pekka Paalanen33156972012-08-03 13:30:30 -04001936 if (!udev_device)
1937 return 1;
1938
1939 action = udev_device_get_action(udev_device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001940 if (!action)
1941 goto out;
Pekka Paalanen33156972012-08-03 13:30:30 -04001942
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001943 if (strncmp("event", udev_device_get_sysname(udev_device), 5) != 0)
1944 goto out;
1945
1946 if (!strcmp(action, "add")) {
1947 device_added(udev_device, seat);
Pekka Paalanen33156972012-08-03 13:30:30 -04001948 }
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001949 else if (!strcmp(action, "remove")) {
1950 devnode = udev_device_get_devnode(udev_device);
1951 wl_list_for_each_safe(device, next, &seat->devices_list, link)
1952 if (!strcmp(device->devnode, devnode)) {
Pekka Paalanen42b3f6a2012-08-03 14:39:09 +03001953 weston_log("input device %s, %s removed\n",
1954 device->devname, device->devnode);
Pekka Paalanen3eb47612012-08-06 14:57:08 +03001955 evdev_device_destroy(device);
Pekka Paalanend2e69c22012-08-03 14:39:08 +03001956 break;
1957 }
1958 }
1959
1960out:
Pekka Paalanen33156972012-08-03 13:30:30 -04001961 udev_device_unref(udev_device);
1962
1963 return 0;
1964}
1965
1966static int
1967evdev_enable_udev_monitor(struct udev *udev, struct weston_seat *seat_base)
1968{
1969 struct drm_seat *master = (struct drm_seat *) seat_base;
1970 struct wl_event_loop *loop;
1971 struct weston_compositor *c = master->base.compositor;
1972 int fd;
1973
1974 master->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
1975 if (!master->udev_monitor) {
1976 weston_log("udev: failed to create the udev monitor\n");
1977 return 0;
1978 }
1979
1980 udev_monitor_filter_add_match_subsystem_devtype(master->udev_monitor,
1981 "input", NULL);
1982
1983 if (udev_monitor_enable_receiving(master->udev_monitor)) {
1984 weston_log("udev: failed to bind the udev monitor\n");
1985 udev_monitor_unref(master->udev_monitor);
1986 return 0;
1987 }
1988
1989 loop = wl_display_get_event_loop(c->wl_display);
1990 fd = udev_monitor_get_fd(master->udev_monitor);
1991 master->udev_monitor_source =
1992 wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
1993 evdev_udev_handler, master);
1994 if (!master->udev_monitor_source) {
1995 udev_monitor_unref(master->udev_monitor);
1996 return 0;
1997 }
1998
1999 return 1;
2000}
2001
2002static void
2003evdev_disable_udev_monitor(struct weston_seat *seat_base)
2004{
2005 struct drm_seat *seat = (struct drm_seat *) seat_base;
2006
2007 if (!seat->udev_monitor)
2008 return;
2009
2010 udev_monitor_unref(seat->udev_monitor);
2011 seat->udev_monitor = NULL;
2012 wl_event_source_remove(seat->udev_monitor_source);
2013 seat->udev_monitor_source = NULL;
2014}
2015
2016static void
2017drm_led_update(struct weston_seat *seat_base, enum weston_led leds)
2018{
2019 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002020 struct evdev_device *device;
Pekka Paalanen33156972012-08-03 13:30:30 -04002021
Pekka Paalanenb9d38f42012-08-06 14:57:07 +03002022 wl_list_for_each(device, &seat->devices_list, link)
2023 evdev_led_update(device, leds);
Pekka Paalanen33156972012-08-03 13:30:30 -04002024}
2025
2026static void
2027evdev_input_create(struct weston_compositor *c, struct udev *udev,
2028 const char *seat_id)
2029{
2030 struct drm_seat *seat;
2031
2032 seat = malloc(sizeof *seat);
2033 if (seat == NULL)
2034 return;
2035
2036 memset(seat, 0, sizeof *seat);
2037 weston_seat_init(&seat->base, c);
2038 seat->base.led_update = drm_led_update;
2039
2040 wl_list_init(&seat->devices_list);
2041 seat->seat_id = strdup(seat_id);
2042 if (!evdev_enable_udev_monitor(udev, &seat->base)) {
2043 free(seat->seat_id);
2044 free(seat);
2045 return;
2046 }
2047
2048 evdev_add_devices(udev, &seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002049}
2050
2051static void
2052evdev_remove_devices(struct weston_seat *seat_base)
2053{
2054 struct drm_seat *seat = (struct drm_seat *) seat_base;
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002055 struct evdev_device *device, *next;
Pekka Paalanen33156972012-08-03 13:30:30 -04002056
2057 wl_list_for_each_safe(device, next, &seat->devices_list, link)
Pekka Paalanen3eb47612012-08-06 14:57:08 +03002058 evdev_device_destroy(device);
Pekka Paalanen33156972012-08-03 13:30:30 -04002059
Pekka Paalanend8583512012-08-03 14:39:11 +03002060 if (seat->base.seat.keyboard)
Kristian Høgsbergcb3eaae2012-08-10 09:50:11 -04002061 notify_keyboard_focus_out(&seat->base);
Pekka Paalanen33156972012-08-03 13:30:30 -04002062}
2063
2064static void
2065evdev_input_destroy(struct weston_seat *seat_base)
2066{
2067 struct drm_seat *seat = (struct drm_seat *) seat_base;
2068
2069 evdev_remove_devices(seat_base);
2070 evdev_disable_udev_monitor(&seat->base);
2071
2072 weston_seat_release(seat_base);
2073 free(seat->seat_id);
2074 free(seat);
2075}
2076
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002077static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002078drm_free_configured_output(struct drm_configured_output *output)
2079{
2080 free(output->name);
2081 free(output->mode);
2082 free(output);
2083}
2084
2085static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002086drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002087{
2088 struct drm_compositor *d = (struct drm_compositor *) ec;
Daniel Stone37816df2012-05-16 18:45:18 +01002089 struct weston_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002090 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002091
Daniel Stone37816df2012-05-16 18:45:18 +01002092 wl_list_for_each_safe(seat, next, &ec->seat_list, link)
2093 evdev_input_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002094 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002095 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002096
2097 wl_event_source_remove(d->udev_drm_source);
2098 wl_event_source_remove(d->drm_source);
2099
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002100 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002101
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002102 /* Work around crash in egl_dri2.c's dri2_make_current() */
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002103 eglMakeCurrent(ec->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002104 EGL_NO_CONTEXT);
Kristian Høgsberg362b6722012-06-18 15:13:51 -04002105 eglTerminate(ec->egl_display);
Ander Conselvan de Oliveira5f5f3192012-04-30 13:31:28 +03002106 eglReleaseThread();
2107
Matt Roper361d2ad2011-08-29 13:52:23 -07002108 gbm_device_destroy(d->gbm);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002109 destroy_sprites(d);
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002110 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002111 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002112 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002113
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002114 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002115}
2116
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002117static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002118drm_compositor_set_modes(struct drm_compositor *compositor)
2119{
2120 struct drm_output *output;
2121 struct drm_mode *drm_mode;
2122 int ret;
2123
2124 wl_list_for_each(output, &compositor->base.output_list, base.link) {
2125 drm_mode = (struct drm_mode *) output->base.current;
2126 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002127 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002128 &output->connector_id, 1,
2129 &drm_mode->mode_info);
2130 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002131 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002132 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002133 drm_mode->base.width, drm_mode->base.height,
2134 output->base.x, output->base.y);
2135 }
2136 }
2137}
2138
2139static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002140vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002141{
2142 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Daniel Stone37816df2012-05-16 18:45:18 +01002143 struct weston_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002144 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002145 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002146
2147 switch (event) {
2148 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002149 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002150 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002151 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002152 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002153 wl_display_terminate(compositor->wl_display);
2154 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002155 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002156 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002157 weston_compositor_damage_all(compositor);
Daniel Stone37816df2012-05-16 18:45:18 +01002158 wl_list_for_each(seat, &compositor->seat_list, link) {
2159 evdev_add_devices(ec->udev, seat);
2160 evdev_enable_udev_monitor(ec->udev, seat);
Benjamin Franzke78d3afe2012-04-09 18:14:58 +02002161 }
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002162 break;
2163 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002164 weston_log("leaving VT\n");
Daniel Stone37816df2012-05-16 18:45:18 +01002165 wl_list_for_each(seat, &compositor->seat_list, link) {
2166 evdev_disable_udev_monitor(seat);
2167 evdev_remove_devices(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002168 }
2169
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002170 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002171 ec->prev_state = compositor->state;
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002172 compositor->state = WESTON_COMPOSITOR_SLEEPING;
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002173
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002174 /* If we have a repaint scheduled (either from a
2175 * pending pageflip or the idle handler), make sure we
2176 * cancel that so we don't try to pageflip when we're
2177 * vt switched away. The SLEEPING state will prevent
2178 * further attemps at repainting. When we switch
2179 * back, we schedule a repaint, which will process
2180 * pending frame callbacks. */
2181
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002182 wl_list_for_each(output, &ec->base.output_list, base.link) {
2183 output->base.repaint_needed = 0;
2184 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002185 }
2186
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002187 output = container_of(ec->base.output_list.next,
2188 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002189
2190 wl_list_for_each(sprite, &ec->sprite_list, link)
2191 drmModeSetPlane(ec->drm.fd,
2192 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002193 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002194 0, 0, 0, 0, 0, 0, 0, 0);
2195
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002196 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002197 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002198
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002199 break;
2200 };
2201}
2202
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002203static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002204switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002205{
2206 struct drm_compositor *ec = data;
2207
Daniel Stone325fc2d2012-05-30 16:31:58 +01002208 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002209}
2210
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002211static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002212drm_compositor_create(struct wl_display *display,
Daniel Stonebaf43592012-06-01 11:11:10 -04002213 int connector, const char *seat, int tty,
Daniel Stonec1be8e52012-06-01 11:14:02 -04002214 int argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002215{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002216 struct drm_compositor *ec;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002217 struct udev_enumerate *e;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002218 struct udev_list_entry *entry;
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002219 struct udev_device *device, *drm_device;
2220 const char *path, *device_seat;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002221 struct wl_event_loop *loop;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002222 struct weston_seat *weston_seat, *next;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002223 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002224
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002225 weston_log("initializing drm backend\n");
2226
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002227 ec = malloc(sizeof *ec);
2228 if (ec == NULL)
2229 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002230 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002231
2232 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002233 config_file) < 0) {
2234 weston_log("weston_compositor_init failed\n");
2235 goto err_base;
2236 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002237
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002238 ec->udev = udev_new();
2239 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002240 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002241 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002242 }
2243
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002244 ec->base.wl_display = display;
2245 ec->tty = tty_create(&ec->base, vt_func, tty);
2246 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002247 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002248 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002249 }
2250
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002251 e = udev_enumerate_new(ec->udev);
2252 udev_enumerate_add_match_subsystem(e, "drm");
Benjamin Franzkea764ee52011-10-07 08:23:22 +02002253 udev_enumerate_add_match_sysname(e, "card[0-9]*");
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002254
Benjamin Franzke117483d2011-08-30 11:38:26 +02002255 udev_enumerate_scan_devices(e);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002256 drm_device = NULL;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002257 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002258 path = udev_list_entry_get_name(entry);
2259 device = udev_device_new_from_syspath(ec->udev, path);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002260 device_seat =
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002261 udev_device_get_property_value(device, "ID_SEAT");
2262 if (!device_seat)
2263 device_seat = default_seat;
2264 if (strcmp(device_seat, seat) == 0) {
2265 drm_device = device;
2266 break;
2267 }
2268 udev_device_unref(device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002269 }
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002270
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002271 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002272 weston_log("no drm device found\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002273 goto err_udev_enum;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002274 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002275
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002276 if (init_egl(ec, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002277 weston_log("failed to initialize egl\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002278 goto err_udev_dev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002279 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002280
2281 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002282 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002283
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002284 ec->base.focus = 1;
2285
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002286 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002287
Daniel Stone725c2c32012-06-22 14:04:36 +01002288 if (weston_compositor_init_gl(&ec->base) < 0)
Daniel Stonea96b93c2012-06-22 14:04:37 +01002289 goto err_egl;
Benjamin Franzked59eb1c2011-04-29 22:14:54 +02002290
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002291 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002292 weston_compositor_add_key_binding(&ec->base, key,
2293 MODIFIER_CTRL | MODIFIER_ALT,
2294 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002295
Jesse Barnes58ef3792012-02-23 09:45:49 -05002296 wl_list_init(&ec->sprite_list);
2297 create_sprites(ec);
2298
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002299 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002300 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002301 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002302 }
2303
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002304 path = NULL;
2305
Tiago Vignattice03ec32011-12-19 01:14:03 +02002306 evdev_input_create(&ec->base, ec->udev, seat);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002307
2308 loop = wl_display_get_event_loop(ec->base.wl_display);
2309 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002310 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002311 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002312
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002313 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2314 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002315 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002316 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002317 }
2318 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2319 "drm", NULL);
2320 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002321 wl_event_loop_add_fd(loop,
2322 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002323 WL_EVENT_READABLE, udev_drm_event, ec);
2324
2325 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002326 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002327 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002328 }
2329
Daniel Stonea96b93c2012-06-22 14:04:37 +01002330 udev_device_unref(drm_device);
2331 udev_enumerate_unref(e);
2332
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002333 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002334
2335err_udev_monitor:
2336 wl_event_source_remove(ec->udev_drm_source);
2337 udev_monitor_unref(ec->udev_monitor);
2338err_drm_source:
2339 wl_event_source_remove(ec->drm_source);
2340 wl_list_for_each_safe(weston_seat, next, &ec->base.seat_list, link)
2341 evdev_input_destroy(weston_seat);
2342err_sprite:
2343 destroy_sprites(ec);
2344err_egl:
2345 eglMakeCurrent(ec->base.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
2346 EGL_NO_CONTEXT);
2347 eglTerminate(ec->base.egl_display);
2348 eglReleaseThread();
2349 gbm_device_destroy(ec->gbm);
2350err_udev_dev:
2351 udev_device_unref(drm_device);
2352err_udev_enum:
2353 udev_enumerate_unref(e);
2354 tty_destroy(ec->tty);
2355err_udev:
2356 udev_unref(ec->udev);
2357err_compositor:
2358 weston_compositor_shutdown(&ec->base);
2359err_base:
2360 free(ec);
2361 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002362}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002363
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002364static int
2365set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2366{
2367 mode->flags = 0;
2368
2369 if (strcmp(hsync, "+hsync") == 0)
2370 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2371 else if (strcmp(hsync, "-hsync") == 0)
2372 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2373 else
2374 return -1;
2375
2376 if (strcmp(vsync, "+vsync") == 0)
2377 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2378 else if (strcmp(vsync, "-vsync") == 0)
2379 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2380 else
2381 return -1;
2382
2383 return 0;
2384}
2385
2386static int
2387check_for_modeline(struct drm_configured_output *output)
2388{
2389 drmModeModeInfo mode;
2390 char hsync[16];
2391 char vsync[16];
2392 char mode_name[16];
2393 float fclock;
2394
2395 mode.type = DRM_MODE_TYPE_USERDEF;
2396 mode.hskew = 0;
2397 mode.vscan = 0;
2398 mode.vrefresh = 0;
2399
2400 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2401 &fclock, &mode.hdisplay,
2402 &mode.hsync_start,
2403 &mode.hsync_end, &mode.htotal,
2404 &mode.vdisplay,
2405 &mode.vsync_start,
2406 &mode.vsync_end, &mode.vtotal,
2407 hsync, vsync) == 11) {
2408 if (set_sync_flags(&mode, hsync, vsync))
2409 return -1;
2410
2411 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2412 strcpy(mode.name, mode_name);
2413
2414 mode.clock = fclock * 1000;
2415 } else
2416 return -1;
2417
2418 output->crtc_mode = mode;
2419
2420 return 0;
2421}
2422
Scott Moreau8ab5d452012-07-30 19:51:08 -06002423static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002424drm_output_set_transform(struct drm_configured_output *output)
2425{
2426 if (!output_transform) {
2427 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2428 return;
2429 }
2430
2431 if (!strcmp(output_transform, "normal"))
2432 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2433 else if (!strcmp(output_transform, "90"))
2434 output->transform = WL_OUTPUT_TRANSFORM_90;
2435 else if (!strcmp(output_transform, "180"))
2436 output->transform = WL_OUTPUT_TRANSFORM_180;
2437 else if (!strcmp(output_transform, "270"))
2438 output->transform = WL_OUTPUT_TRANSFORM_270;
2439 else if (!strcmp(output_transform, "flipped"))
2440 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2441 else if (!strcmp(output_transform, "flipped-90"))
2442 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2443 else if (!strcmp(output_transform, "flipped-180"))
2444 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2445 else if (!strcmp(output_transform, "flipped-270"))
2446 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2447 else {
2448 weston_log("Invalid transform \"%s\" for output %s\n",
2449 output_transform, output_name);
2450 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2451 }
2452
2453 free(output_transform);
2454 output_transform = NULL;
2455}
2456
2457static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002458output_section_done(void *data)
2459{
2460 struct drm_configured_output *output;
2461
2462 output = malloc(sizeof *output);
2463
Scott Moreau1bad5db2012-08-18 01:04:05 -06002464 if (!output || !output_name || (output_name[0] == 'X') ||
2465 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002466 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002467 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002468 free(output_transform);
2469 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002470 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002471 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002472 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002473 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002474
2475 output->config = OUTPUT_CONFIG_INVALID;
2476 output->name = output_name;
2477 output->mode = output_mode;
2478
Scott Moreau1bad5db2012-08-18 01:04:05 -06002479 if (output_mode) {
2480 if (strcmp(output_mode, "off") == 0)
2481 output->config = OUTPUT_CONFIG_OFF;
2482 else if (strcmp(output_mode, "preferred") == 0)
2483 output->config = OUTPUT_CONFIG_PREFERRED;
2484 else if (strcmp(output_mode, "current") == 0)
2485 output->config = OUTPUT_CONFIG_CURRENT;
2486 else if (sscanf(output_mode, "%dx%d",
2487 &output->width, &output->height) == 2)
2488 output->config = OUTPUT_CONFIG_MODE;
2489 else if (check_for_modeline(output) == 0)
2490 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002491
Scott Moreau1bad5db2012-08-18 01:04:05 -06002492 if (output->config == OUTPUT_CONFIG_INVALID)
2493 weston_log("Invalid mode \"%s\" for output %s\n",
2494 output_mode, output_name);
2495 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002496 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002497
2498 drm_output_set_transform(output);
2499
2500 wl_list_insert(&configured_output_list, &output->link);
2501
2502 if (output_transform)
2503 free(output_transform);
2504 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002505}
2506
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002507WL_EXPORT struct weston_compositor *
Daniel Stonec1be8e52012-06-01 11:14:02 -04002508backend_init(struct wl_display *display, int argc, char *argv[],
2509 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002510{
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002511 int connector = 0, tty = 0;
2512 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002513
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002514 const struct weston_option drm_options[] = {
2515 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2516 { WESTON_OPTION_STRING, "seat", 0, &seat },
2517 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002518 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002519 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002520
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002521 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002522
Scott Moreau8ab5d452012-07-30 19:51:08 -06002523 wl_list_init(&configured_output_list);
2524
2525 const struct config_key drm_config_keys[] = {
2526 { "name", CONFIG_KEY_STRING, &output_name },
2527 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002528 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002529 };
2530
2531 const struct config_section config_section[] = {
2532 { "output", drm_config_keys,
2533 ARRAY_LENGTH(drm_config_keys), output_section_done },
2534 };
2535
2536 parse_config_file(config_file, config_section,
2537 ARRAY_LENGTH(config_section), NULL);
2538
Daniel Stonec1be8e52012-06-01 11:14:02 -04002539 return drm_compositor_create(display, connector, seat, tty, argc, argv,
2540 config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002541}