blob: f39096e4cfd35d1dbfc0de87048d720cff33c31a [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
Richard Hughesab745622013-05-01 21:52:13 +010024#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040028#define _GNU_SOURCE
29
Jesse Barnes58ef3792012-02-23 09:45:49 -050030#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040031#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010032#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040033#include <string.h>
34#include <fcntl.h>
35#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040036#include <linux/input.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030037#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020038#include <sys/mman.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040039
Benjamin Franzkec649a922011-03-02 11:56:04 +010040#include <xf86drm.h>
41#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050042#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010043
Benjamin Franzke060cf802011-04-30 09:32:11 +020044#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020045#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040046#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020047
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040048#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010049#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020050#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050051#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010052#include "launcher-util.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Kristian Høgsberg061c4252012-06-28 11:28:15 -040054static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060055static char *output_name;
56static char *output_mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060057static char *output_transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060058static struct wl_list configured_output_list;
59
60enum output_config {
61 OUTPUT_CONFIG_INVALID = 0,
62 OUTPUT_CONFIG_OFF,
63 OUTPUT_CONFIG_PREFERRED,
64 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060065 OUTPUT_CONFIG_MODE,
66 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060067};
68
69struct drm_configured_output {
70 char *name;
71 char *mode;
Scott Moreau1bad5db2012-08-18 01:04:05 -060072 uint32_t transform;
Scott Moreau8ab5d452012-07-30 19:51:08 -060073 int32_t width, height;
Scott Moreau8f37e0b2012-07-31 15:30:41 -060074 drmModeModeInfo crtc_mode;
Scott Moreau8ab5d452012-07-30 19:51:08 -060075 enum output_config config;
76 struct wl_list link;
77};
Kristian Høgsberg061c4252012-06-28 11:28:15 -040078
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040079struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050080 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040081
82 struct udev *udev;
83 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040084
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010085 struct udev_monitor *udev_monitor;
86 struct wl_event_source *udev_drm_source;
87
Benjamin Franzke2af7f102011-03-02 11:14:59 +010088 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010089 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010090 int fd;
91 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020092 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050093 uint32_t *crtcs;
94 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050095 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010096 uint32_t connector_allocator;
Kristian Høgsberge4762a62011-01-14 14:59:13 -050097 struct tty *tty;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020098
Rob Clark4339add2012-08-09 14:18:28 -050099 /* we need these parameters in order to not fail drmModeAddFB2()
100 * due to out of bounds dimensions, and then mistakenly set
101 * sprites_are_broken:
102 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200103 uint32_t min_width, max_width;
104 uint32_t min_height, max_height;
105 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -0500106
Jesse Barnes58ef3792012-02-23 09:45:49 -0500107 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500108 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200109 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500110
Rob Clarkab5b1e32012-08-09 13:24:45 -0500111 int cursors_are_broken;
112
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200113 int use_pixman;
114
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200115 uint32_t prev_state;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400116};
117
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400118struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500119 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400120 drmModeModeInfo mode_info;
121};
122
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300123struct drm_output;
124
125struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300126 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200127 uint32_t fb_id, stride, handle, size;
128 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300129 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200130 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200131
132 /* Used by gbm fbs */
133 struct gbm_bo *bo;
134
135 /* Used by dumb fbs */
136 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300137};
138
Richard Hughes2b2092a2013-04-24 14:58:02 +0100139struct drm_edid {
140 char eisa_id[13];
141 char monitor_name[13];
142 char pnp_id[5];
143 char serial_number[13];
144};
145
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500147 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400148
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400149 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500150 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400151 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700152 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100153 struct drm_edid edid;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200154
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300155 int vblank_pending;
156 int page_flip_pending;
157
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400158 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400159 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400160 struct weston_plane cursor_plane;
161 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400162 struct weston_surface *cursor_surface;
163 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300164 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200165 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200166
167 struct drm_fb *dumb[2];
168 pixman_image_t *image[2];
169 int current_image;
170 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400171};
172
Jesse Barnes58ef3792012-02-23 09:45:49 -0500173/*
174 * An output has a primary display plane plus zero or more sprites for
175 * blending display contents.
176 */
177struct drm_sprite {
178 struct wl_list link;
179
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400180 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200182 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300183 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184 struct drm_compositor *compositor;
185
Jesse Barnes58ef3792012-02-23 09:45:49 -0500186 uint32_t possible_crtcs;
187 uint32_t plane_id;
188 uint32_t count_formats;
189
190 int32_t src_x, src_y;
191 uint32_t src_w, src_h;
192 uint32_t dest_x, dest_y;
193 uint32_t dest_w, dest_h;
194
195 uint32_t formats[];
196};
197
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500198static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400199
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400200static void
201drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400202
Jesse Barnes58ef3792012-02-23 09:45:49 -0500203static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500204drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
205{
206 struct weston_compositor *ec = output_base->compositor;
207 struct drm_compositor *c =(struct drm_compositor *) ec;
208 struct drm_output *output = (struct drm_output *) output_base;
209 int crtc;
210
211 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
212 if (c->crtcs[crtc] != output->crtc_id)
213 continue;
214
215 if (supported & (1 << crtc))
216 return -1;
217 }
218
219 return 0;
220}
221
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300222static void
223drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
224{
225 struct drm_fb *fb = data;
226 struct gbm_device *gbm = gbm_bo_get_device(bo);
227
228 if (fb->fb_id)
229 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
230
Pekka Paalanende685b82012-12-04 15:58:12 +0200231 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300232
233 free(data);
234}
235
236static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200237drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
238{
239 struct drm_fb *fb;
240 int ret;
241
242 struct drm_mode_create_dumb create_arg;
243 struct drm_mode_destroy_dumb destroy_arg;
244 struct drm_mode_map_dumb map_arg;
245
246 fb = calloc(1, sizeof *fb);
247 if (!fb)
248 return NULL;
249
250 create_arg.bpp = 32;
251 create_arg.width = width;
252 create_arg.height = height;
253
254 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
255 if (ret)
256 goto err_fb;
257
258 fb->handle = create_arg.handle;
259 fb->stride = create_arg.pitch;
260 fb->size = create_arg.size;
261 fb->fd = ec->drm.fd;
262
263 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
264 fb->stride, fb->handle, &fb->fb_id);
265 if (ret)
266 goto err_bo;
267
268 memset(&map_arg, 0, sizeof(map_arg));
269 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400270 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200271 if (ret)
272 goto err_add_fb;
273
274 fb->map = mmap(0, fb->size, PROT_WRITE,
275 MAP_SHARED, ec->drm.fd, map_arg.offset);
276 if (fb->map == MAP_FAILED)
277 goto err_add_fb;
278
279 return fb;
280
281err_add_fb:
282 drmModeRmFB(ec->drm.fd, fb->fb_id);
283err_bo:
284 memset(&destroy_arg, 0, sizeof(destroy_arg));
285 destroy_arg.handle = create_arg.handle;
286 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
287err_fb:
288 free(fb);
289 return NULL;
290}
291
292static void
293drm_fb_destroy_dumb(struct drm_fb *fb)
294{
295 struct drm_mode_destroy_dumb destroy_arg;
296
297 if (!fb->map)
298 return;
299
300 if (fb->fb_id)
301 drmModeRmFB(fb->fd, fb->fb_id);
302
303 weston_buffer_reference(&fb->buffer_ref, NULL);
304
305 munmap(fb->map, fb->size);
306
307 memset(&destroy_arg, 0, sizeof(destroy_arg));
308 destroy_arg.handle = fb->handle;
309 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
310
311 free(fb);
312}
313
314static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500315drm_fb_get_from_bo(struct gbm_bo *bo,
316 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300317{
318 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200319 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200320 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300321 int ret;
322
323 if (fb)
324 return fb;
325
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200326 fb = calloc(1, sizeof *fb);
327 if (!fb)
328 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329
330 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331
332 width = gbm_bo_get_width(bo);
333 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200334 fb->stride = gbm_bo_get_stride(bo);
335 fb->handle = gbm_bo_get_handle(bo).u32;
336 fb->size = fb->stride * height;
337 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300338
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200339 if (compositor->min_width > width || width > compositor->max_width ||
340 compositor->min_height > height ||
341 height > compositor->max_height) {
342 weston_log("bo geometry out of bounds\n");
343 goto err_free;
344 }
345
346 ret = -1;
347
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200348 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200349 handles[0] = fb->handle;
350 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200351 offsets[0] = 0;
352
353 ret = drmModeAddFB2(compositor->drm.fd, width, height,
354 format, handles, pitches, offsets,
355 &fb->fb_id, 0);
356 if (ret) {
357 weston_log("addfb2 failed: %m\n");
358 compositor->no_addfb2 = 1;
359 compositor->sprites_are_broken = 1;
360 }
361 }
362
363 if (ret)
364 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200365 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200366
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200368 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200369 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300370 }
371
372 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
373
374 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200375
376err_free:
377 free(fb);
378 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300379}
380
381static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200382drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
383{
Pekka Paalanende685b82012-12-04 15:58:12 +0200384 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
386 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200387
Pekka Paalanende685b82012-12-04 15:58:12 +0200388 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200389}
390
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200391static void
392drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
393{
394 if (!fb)
395 return;
396
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200397 if (fb->map &&
398 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200399 drm_fb_destroy_dumb(fb);
400 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200401 if (fb->is_client_buffer)
402 gbm_bo_destroy(fb->bo);
403 else
404 gbm_surface_release_buffer(output->surface,
405 output->current->bo);
406 }
407}
408
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500409static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200410drm_output_check_scanout_format(struct drm_output *output,
411 struct weston_surface *es, struct gbm_bo *bo)
412{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200413 uint32_t format;
414 pixman_region32_t r;
415
416 format = gbm_bo_get_format(bo);
417
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500418 switch (format) {
419 case GBM_FORMAT_XRGB8888:
420 return format;
421 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200422 /* We can only scanout an ARGB buffer if the surface's
423 * opaque region covers the whole output */
424 pixman_region32_init(&r);
425 pixman_region32_subtract(&r, &output->base.region,
426 &es->opaque);
427
428 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500429 format = GBM_FORMAT_XRGB8888;
430 else
431 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200432
433 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500435 return format;
436 default:
437 return 0;
438 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200439}
440
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400441static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400442drm_output_prepare_scanout_surface(struct weston_output *_output,
443 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500444{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400445 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500446 struct drm_compositor *c =
447 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200448 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300449 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500450 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500451
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500452 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200453 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200454 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200455 buffer->width != output->base.current->width ||
456 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200457 output->base.transform != es->buffer_transform ||
458 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400459 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500460
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400461 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200462 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500463
Rob Bradford9b101872012-09-14 23:25:41 +0100464 /* Unable to use the buffer for scanout */
465 if (!bo)
466 return NULL;
467
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500468 format = drm_output_check_scanout_format(output, es, bo);
469 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300470 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400471 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300472 }
473
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500474 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300475 if (!output->next) {
476 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400477 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300478 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500479
Pekka Paalanende685b82012-12-04 15:58:12 +0200480 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500481
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400482 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500483}
484
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500485static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200486drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400487{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200488 struct drm_compositor *c =
489 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300490 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400491
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200492 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400493
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300494 bo = gbm_surface_lock_front_buffer(output->surface);
495 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200496 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400497 return;
498 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500500 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200502 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 gbm_surface_release_buffer(output->surface, bo);
504 return;
505 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400506}
507
508static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200509drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
510{
511 struct weston_compositor *ec = output->base.compositor;
512 pixman_region32_t total_damage, previous_damage;
513
514 pixman_region32_init(&total_damage);
515 pixman_region32_init(&previous_damage);
516
517 pixman_region32_copy(&previous_damage, damage);
518
519 pixman_region32_union(&total_damage, damage, &output->previous_damage);
520 pixman_region32_copy(&output->previous_damage, &previous_damage);
521
522 output->current_image ^= 1;
523
524 output->next = output->dumb[output->current_image];
525 pixman_renderer_output_set_buffer(&output->base,
526 output->image[output->current_image]);
527
528 ec->renderer->repaint_output(&output->base, &total_damage);
529
530 pixman_region32_fini(&total_damage);
531 pixman_region32_fini(&previous_damage);
532}
533
534static void
535drm_output_render(struct drm_output *output, pixman_region32_t *damage)
536{
537 struct drm_compositor *c =
538 (struct drm_compositor *) output->base.compositor;
539
540 if (c->use_pixman)
541 drm_output_render_pixman(output, damage);
542 else
543 drm_output_render_gl(output, damage);
544
545 pixman_region32_subtract(&c->base.primary_plane.damage,
546 &c->base.primary_plane.damage, damage);
547}
548
549static void
Richard Hughese7299962013-05-01 21:52:12 +0100550drm_output_set_gamma(struct weston_output *output_base,
551 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
552{
553 int rc;
554 struct drm_output *output = (struct drm_output *) output_base;
555 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
556
557 /* check */
558 if (output_base->gamma_size != size)
559 return;
560 if (!output->original_crtc)
561 return;
562
563 rc = drmModeCrtcSetGamma(compositor->drm.fd,
564 output->crtc_id,
565 size, r, g, b);
566 if (rc)
567 weston_log("set gamma failed: %m\n");
568}
569
570static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500571drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400572 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100573{
574 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500575 struct drm_compositor *compositor =
576 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400578 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500579 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100580
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300581 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400582 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300583 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400584 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100585
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400586 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300587 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400588 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300589 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400590 &output->connector_id, 1,
591 &mode->mode_info);
592 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200593 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400594 return;
595 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200596 }
597
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500598 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300599 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500600 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200601 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500602 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500603 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100604
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300605 output->page_flip_pending = 1;
606
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400607 drm_output_set_cursor(output);
608
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609 /*
610 * Now, update all the sprite surfaces
611 */
612 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200613 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500614 drmVBlank vbl = {
615 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
616 .request.sequence = 1,
617 };
618
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200619 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200620 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 continue;
622
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200623 if (s->next && !compositor->sprites_hidden)
624 fb_id = s->next->fb_id;
625
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200627 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628 s->dest_x, s->dest_y,
629 s->dest_w, s->dest_h,
630 s->src_x, s->src_y,
631 s->src_w, s->src_h);
632 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200633 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 ret, strerror(errno));
635
Rob Clark5ca1a472012-08-08 20:27:37 -0500636 if (output->pipe > 0)
637 vbl.request.type |= DRM_VBLANK_SECONDARY;
638
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 /*
640 * Queue a vblank signal so we know when the surface
641 * becomes active on the display or has been replaced.
642 */
643 vbl.request.signal = (unsigned long)s;
644 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
645 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200646 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 ret, strerror(errno));
648 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300649
650 s->output = output;
651 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 }
653
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500654 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400655}
656
657static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200658drm_output_start_repaint_loop(struct weston_output *output_base)
659{
660 struct drm_output *output = (struct drm_output *) output_base;
661 struct drm_compositor *compositor = (struct drm_compositor *)
662 output_base->compositor;
663 uint32_t fb_id;
664
665 if (output->current)
666 fb_id = output->current->fb_id;
667 else
668 fb_id = output->original_crtc->buffer_id;
669
670 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
671 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
672 weston_log("queueing pageflip failed: %m\n");
673 return;
674 }
675}
676
677static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500678vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
679 void *data)
680{
681 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300682 struct drm_output *output = s->output;
683 uint32_t msecs;
684
685 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500686
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200687 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200688 s->current = s->next;
689 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300690
691 if (!output->page_flip_pending) {
692 msecs = sec * 1000 + usec / 1000;
693 weston_output_finish_frame(&output->base, msecs);
694 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500695}
696
697static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400698page_flip_handler(int fd, unsigned int frame,
699 unsigned int sec, unsigned int usec, void *data)
700{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200701 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400702 uint32_t msecs;
703
Jonas Ådahle5a12252013-04-05 23:07:11 +0200704 /* We don't set page_flip_pending on start_repaint_loop, in that case
705 * we just want to page flip to the current buffer to get an accurate
706 * timestamp */
707 if (output->page_flip_pending) {
708 drm_output_release_fb(output, output->current);
709 output->current = output->next;
710 output->next = NULL;
711 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300712
Jonas Ådahle5a12252013-04-05 23:07:11 +0200713 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400714
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300715 if (!output->vblank_pending) {
716 msecs = sec * 1000 + usec / 1000;
717 weston_output_finish_frame(&output->base, msecs);
718 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200719}
720
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500721static uint32_t
722drm_output_check_sprite_format(struct drm_sprite *s,
723 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500724{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500725 uint32_t i, format;
726
727 format = gbm_bo_get_format(bo);
728
729 if (format == GBM_FORMAT_ARGB8888) {
730 pixman_region32_t r;
731
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500732 pixman_region32_init_rect(&r, 0, 0,
733 es->geometry.width,
734 es->geometry.height);
735 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500736
737 if (!pixman_region32_not_empty(&r))
738 format = GBM_FORMAT_XRGB8888;
739
740 pixman_region32_fini(&r);
741 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500742
743 for (i = 0; i < s->count_formats; i++)
744 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500745 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500746
747 return 0;
748}
749
750static int
751drm_surface_transform_supported(struct weston_surface *es)
752{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500753 return !es->transform.enabled ||
754 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500755}
756
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400757static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500758drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400759 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760{
761 struct weston_compositor *ec = output_base->compositor;
762 struct drm_compositor *c =(struct drm_compositor *) ec;
763 struct drm_sprite *s;
764 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500765 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500766 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200767 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400769 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200771 if (c->gbm == NULL)
772 return NULL;
773
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200774 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200775 return NULL;
776
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500777 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400778 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500779
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300780 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400781 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300782
Pekka Paalanende685b82012-12-04 15:58:12 +0200783 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400784 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500785
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200786 if (es->alpha != 1.0f)
787 return NULL;
788
Pekka Paalanende685b82012-12-04 15:58:12 +0200789 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500790 return NULL;
791
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400793 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500794
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795 wl_list_for_each(s, &c->sprite_list, link) {
796 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
797 continue;
798
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200799 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500800 found = 1;
801 break;
802 }
803 }
804
805 /* No sprites available */
806 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400807 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500808
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400809 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200810 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400811 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400812 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400813
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500814 format = drm_output_check_sprite_format(s, es, bo);
815 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200816 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400817 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500818 }
819
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200820 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200821 if (!s->next) {
822 gbm_bo_destroy(bo);
823 return NULL;
824 }
825
Pekka Paalanende685b82012-12-04 15:58:12 +0200826 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500827
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400828 box = pixman_region32_extents(&es->transform.boundingbox);
829 s->plane.x = box->x1;
830 s->plane.y = box->y1;
831
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832 /*
833 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200834 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500835 * for us already).
836 */
837 pixman_region32_init(&dest_rect);
838 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
839 &output_base->region);
840 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
841 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200842 tbox = weston_transformed_rect(output_base->width,
843 output_base->height,
844 output_base->transform, *box);
845 s->dest_x = tbox.x1;
846 s->dest_y = tbox.y1;
847 s->dest_w = tbox.x2 - tbox.x1;
848 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500849 pixman_region32_fini(&dest_rect);
850
851 pixman_region32_init(&src_rect);
852 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
853 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500854 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400855
856 weston_surface_from_global_fixed(es,
857 wl_fixed_from_int(box->x1),
858 wl_fixed_from_int(box->y1),
859 &sx1, &sy1);
860 weston_surface_from_global_fixed(es,
861 wl_fixed_from_int(box->x2),
862 wl_fixed_from_int(box->y2),
863 &sx2, &sy2);
864
865 if (sx1 < 0)
866 sx1 = 0;
867 if (sy1 < 0)
868 sy1 = 0;
869 if (sx2 > wl_fixed_from_int(es->geometry.width))
870 sx2 = wl_fixed_from_int(es->geometry.width);
871 if (sy2 > wl_fixed_from_int(es->geometry.height))
872 sy2 = wl_fixed_from_int(es->geometry.height);
873
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200874 tbox.x1 = sx1;
875 tbox.y1 = sy1;
876 tbox.x2 = sx2;
877 tbox.y2 = sy2;
878
879 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
880 wl_fixed_from_int(es->geometry.height),
881 es->buffer_transform, tbox);
882
883 s->src_x = tbox.x1 << 8;
884 s->src_y = tbox.y1 << 8;
885 s->src_w = (tbox.x2 - tbox.x1) << 8;
886 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500887 pixman_region32_fini(&src_rect);
888
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400889 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500890}
891
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400892static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400893drm_output_prepare_cursor_surface(struct weston_output *output_base,
894 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500895{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400896 struct drm_compositor *c =
897 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400898 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400899
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200900 if (c->gbm == NULL)
901 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200902 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
903 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400904 if (output->cursor_surface)
905 return NULL;
906 if (es->output_mask != (1u << output_base->id))
907 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500908 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400909 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200910 if (es->buffer_ref.buffer == NULL ||
911 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400912 es->geometry.width > 64 || es->geometry.height > 64)
913 return NULL;
914
915 output->cursor_surface = es;
916
917 return &output->cursor_plane;
918}
919
920static void
921drm_output_set_cursor(struct drm_output *output)
922{
923 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400924 struct drm_compositor *c =
925 (struct drm_compositor *) output->base.compositor;
926 EGLint handle, stride;
927 struct gbm_bo *bo;
928 uint32_t buf[64 * 64];
929 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400930 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500931
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400932 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400933 if (es == NULL) {
934 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
935 return;
936 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500937
Pekka Paalanende685b82012-12-04 15:58:12 +0200938 if (es->buffer_ref.buffer &&
939 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400940 pixman_region32_fini(&output->cursor_plane.damage);
941 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400942 output->current_cursor ^= 1;
943 bo = output->cursor_bo[output->current_cursor];
944 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200945 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
946 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400947 for (i = 0; i < es->geometry.height; i++)
948 memcpy(buf + i * 64, s + i * stride,
949 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500950
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400951 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300952 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400953
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400954 handle = gbm_bo_get_handle(bo).s32;
955 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500956 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300957 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500958 c->cursors_are_broken = 1;
959 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400960 }
961
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400962 x = es->geometry.x - output->base.x;
963 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400964 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500965 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400966 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500967 c->cursors_are_broken = 1;
968 }
969
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400970 output->cursor_plane.x = x;
971 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400972 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500973}
974
Jesse Barnes58ef3792012-02-23 09:45:49 -0500975static void
976drm_assign_planes(struct weston_output *output)
977{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400978 struct drm_compositor *c =
979 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400980 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500981 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400982 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500983
984 /*
985 * Find a surface for each sprite in the output using some heuristics:
986 * 1) size
987 * 2) frequency of update
988 * 3) opacity (though some hw might support alpha blending)
989 * 4) clipping (this can be fixed with color keys)
990 *
991 * The idea is to save on blitting since this should save power.
992 * If we can get a large video surface on the sprite for example,
993 * the main display surface may not need to update at all, and
994 * the client buffer can be used directly for the sprite surface
995 * as we do for flipping full screen surfaces.
996 */
997 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400998 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400999 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001000 /* test whether this buffer can ever go into a plane:
1001 * non-shm, or small enough to be a cursor
1002 */
1003 if ((es->buffer_ref.buffer &&
1004 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1005 (es->geometry.width <= 64 && es->geometry.height <= 64))
1006 es->keep_buffer = 1;
1007 else
1008 es->keep_buffer = 0;
1009
Jesse Barnes58ef3792012-02-23 09:45:49 -05001010 pixman_region32_init(&surface_overlap);
1011 pixman_region32_intersect(&surface_overlap, &overlap,
1012 &es->transform.boundingbox);
1013
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001014 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001015 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001016 next_plane = primary;
1017 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001018 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001019 if (next_plane == NULL)
1020 next_plane = drm_output_prepare_scanout_surface(output, es);
1021 if (next_plane == NULL)
1022 next_plane = drm_output_prepare_overlay_surface(output, es);
1023 if (next_plane == NULL)
1024 next_plane = primary;
1025 weston_surface_move_to_plane(es, next_plane);
1026 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001027 pixman_region32_union(&overlap, &overlap,
1028 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001029
Jesse Barnes58ef3792012-02-23 09:45:49 -05001030 pixman_region32_fini(&surface_overlap);
1031 }
1032 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001033}
1034
Matt Roper361d2ad2011-08-29 13:52:23 -07001035static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001036drm_output_fini_pixman(struct drm_output *output);
1037
1038static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001039drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001040{
1041 struct drm_output *output = (struct drm_output *) output_base;
1042 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001043 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001044 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001045
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001046 if (output->backlight)
1047 backlight_destroy(output->backlight);
1048
Matt Roper361d2ad2011-08-29 13:52:23 -07001049 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001050 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001051
1052 /* Restore original CRTC state */
1053 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001054 origcrtc->x, origcrtc->y,
1055 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001056 drmModeFreeCrtc(origcrtc);
1057
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001058 c->crtc_allocator &= ~(1 << output->crtc_id);
1059 c->connector_allocator &= ~(1 << output->connector_id);
1060
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001061 if (c->use_pixman) {
1062 drm_output_fini_pixman(output);
1063 } else {
1064 gl_renderer_output_destroy(output_base);
1065 gbm_surface_destroy(output->surface);
1066 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001067
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001068 weston_plane_release(&output->fb_plane);
1069 weston_plane_release(&output->cursor_plane);
1070
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001071 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001072 wl_list_remove(&output->base.link);
1073
Matt Roper361d2ad2011-08-29 13:52:23 -07001074 free(output);
1075}
1076
Alex Wub7b8bda2012-04-17 17:20:48 +08001077static struct drm_mode *
1078choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1079{
1080 struct drm_mode *tmp_mode = NULL, *mode;
1081
1082 if (output->base.current->width == target_mode->width &&
1083 output->base.current->height == target_mode->height &&
1084 (output->base.current->refresh == target_mode->refresh ||
1085 target_mode->refresh == 0))
1086 return (struct drm_mode *)output->base.current;
1087
1088 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1089 if (mode->mode_info.hdisplay == target_mode->width &&
1090 mode->mode_info.vdisplay == target_mode->height) {
1091 if (mode->mode_info.vrefresh == target_mode->refresh ||
1092 target_mode->refresh == 0) {
1093 return mode;
1094 } else if (!tmp_mode)
1095 tmp_mode = mode;
1096 }
1097 }
1098
1099 return tmp_mode;
1100}
1101
1102static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001103drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001104static int
1105drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001106
1107static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001108drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1109{
1110 struct drm_output *output;
1111 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001112 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001113
1114 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001115 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001116 return -1;
1117 }
1118
1119 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001120 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001121 return -1;
1122 }
1123
1124 ec = (struct drm_compositor *)output_base->compositor;
1125 output = (struct drm_output *)output_base;
1126 drm_mode = choose_mode (output, mode);
1127
1128 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001129 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001130 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001131 }
1132
1133 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001134 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001135
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001136 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001137
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001138 output->base.current = &drm_mode->base;
1139 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001140 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1141
Alex Wub7b8bda2012-04-17 17:20:48 +08001142 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001143 drm_output_release_fb(output, output->current);
1144 drm_output_release_fb(output, output->next);
1145 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001146
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001147 if (ec->use_pixman) {
1148 drm_output_fini_pixman(output);
1149 if (drm_output_init_pixman(output, ec) < 0) {
1150 weston_log("failed to init output pixman state with "
1151 "new mode\n");
1152 return -1;
1153 }
1154 } else {
1155 gl_renderer_output_destroy(&output->base);
1156 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001157
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001158 if (drm_output_init_egl(output, ec) < 0) {
1159 weston_log("failed to init output egl state with "
1160 "new mode");
1161 return -1;
1162 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001163 }
1164
Alex Wub7b8bda2012-04-17 17:20:48 +08001165 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001166}
1167
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001168static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001169on_drm_input(int fd, uint32_t mask, void *data)
1170{
1171 drmEventContext evctx;
1172
1173 memset(&evctx, 0, sizeof evctx);
1174 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1175 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001176 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001177 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001178
1179 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001180}
1181
1182static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001183init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001184{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001185 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001186 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001187
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001188 sysnum = udev_device_get_sysnum(device);
1189 if (sysnum)
1190 ec->drm.id = atoi(sysnum);
1191 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001192 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001193 return -1;
1194 }
1195
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001196 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001197 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001198 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001199 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001200 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001201 udev_device_get_devnode(device));
1202 return -1;
1203 }
1204
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001205 weston_log("using %s\n", filename);
1206
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001207 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001208
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001209
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001210 return 0;
1211}
1212
1213static int
1214init_egl(struct drm_compositor *ec)
1215{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001216 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001217
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001218 if (!ec->gbm)
1219 return -1;
1220
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001221 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001222 NULL) < 0) {
1223 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001224 return -1;
1225 }
1226
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001227 return 0;
1228}
1229
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001230static int
1231init_pixman(struct drm_compositor *ec)
1232{
1233 return pixman_renderer_init(&ec->base);
1234}
1235
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001236static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001237drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1238{
1239 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001240 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001241
1242 mode = malloc(sizeof *mode);
1243 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001244 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001245
1246 mode->base.flags = 0;
1247 mode->base.width = info->hdisplay;
1248 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001249
1250 /* Calculate higher precision (mHz) refresh rate */
1251 refresh = (info->clock * 1000000LL / info->htotal +
1252 info->vtotal / 2) / info->vtotal;
1253
1254 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1255 refresh *= 2;
1256 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1257 refresh /= 2;
1258 if (info->vscan > 1)
1259 refresh /= info->vscan;
1260
1261 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001262 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001263
1264 if (info->type & DRM_MODE_TYPE_PREFERRED)
1265 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1266
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001267 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1268
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001269 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001270}
1271
1272static int
1273drm_subpixel_to_wayland(int drm_value)
1274{
1275 switch (drm_value) {
1276 default:
1277 case DRM_MODE_SUBPIXEL_UNKNOWN:
1278 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1279 case DRM_MODE_SUBPIXEL_NONE:
1280 return WL_OUTPUT_SUBPIXEL_NONE;
1281 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1282 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1283 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1284 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1285 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1286 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1287 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1288 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1289 }
1290}
1291
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001292/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001293static uint32_t
1294drm_get_backlight(struct drm_output *output)
1295{
1296 long brightness, max_brightness, norm;
1297
1298 brightness = backlight_get_brightness(output->backlight);
1299 max_brightness = backlight_get_max_brightness(output->backlight);
1300
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001301 /* convert it on a scale of 0 to 255 */
1302 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001303
1304 return (uint32_t) norm;
1305}
1306
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001307/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001308static void
1309drm_set_backlight(struct weston_output *output_base, uint32_t value)
1310{
1311 struct drm_output *output = (struct drm_output *) output_base;
1312 long max_brightness, new_brightness;
1313
1314 if (!output->backlight)
1315 return;
1316
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001317 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001318 return;
1319
1320 max_brightness = backlight_get_max_brightness(output->backlight);
1321
1322 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001323 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001324
1325 backlight_set_brightness(output->backlight, new_brightness);
1326}
1327
1328static drmModePropertyPtr
1329drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1330{
1331 drmModePropertyPtr props;
1332 int i;
1333
1334 for (i = 0; i < connector->count_props; i++) {
1335 props = drmModeGetProperty(fd, connector->props[i]);
1336 if (!props)
1337 continue;
1338
1339 if (!strcmp(props->name, name))
1340 return props;
1341
1342 drmModeFreeProperty(props);
1343 }
1344
1345 return NULL;
1346}
1347
1348static void
1349drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1350{
1351 struct drm_output *output = (struct drm_output *) output_base;
1352 struct weston_compositor *ec = output_base->compositor;
1353 struct drm_compositor *c = (struct drm_compositor *) ec;
1354 drmModeConnectorPtr connector;
1355 drmModePropertyPtr prop;
1356
1357 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1358 if (!connector)
1359 return;
1360
1361 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1362 if (!prop) {
1363 drmModeFreeConnector(connector);
1364 return;
1365 }
1366
1367 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1368 prop->prop_id, level);
1369 drmModeFreeProperty(prop);
1370 drmModeFreeConnector(connector);
1371}
1372
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001373static const char *connector_type_names[] = {
1374 "None",
1375 "VGA",
1376 "DVI",
1377 "DVI",
1378 "DVI",
1379 "Composite",
1380 "TV",
1381 "LVDS",
1382 "CTV",
1383 "DIN",
1384 "DP",
1385 "HDMI",
1386 "HDMI",
1387 "TV",
1388 "eDP",
1389};
1390
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001391static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001392find_crtc_for_connector(struct drm_compositor *ec,
1393 drmModeRes *resources, drmModeConnector *connector)
1394{
1395 drmModeEncoder *encoder;
1396 uint32_t possible_crtcs;
1397 int i, j;
1398
1399 for (j = 0; j < connector->count_encoders; j++) {
1400 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1401 if (encoder == NULL) {
1402 weston_log("Failed to get encoder.\n");
1403 return -1;
1404 }
1405 possible_crtcs = encoder->possible_crtcs;
1406 drmModeFreeEncoder(encoder);
1407
1408 for (i = 0; i < resources->count_crtcs; i++) {
1409 if (possible_crtcs & (1 << i) &&
1410 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1411 return i;
1412 }
1413 }
1414
1415 return -1;
1416}
1417
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001418/* Init output state that depends on gl or gbm */
1419static int
1420drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1421{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001422 int i, flags;
1423
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001424 output->surface = gbm_surface_create(ec->gbm,
1425 output->base.current->width,
1426 output->base.current->height,
1427 GBM_FORMAT_XRGB8888,
1428 GBM_BO_USE_SCANOUT |
1429 GBM_BO_USE_RENDERING);
1430 if (!output->surface) {
1431 weston_log("failed to create gbm surface\n");
1432 return -1;
1433 }
1434
1435 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001436 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001437 gbm_surface_destroy(output->surface);
1438 return -1;
1439 }
1440
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001441 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1442
1443 for (i = 0; i < 2; i++) {
1444 if (output->cursor_bo[i])
1445 continue;
1446
1447 output->cursor_bo[i] =
1448 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1449 flags);
1450 }
1451
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001452 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1453 weston_log("cursor buffers unavailable, using gl cursors\n");
1454 ec->cursors_are_broken = 1;
1455 }
1456
1457 return 0;
1458}
1459
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001460static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001461drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1462{
1463 int w = output->base.current->width;
1464 int h = output->base.current->height;
1465 unsigned int i;
1466
1467 /* FIXME error checking */
1468
1469 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1470 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1471 if (!output->dumb[i])
1472 goto err;
1473
1474 output->image[i] =
1475 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1476 output->dumb[i]->map,
1477 output->dumb[i]->stride);
1478 if (!output->image[i])
1479 goto err;
1480 }
1481
1482 if (pixman_renderer_output_create(&output->base) < 0)
1483 goto err;
1484
1485 pixman_region32_init_rect(&output->previous_damage,
1486 output->base.x, output->base.y, w, h);
1487
1488 return 0;
1489
1490err:
1491 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1492 if (output->dumb[i])
1493 drm_fb_destroy_dumb(output->dumb[i]);
1494 if (output->image[i])
1495 pixman_image_unref(output->image[i]);
1496
1497 output->dumb[i] = NULL;
1498 output->image[i] = NULL;
1499 }
1500
1501 return -1;
1502}
1503
1504static void
1505drm_output_fini_pixman(struct drm_output *output)
1506{
1507 unsigned int i;
1508
1509 pixman_renderer_output_destroy(&output->base);
1510 pixman_region32_fini(&output->previous_damage);
1511
1512 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1513 drm_fb_destroy_dumb(output->dumb[i]);
1514 pixman_image_unref(output->image[i]);
1515 output->dumb[i] = NULL;
1516 output->image[i] = NULL;
1517 }
1518}
1519
Richard Hughes2b2092a2013-04-24 14:58:02 +01001520static void
1521edid_parse_string(const uint8_t *data, char text[])
1522{
1523 int i;
1524 int replaced = 0;
1525
1526 /* this is always 12 bytes, but we can't guarantee it's null
1527 * terminated or not junk. */
1528 strncpy(text, (const char *) data, 12);
1529
1530 /* remove insane chars */
1531 for (i = 0; text[i] != '\0'; i++) {
1532 if (text[i] == '\n' ||
1533 text[i] == '\r') {
1534 text[i] = '\0';
1535 break;
1536 }
1537 }
1538
1539 /* ensure string is printable */
1540 for (i = 0; text[i] != '\0'; i++) {
1541 if (!isprint(text[i])) {
1542 text[i] = '-';
1543 replaced++;
1544 }
1545 }
1546
1547 /* if the string is random junk, ignore the string */
1548 if (replaced > 4)
1549 text[0] = '\0';
1550}
1551
1552#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1553#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1554#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1555#define EDID_OFFSET_DATA_BLOCKS 0x36
1556#define EDID_OFFSET_LAST_BLOCK 0x6c
1557#define EDID_OFFSET_PNPID 0x08
1558#define EDID_OFFSET_SERIAL 0x0c
1559
1560static int
1561edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1562{
1563 int i;
1564 uint32_t serial_number;
1565
1566 /* check header */
1567 if (length < 128)
1568 return -1;
1569 if (data[0] != 0x00 || data[1] != 0xff)
1570 return -1;
1571
1572 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1573 * /--08--\/--09--\
1574 * 7654321076543210
1575 * |\---/\---/\---/
1576 * R C1 C2 C3 */
1577 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1578 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1579 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1580 edid->pnp_id[3] = '\0';
1581
1582 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1583 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1584 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1585 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1586 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1587 if (serial_number > 0)
1588 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1589
1590 /* parse EDID data */
1591 for (i = EDID_OFFSET_DATA_BLOCKS;
1592 i <= EDID_OFFSET_LAST_BLOCK;
1593 i += 18) {
1594 /* ignore pixel clock data */
1595 if (data[i] != 0)
1596 continue;
1597 if (data[i+2] != 0)
1598 continue;
1599
1600 /* any useful blocks? */
1601 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1602 edid_parse_string(&data[i+5],
1603 edid->monitor_name);
1604 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1605 edid_parse_string(&data[i+5],
1606 edid->serial_number);
1607 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1608 edid_parse_string(&data[i+5],
1609 edid->eisa_id);
1610 }
1611 }
1612 return 0;
1613}
1614
1615static void
1616find_and_parse_output_edid(struct drm_compositor *ec,
1617 struct drm_output *output,
1618 drmModeConnector *connector)
1619{
1620 drmModePropertyBlobPtr edid_blob = NULL;
1621 drmModePropertyPtr property;
1622 int i;
1623 int rc;
1624
1625 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1626 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1627 if (!property)
1628 continue;
1629 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1630 !strcmp(property->name, "EDID")) {
1631 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1632 connector->prop_values[i]);
1633 }
1634 drmModeFreeProperty(property);
1635 }
1636 if (!edid_blob)
1637 return;
1638
1639 rc = edid_parse(&output->edid,
1640 edid_blob->data,
1641 edid_blob->length);
1642 if (!rc) {
1643 weston_log("EDID data '%s', '%s', '%s'\n",
1644 output->edid.pnp_id,
1645 output->edid.monitor_name,
1646 output->edid.serial_number);
1647 if (output->edid.pnp_id[0] != '\0')
1648 output->base.make = output->edid.pnp_id;
1649 if (output->edid.monitor_name[0] != '\0')
1650 output->base.model = output->edid.monitor_name;
1651 if (output->edid.serial_number[0] != '\0')
1652 output->base.serial_number = output->edid.serial_number;
1653 }
1654 drmModeFreePropertyBlob(edid_blob);
1655}
1656
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001657static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001658create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001659 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001660 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001661 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001662{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001663 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001664 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1665 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001666 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001667 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001668 drmModeModeInfo crtc_mode;
1669 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001670 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001671 char name[32];
1672 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001673
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001674 i = find_crtc_for_connector(ec, resources, connector);
1675 if (i < 0) {
1676 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001677 return -1;
1678 }
1679
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001680 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001681 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001682 return -1;
1683
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001684 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001685 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1686 output->base.make = "unknown";
1687 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001688 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001689 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001690
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001691 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1692 type_name = connector_type_names[connector->connector_type];
1693 else
1694 type_name = "UNKNOWN";
1695 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001696 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001697
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001698 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001699 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001700 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001701 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001702 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001703
Matt Roper361d2ad2011-08-29 13:52:23 -07001704 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1705
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001706 /* Get the current mode on the crtc that's currently driving
1707 * this connector. */
1708 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001709 memset(&crtc_mode, 0, sizeof crtc_mode);
1710 if (encoder != NULL) {
1711 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1712 drmModeFreeEncoder(encoder);
1713 if (crtc == NULL)
1714 goto err_free;
1715 if (crtc->mode_valid)
1716 crtc_mode = crtc->mode;
1717 drmModeFreeCrtc(crtc);
1718 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001719
David Herrmann0f0d54e2011-12-08 17:05:45 +01001720 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001721 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1722 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001723 goto err_free;
1724 }
1725
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001726 preferred = NULL;
1727 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001728 configured = NULL;
1729
1730 wl_list_for_each(temp, &configured_output_list, link) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001731 if (strcmp(temp->name, output->base.name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001732 if (temp->mode)
1733 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001734 temp->name, temp->mode);
1735 o = temp;
1736 break;
1737 }
1738 }
1739
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001740 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001741 weston_log("Disabling output %s\n", o->name);
1742
1743 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1744 0, 0, 0, 0, 0, NULL);
1745 goto err_free;
1746 }
1747
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001748 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001749 if (o && o->config == OUTPUT_CONFIG_MODE &&
1750 o->width == drm_mode->base.width &&
1751 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001752 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001753 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001754 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001755 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001756 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001757 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001758
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001759 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001760 configured = drm_output_add_mode(output, &o->crtc_mode);
1761 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001762 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001763 current = configured;
1764 }
1765
Wang Quanxianacb805a2012-07-30 18:09:46 -04001766 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001767 current = drm_output_add_mode(output, &crtc_mode);
1768 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001769 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001770 }
1771
Scott Moreau8ab5d452012-07-30 19:51:08 -06001772 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1773 configured = current;
1774
Wang Quanxianacb805a2012-07-30 18:09:46 -04001775 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001776 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001777 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001778 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001779 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001780 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001781 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001782 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001783
1784 if (output->base.current == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001785 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001786 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001787 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001788
Wang Quanxianacb805a2012-07-30 18:09:46 -04001789 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1790
John Kåre Alsaker94659272012-11-13 19:10:18 +01001791 weston_output_init(&output->base, &ec->base, x, y,
1792 connector->mmWidth, connector->mmHeight,
1793 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1794
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001795 if (ec->use_pixman) {
1796 if (drm_output_init_pixman(output, ec) < 0) {
1797 weston_log("Failed to init output pixman state\n");
1798 goto err_output;
1799 }
1800 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001801 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001802 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001803 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001804
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001805 output->backlight = backlight_init(drm_device,
1806 connector->connector_type);
1807 if (output->backlight) {
1808 output->base.set_backlight = drm_set_backlight;
1809 output->base.backlight_current = drm_get_backlight(output);
1810 }
1811
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001812 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1813
Richard Hughes2b2092a2013-04-24 14:58:02 +01001814 find_and_parse_output_edid(ec, output, connector);
1815
Alex Wubd3354b2012-04-17 17:20:49 +08001816 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001817 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001818 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001819 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001820 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001821 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001822 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001823
Richard Hughese7299962013-05-01 21:52:12 +01001824 output->base.gamma_size = output->original_crtc->gamma_size;
1825 output->base.set_gamma = drm_output_set_gamma;
1826
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001827 weston_plane_init(&output->cursor_plane, 0, 0);
1828 weston_plane_init(&output->fb_plane, 0, 0);
1829
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001830 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1831 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1832 &ec->base.primary_plane);
1833
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001834 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001835 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001836 wl_list_for_each(m, &output->base.mode_list, link)
1837 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1838 m->width, m->height, m->refresh / 1000.0,
1839 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1840 ", preferred" : "",
1841 m->flags & WL_OUTPUT_MODE_CURRENT ?
1842 ", current" : "",
1843 connector->count_modes == 0 ?
1844 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001845
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001846 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001847
John Kåre Alsaker94659272012-11-13 19:10:18 +01001848err_output:
1849 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001850err_free:
1851 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1852 base.link) {
1853 wl_list_remove(&drm_mode->base.link);
1854 free(drm_mode);
1855 }
1856
1857 drmModeFreeCrtc(output->original_crtc);
1858 ec->crtc_allocator &= ~(1 << output->crtc_id);
1859 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001860 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001861
David Herrmann0f0d54e2011-12-08 17:05:45 +01001862 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001863}
1864
Jesse Barnes58ef3792012-02-23 09:45:49 -05001865static void
1866create_sprites(struct drm_compositor *ec)
1867{
1868 struct drm_sprite *sprite;
1869 drmModePlaneRes *plane_res;
1870 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001871 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001872
1873 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1874 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001875 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001876 strerror(errno));
1877 return;
1878 }
1879
1880 for (i = 0; i < plane_res->count_planes; i++) {
1881 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1882 if (!plane)
1883 continue;
1884
1885 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1886 plane->count_formats));
1887 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001888 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001889 __func__);
1890 free(plane);
1891 continue;
1892 }
1893
1894 memset(sprite, 0, sizeof *sprite);
1895
1896 sprite->possible_crtcs = plane->possible_crtcs;
1897 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001898 sprite->current = NULL;
1899 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001900 sprite->compositor = ec;
1901 sprite->count_formats = plane->count_formats;
1902 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001903 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001904 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001905 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001906 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1907 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001908
1909 wl_list_insert(&ec->sprite_list, &sprite->link);
1910 }
1911
1912 free(plane_res->planes);
1913 free(plane_res);
1914}
1915
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001916static void
1917destroy_sprites(struct drm_compositor *compositor)
1918{
1919 struct drm_sprite *sprite, *next;
1920 struct drm_output *output;
1921
1922 output = container_of(compositor->base.output_list.next,
1923 struct drm_output, base.link);
1924
1925 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1926 drmModeSetPlane(compositor->drm.fd,
1927 sprite->plane_id,
1928 output->crtc_id, 0, 0,
1929 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001930 drm_output_release_fb(output, sprite->current);
1931 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001932 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001933 free(sprite);
1934 }
1935}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001936
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001937static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001938create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001939 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001940{
1941 drmModeConnector *connector;
1942 drmModeRes *resources;
1943 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001944 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001945
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001946 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001947 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001948 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001949 return -1;
1950 }
1951
Jesse Barnes58ef3792012-02-23 09:45:49 -05001952 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001953 if (!ec->crtcs) {
1954 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001955 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001956 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001957
Rob Clark4339add2012-08-09 14:18:28 -05001958 ec->min_width = resources->min_width;
1959 ec->max_width = resources->max_width;
1960 ec->min_height = resources->min_height;
1961 ec->max_height = resources->max_height;
1962
Jesse Barnes58ef3792012-02-23 09:45:49 -05001963 ec->num_crtcs = resources->count_crtcs;
1964 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1965
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001966 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001967 connector = drmModeGetConnector(ec->drm.fd,
1968 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001969 if (connector == NULL)
1970 continue;
1971
1972 if (connector->connection == DRM_MODE_CONNECTED &&
1973 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001974 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001975 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001976 connector, x, y,
1977 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001978 drmModeFreeConnector(connector);
1979 continue;
1980 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001981
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001982 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001983 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001984 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001985 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001986
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001987 drmModeFreeConnector(connector);
1988 }
1989
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001990 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001991 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001992 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001993 return -1;
1994 }
1995
1996 drmModeFreeResources(resources);
1997
1998 return 0;
1999}
2000
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002001static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002002update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002003{
2004 drmModeConnector *connector;
2005 drmModeRes *resources;
2006 struct drm_output *output, *next;
2007 int x = 0, y = 0;
2008 int x_offset = 0, y_offset = 0;
2009 uint32_t connected = 0, disconnects = 0;
2010 int i;
2011
2012 resources = drmModeGetResources(ec->drm.fd);
2013 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002014 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002015 return;
2016 }
2017
2018 /* collect new connects */
2019 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002020 int connector_id = resources->connectors[i];
2021
2022 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002023 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002024 continue;
2025
David Herrmann7551cff2011-12-08 17:05:43 +01002026 if (connector->connection != DRM_MODE_CONNECTED) {
2027 drmModeFreeConnector(connector);
2028 continue;
2029 }
2030
Benjamin Franzke117483d2011-08-30 11:38:26 +02002031 connected |= (1 << connector_id);
2032
2033 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002034 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002035 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002036 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002037
2038 /* XXX: not yet needed, we die with 0 outputs */
2039 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002040 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002041 else
2042 x = 0;
2043 y = 0;
2044 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002045 connector, x, y,
2046 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002047 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002048
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002049 }
2050 drmModeFreeConnector(connector);
2051 }
2052 drmModeFreeResources(resources);
2053
2054 disconnects = ec->connector_allocator & ~connected;
2055 if (disconnects) {
2056 wl_list_for_each_safe(output, next, &ec->base.output_list,
2057 base.link) {
2058 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002059 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002060 output->base.x - x_offset,
2061 output->base.y - y_offset);
2062 }
2063
2064 if (disconnects & (1 << output->connector_id)) {
2065 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002066 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002067 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002068 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002069 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002070 }
2071 }
2072 }
2073
2074 /* FIXME: handle zero outputs, without terminating */
2075 if (ec->connector_allocator == 0)
2076 wl_display_terminate(ec->base.wl_display);
2077}
2078
2079static int
David Herrmannd7488c22012-03-11 20:05:21 +01002080udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002081{
David Herrmannd7488c22012-03-11 20:05:21 +01002082 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002083 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002084
2085 sysnum = udev_device_get_sysnum(device);
2086 if (!sysnum || atoi(sysnum) != ec->drm.id)
2087 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002088
David Herrmann6ac52db2012-03-11 20:05:22 +01002089 val = udev_device_get_property_value(device, "HOTPLUG");
2090 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002091 return 0;
2092
David Herrmann6ac52db2012-03-11 20:05:22 +01002093 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002094}
2095
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002096static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002097udev_drm_event(int fd, uint32_t mask, void *data)
2098{
2099 struct drm_compositor *ec = data;
2100 struct udev_device *event;
2101
2102 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002103
David Herrmannd7488c22012-03-11 20:05:21 +01002104 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002105 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002106
2107 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002108
2109 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002110}
2111
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002112static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002113drm_restore(struct weston_compositor *ec)
2114{
2115 struct drm_compositor *d = (struct drm_compositor *) ec;
2116
2117 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2118 weston_log("failed to drop master: %m\n");
2119 tty_reset(d->tty);
2120}
2121
2122static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002123drm_free_configured_output(struct drm_configured_output *output)
2124{
2125 free(output->name);
2126 free(output->mode);
2127 free(output);
2128}
2129
2130static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002131drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002132{
2133 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002134 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002135 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002136
Kristian Høgsberge8091032013-02-18 15:43:29 -05002137 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2138 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002139 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002140 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002141
2142 wl_event_source_remove(d->udev_drm_source);
2143 wl_event_source_remove(d->drm_source);
2144
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002145 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002146
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002147 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002148
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002149 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002150
2151 if (d->gbm)
2152 gbm_device_destroy(d->gbm);
2153
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002154 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002155 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002156 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002157
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002158 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002159}
2160
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002161static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002162drm_compositor_set_modes(struct drm_compositor *compositor)
2163{
2164 struct drm_output *output;
2165 struct drm_mode *drm_mode;
2166 int ret;
2167
2168 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002169 if (!output->current) {
2170 /* If something that would cause the output to
2171 * switch mode happened while in another vt, we
2172 * might not have a current drm_fb. In that case,
2173 * schedule a repaint and let drm_output_repaint
2174 * handle setting the mode. */
2175 weston_output_schedule_repaint(&output->base);
2176 continue;
2177 }
2178
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002179 drm_mode = (struct drm_mode *) output->base.current;
2180 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002181 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002182 &output->connector_id, 1,
2183 &drm_mode->mode_info);
2184 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002185 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002186 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002187 drm_mode->base.width, drm_mode->base.height,
2188 output->base.x, output->base.y);
2189 }
2190 }
2191}
2192
2193static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002194vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002195{
2196 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002197 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002198 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002199 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002200
2201 switch (event) {
2202 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002203 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002204 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002205 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002206 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002207 wl_display_terminate(compositor->wl_display);
2208 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002209 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002210 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002211 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002212 wl_list_for_each(seat, &compositor->seat_list, base.link)
2213 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002214 break;
2215 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002216 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002217 wl_list_for_each(seat, &compositor->seat_list, base.link)
2218 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002219
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002220 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002221 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002222 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002223
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002224 /* If we have a repaint scheduled (either from a
2225 * pending pageflip or the idle handler), make sure we
2226 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002227 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002228 * further attemps at repainting. When we switch
2229 * back, we schedule a repaint, which will process
2230 * pending frame callbacks. */
2231
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002232 wl_list_for_each(output, &ec->base.output_list, base.link) {
2233 output->base.repaint_needed = 0;
2234 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002235 }
2236
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002237 output = container_of(ec->base.output_list.next,
2238 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002239
2240 wl_list_for_each(sprite, &ec->sprite_list, link)
2241 drmModeSetPlane(ec->drm.fd,
2242 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002243 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002244 0, 0, 0, 0, 0, 0, 0, 0);
2245
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002246 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002247 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002248
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002249 break;
2250 };
2251}
2252
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002253static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002254switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002255{
2256 struct drm_compositor *ec = data;
2257
Daniel Stone325fc2d2012-05-30 16:31:58 +01002258 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002259}
2260
David Herrmann0af066f2012-10-29 19:21:16 +01002261/*
2262 * Find primary GPU
2263 * Some systems may have multiple DRM devices attached to a single seat. This
2264 * function loops over all devices and tries to find a PCI device with the
2265 * boot_vga sysfs attribute set to 1.
2266 * If no such device is found, the first DRM device reported by udev is used.
2267 */
2268static struct udev_device*
2269find_primary_gpu(struct drm_compositor *ec, const char *seat)
2270{
2271 struct udev_enumerate *e;
2272 struct udev_list_entry *entry;
2273 const char *path, *device_seat, *id;
2274 struct udev_device *device, *drm_device, *pci;
2275
2276 e = udev_enumerate_new(ec->udev);
2277 udev_enumerate_add_match_subsystem(e, "drm");
2278 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2279
2280 udev_enumerate_scan_devices(e);
2281 drm_device = NULL;
2282 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2283 path = udev_list_entry_get_name(entry);
2284 device = udev_device_new_from_syspath(ec->udev, path);
2285 if (!device)
2286 continue;
2287 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2288 if (!device_seat)
2289 device_seat = default_seat;
2290 if (strcmp(device_seat, seat)) {
2291 udev_device_unref(device);
2292 continue;
2293 }
2294
2295 pci = udev_device_get_parent_with_subsystem_devtype(device,
2296 "pci", NULL);
2297 if (pci) {
2298 id = udev_device_get_sysattr_value(pci, "boot_vga");
2299 if (id && !strcmp(id, "1")) {
2300 if (drm_device)
2301 udev_device_unref(drm_device);
2302 drm_device = device;
2303 break;
2304 }
2305 }
2306
2307 if (!drm_device)
2308 drm_device = device;
2309 else
2310 udev_device_unref(device);
2311 }
2312
2313 udev_enumerate_unref(e);
2314 return drm_device;
2315}
2316
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002317static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002318planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002319{
2320 struct drm_compositor *c = data;
2321
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002322 switch (key) {
2323 case KEY_C:
2324 c->cursors_are_broken ^= 1;
2325 break;
2326 case KEY_V:
2327 c->sprites_are_broken ^= 1;
2328 break;
2329 case KEY_O:
2330 c->sprites_hidden ^= 1;
2331 break;
2332 default:
2333 break;
2334 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002335}
2336
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002337static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002338drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002339 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002340 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002341{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002342 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002343 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002344 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002345 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002346 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002347 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002348
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002349 weston_log("initializing drm backend\n");
2350
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002351 ec = malloc(sizeof *ec);
2352 if (ec == NULL)
2353 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002354 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002355
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002356 /* KMS support for sprites is not complete yet, so disable the
2357 * functionality for now. */
2358 ec->sprites_are_broken = 1;
2359
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002360 ec->use_pixman = pixman;
2361
Daniel Stone725c2c32012-06-22 14:04:36 +01002362 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002363 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002364 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002365 goto err_base;
2366 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002367
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002368 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002369 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002370 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002371 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002372 goto err_compositor;
2373 }
2374
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002375 ec->udev = udev_new();
2376 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002377 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002378 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002379 }
2380
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002381 ec->base.wl_display = display;
2382 ec->tty = tty_create(&ec->base, vt_func, tty);
2383 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002384 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002385 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002386 }
2387
David Herrmann0af066f2012-10-29 19:21:16 +01002388 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002389 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002390 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002391 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002392 }
David Herrmann0af066f2012-10-29 19:21:16 +01002393 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002394
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002395 if (init_drm(ec, drm_device) < 0) {
2396 weston_log("failed to initialize kms\n");
2397 goto err_udev_dev;
2398 }
2399
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002400 if (ec->use_pixman) {
2401 if (init_pixman(ec) < 0) {
2402 weston_log("failed to initialize pixman renderer\n");
2403 goto err_udev_dev;
2404 }
2405 } else {
2406 if (init_egl(ec) < 0) {
2407 weston_log("failed to initialize egl\n");
2408 goto err_udev_dev;
2409 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002410 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002411
2412 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002413 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002414
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002415 ec->base.focus = 1;
2416
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002417 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002418
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002419 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002420 weston_compositor_add_key_binding(&ec->base, key,
2421 MODIFIER_CTRL | MODIFIER_ALT,
2422 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002423
Jesse Barnes58ef3792012-02-23 09:45:49 -05002424 wl_list_init(&ec->sprite_list);
2425 create_sprites(ec);
2426
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002427 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002428 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002429 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002430 }
2431
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002432 path = NULL;
2433
Kristian Høgsberge8091032013-02-18 15:43:29 -05002434 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002435 weston_log("failed to create input devices\n");
2436 goto err_sprite;
2437 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002438
2439 loop = wl_display_get_event_loop(ec->base.wl_display);
2440 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002441 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002442 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002443
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002444 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2445 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002446 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002447 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002448 }
2449 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2450 "drm", NULL);
2451 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002452 wl_event_loop_add_fd(loop,
2453 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002454 WL_EVENT_READABLE, udev_drm_event, ec);
2455
2456 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002457 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002458 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002459 }
2460
Daniel Stonea96b93c2012-06-22 14:04:37 +01002461 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002462
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002463 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002464 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002465 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002466 planes_binding, ec);
2467 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2468 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002469
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002470 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002471
2472err_udev_monitor:
2473 wl_event_source_remove(ec->udev_drm_source);
2474 udev_monitor_unref(ec->udev_monitor);
2475err_drm_source:
2476 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002477 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2478 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002479err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002480 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002481 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002482 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002483err_udev_dev:
2484 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002485err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002486 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2487 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002488 tty_destroy(ec->tty);
2489err_udev:
2490 udev_unref(ec->udev);
2491err_compositor:
2492 weston_compositor_shutdown(&ec->base);
2493err_base:
2494 free(ec);
2495 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002496}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002497
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002498static int
2499set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2500{
2501 mode->flags = 0;
2502
2503 if (strcmp(hsync, "+hsync") == 0)
2504 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2505 else if (strcmp(hsync, "-hsync") == 0)
2506 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2507 else
2508 return -1;
2509
2510 if (strcmp(vsync, "+vsync") == 0)
2511 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2512 else if (strcmp(vsync, "-vsync") == 0)
2513 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2514 else
2515 return -1;
2516
2517 return 0;
2518}
2519
2520static int
2521check_for_modeline(struct drm_configured_output *output)
2522{
2523 drmModeModeInfo mode;
2524 char hsync[16];
2525 char vsync[16];
2526 char mode_name[16];
2527 float fclock;
2528
2529 mode.type = DRM_MODE_TYPE_USERDEF;
2530 mode.hskew = 0;
2531 mode.vscan = 0;
2532 mode.vrefresh = 0;
2533
2534 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2535 &fclock, &mode.hdisplay,
2536 &mode.hsync_start,
2537 &mode.hsync_end, &mode.htotal,
2538 &mode.vdisplay,
2539 &mode.vsync_start,
2540 &mode.vsync_end, &mode.vtotal,
2541 hsync, vsync) == 11) {
2542 if (set_sync_flags(&mode, hsync, vsync))
2543 return -1;
2544
2545 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2546 strcpy(mode.name, mode_name);
2547
2548 mode.clock = fclock * 1000;
2549 } else
2550 return -1;
2551
2552 output->crtc_mode = mode;
2553
2554 return 0;
2555}
2556
Scott Moreau8ab5d452012-07-30 19:51:08 -06002557static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002558drm_output_set_transform(struct drm_configured_output *output)
2559{
2560 if (!output_transform) {
2561 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2562 return;
2563 }
2564
2565 if (!strcmp(output_transform, "normal"))
2566 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2567 else if (!strcmp(output_transform, "90"))
2568 output->transform = WL_OUTPUT_TRANSFORM_90;
2569 else if (!strcmp(output_transform, "180"))
2570 output->transform = WL_OUTPUT_TRANSFORM_180;
2571 else if (!strcmp(output_transform, "270"))
2572 output->transform = WL_OUTPUT_TRANSFORM_270;
2573 else if (!strcmp(output_transform, "flipped"))
2574 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2575 else if (!strcmp(output_transform, "flipped-90"))
2576 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2577 else if (!strcmp(output_transform, "flipped-180"))
2578 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2579 else if (!strcmp(output_transform, "flipped-270"))
2580 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2581 else {
2582 weston_log("Invalid transform \"%s\" for output %s\n",
2583 output_transform, output_name);
2584 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2585 }
2586
2587 free(output_transform);
2588 output_transform = NULL;
2589}
2590
2591static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002592output_section_done(void *data)
2593{
2594 struct drm_configured_output *output;
2595
2596 output = malloc(sizeof *output);
2597
Scott Moreau1bad5db2012-08-18 01:04:05 -06002598 if (!output || !output_name || (output_name[0] == 'X') ||
2599 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002600 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002601 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002602 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002603 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002604 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002605 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002606 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002607 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002608 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002609
2610 output->config = OUTPUT_CONFIG_INVALID;
2611 output->name = output_name;
2612 output->mode = output_mode;
2613
Scott Moreau1bad5db2012-08-18 01:04:05 -06002614 if (output_mode) {
2615 if (strcmp(output_mode, "off") == 0)
2616 output->config = OUTPUT_CONFIG_OFF;
2617 else if (strcmp(output_mode, "preferred") == 0)
2618 output->config = OUTPUT_CONFIG_PREFERRED;
2619 else if (strcmp(output_mode, "current") == 0)
2620 output->config = OUTPUT_CONFIG_CURRENT;
2621 else if (sscanf(output_mode, "%dx%d",
2622 &output->width, &output->height) == 2)
2623 output->config = OUTPUT_CONFIG_MODE;
2624 else if (check_for_modeline(output) == 0)
2625 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002626
Scott Moreau1bad5db2012-08-18 01:04:05 -06002627 if (output->config == OUTPUT_CONFIG_INVALID)
2628 weston_log("Invalid mode \"%s\" for output %s\n",
2629 output_mode, output_name);
2630 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002631 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002632
2633 drm_output_set_transform(output);
2634
2635 wl_list_insert(&configured_output_list, &output->link);
2636
2637 if (output_transform)
2638 free(output_transform);
2639 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002640}
2641
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002642WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002643backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002644 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002645{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002646 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002647 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002648
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002649 const struct weston_option drm_options[] = {
2650 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2651 { WESTON_OPTION_STRING, "seat", 0, &seat },
2652 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002653 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002654 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002655 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002656
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002657 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002658
Scott Moreau8ab5d452012-07-30 19:51:08 -06002659 wl_list_init(&configured_output_list);
2660
2661 const struct config_key drm_config_keys[] = {
2662 { "name", CONFIG_KEY_STRING, &output_name },
2663 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002664 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002665 };
2666
2667 const struct config_section config_section[] = {
2668 { "output", drm_config_keys,
2669 ARRAY_LENGTH(drm_config_keys), output_section_done },
2670 };
2671
2672 parse_config_file(config_file, config_section,
2673 ARRAY_LENGTH(config_section), NULL);
2674
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002675 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2676 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002677}