blob: db4db33ac46b45e981de78171531816a5bdfa76d [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øgsberg2f9ed712012-07-26 17:57:15 -0400149 char *name;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400150 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500151 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400152 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700153 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100154 struct drm_edid edid;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200155
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300156 int vblank_pending;
157 int page_flip_pending;
158
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400159 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400160 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400161 struct weston_plane cursor_plane;
162 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400163 struct weston_surface *cursor_surface;
164 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300165 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200166 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200167
168 struct drm_fb *dumb[2];
169 pixman_image_t *image[2];
170 int current_image;
171 pixman_region32_t previous_damage;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400172};
173
Jesse Barnes58ef3792012-02-23 09:45:49 -0500174/*
175 * An output has a primary display plane plus zero or more sprites for
176 * blending display contents.
177 */
178struct drm_sprite {
179 struct wl_list link;
180
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400181 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200183 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300184 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500185 struct drm_compositor *compositor;
186
Jesse Barnes58ef3792012-02-23 09:45:49 -0500187 uint32_t possible_crtcs;
188 uint32_t plane_id;
189 uint32_t count_formats;
190
191 int32_t src_x, src_y;
192 uint32_t src_w, src_h;
193 uint32_t dest_x, dest_y;
194 uint32_t dest_w, dest_h;
195
196 uint32_t formats[];
197};
198
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500199static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400200
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400201static void
202drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400203
Jesse Barnes58ef3792012-02-23 09:45:49 -0500204static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500205drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
206{
207 struct weston_compositor *ec = output_base->compositor;
208 struct drm_compositor *c =(struct drm_compositor *) ec;
209 struct drm_output *output = (struct drm_output *) output_base;
210 int crtc;
211
212 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
213 if (c->crtcs[crtc] != output->crtc_id)
214 continue;
215
216 if (supported & (1 << crtc))
217 return -1;
218 }
219
220 return 0;
221}
222
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300223static void
224drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
225{
226 struct drm_fb *fb = data;
227 struct gbm_device *gbm = gbm_bo_get_device(bo);
228
229 if (fb->fb_id)
230 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
231
Pekka Paalanende685b82012-12-04 15:58:12 +0200232 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300233
234 free(data);
235}
236
237static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200238drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
239{
240 struct drm_fb *fb;
241 int ret;
242
243 struct drm_mode_create_dumb create_arg;
244 struct drm_mode_destroy_dumb destroy_arg;
245 struct drm_mode_map_dumb map_arg;
246
247 fb = calloc(1, sizeof *fb);
248 if (!fb)
249 return NULL;
250
251 create_arg.bpp = 32;
252 create_arg.width = width;
253 create_arg.height = height;
254
255 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
256 if (ret)
257 goto err_fb;
258
259 fb->handle = create_arg.handle;
260 fb->stride = create_arg.pitch;
261 fb->size = create_arg.size;
262 fb->fd = ec->drm.fd;
263
264 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
265 fb->stride, fb->handle, &fb->fb_id);
266 if (ret)
267 goto err_bo;
268
269 memset(&map_arg, 0, sizeof(map_arg));
270 map_arg.handle = fb->handle;
271 drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
272
273 if (ret)
274 goto err_add_fb;
275
276 fb->map = mmap(0, fb->size, PROT_WRITE,
277 MAP_SHARED, ec->drm.fd, map_arg.offset);
278 if (fb->map == MAP_FAILED)
279 goto err_add_fb;
280
281 return fb;
282
283err_add_fb:
284 drmModeRmFB(ec->drm.fd, fb->fb_id);
285err_bo:
286 memset(&destroy_arg, 0, sizeof(destroy_arg));
287 destroy_arg.handle = create_arg.handle;
288 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
289err_fb:
290 free(fb);
291 return NULL;
292}
293
294static void
295drm_fb_destroy_dumb(struct drm_fb *fb)
296{
297 struct drm_mode_destroy_dumb destroy_arg;
298
299 if (!fb->map)
300 return;
301
302 if (fb->fb_id)
303 drmModeRmFB(fb->fd, fb->fb_id);
304
305 weston_buffer_reference(&fb->buffer_ref, NULL);
306
307 munmap(fb->map, fb->size);
308
309 memset(&destroy_arg, 0, sizeof(destroy_arg));
310 destroy_arg.handle = fb->handle;
311 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
312
313 free(fb);
314}
315
316static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500317drm_fb_get_from_bo(struct gbm_bo *bo,
318 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300319{
320 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200321 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200322 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300323 int ret;
324
325 if (fb)
326 return fb;
327
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200328 fb = calloc(1, sizeof *fb);
329 if (!fb)
330 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331
332 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300333
334 width = gbm_bo_get_width(bo);
335 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200336 fb->stride = gbm_bo_get_stride(bo);
337 fb->handle = gbm_bo_get_handle(bo).u32;
338 fb->size = fb->stride * height;
339 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300340
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200341 if (compositor->min_width > width || width > compositor->max_width ||
342 compositor->min_height > height ||
343 height > compositor->max_height) {
344 weston_log("bo geometry out of bounds\n");
345 goto err_free;
346 }
347
348 ret = -1;
349
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200350 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200351 handles[0] = fb->handle;
352 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200353 offsets[0] = 0;
354
355 ret = drmModeAddFB2(compositor->drm.fd, width, height,
356 format, handles, pitches, offsets,
357 &fb->fb_id, 0);
358 if (ret) {
359 weston_log("addfb2 failed: %m\n");
360 compositor->no_addfb2 = 1;
361 compositor->sprites_are_broken = 1;
362 }
363 }
364
365 if (ret)
366 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200367 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200368
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300369 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200370 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200371 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300372 }
373
374 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
375
376 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200377
378err_free:
379 free(fb);
380 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300381}
382
383static void
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200384drm_fb_set_buffer(struct drm_fb *fb, struct wl_buffer *buffer)
385{
Pekka Paalanende685b82012-12-04 15:58:12 +0200386 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200387
388 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200389
Pekka Paalanende685b82012-12-04 15:58:12 +0200390 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200391}
392
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200393static void
394drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
395{
396 if (!fb)
397 return;
398
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200399 if (fb->map &&
400 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200401 drm_fb_destroy_dumb(fb);
402 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200403 if (fb->is_client_buffer)
404 gbm_bo_destroy(fb->bo);
405 else
406 gbm_surface_release_buffer(output->surface,
407 output->current->bo);
408 }
409}
410
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500411static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200412drm_output_check_scanout_format(struct drm_output *output,
413 struct weston_surface *es, struct gbm_bo *bo)
414{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200415 uint32_t format;
416 pixman_region32_t r;
417
418 format = gbm_bo_get_format(bo);
419
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500420 switch (format) {
421 case GBM_FORMAT_XRGB8888:
422 return format;
423 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200424 /* We can only scanout an ARGB buffer if the surface's
425 * opaque region covers the whole output */
426 pixman_region32_init(&r);
427 pixman_region32_subtract(&r, &output->base.region,
428 &es->opaque);
429
430 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500431 format = GBM_FORMAT_XRGB8888;
432 else
433 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434
435 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200436
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500437 return format;
438 default:
439 return 0;
440 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200441}
442
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400443static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400444drm_output_prepare_scanout_surface(struct weston_output *_output,
445 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500446{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400447 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500448 struct drm_compositor *c =
449 (struct drm_compositor *) output->base.compositor;
Pekka Paalanende685b82012-12-04 15:58:12 +0200450 struct wl_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300451 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500452 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500453
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500454 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200455 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200456 buffer == NULL || c->gbm == NULL ||
Pekka Paalanende685b82012-12-04 15:58:12 +0200457 buffer->width != output->base.current->width ||
458 buffer->height != output->base.current->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200459 output->base.transform != es->buffer_transform ||
460 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400461 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500462
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400463 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200464 buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500465
Rob Bradford9b101872012-09-14 23:25:41 +0100466 /* Unable to use the buffer for scanout */
467 if (!bo)
468 return NULL;
469
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500470 format = drm_output_check_scanout_format(output, es, bo);
471 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300472 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400473 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300474 }
475
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500476 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300477 if (!output->next) {
478 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400479 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300480 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500481
Pekka Paalanende685b82012-12-04 15:58:12 +0200482 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500483
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400484 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500485}
486
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500487static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200488drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400489{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200490 struct drm_compositor *c =
491 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300492 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400493
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200494 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400495
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300496 bo = gbm_surface_lock_front_buffer(output->surface);
497 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200498 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400499 return;
500 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500502 output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200504 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300505 gbm_surface_release_buffer(output->surface, bo);
506 return;
507 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400508}
509
510static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200511drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
512{
513 struct weston_compositor *ec = output->base.compositor;
514 pixman_region32_t total_damage, previous_damage;
515
516 pixman_region32_init(&total_damage);
517 pixman_region32_init(&previous_damage);
518
519 pixman_region32_copy(&previous_damage, damage);
520
521 pixman_region32_union(&total_damage, damage, &output->previous_damage);
522 pixman_region32_copy(&output->previous_damage, &previous_damage);
523
524 output->current_image ^= 1;
525
526 output->next = output->dumb[output->current_image];
527 pixman_renderer_output_set_buffer(&output->base,
528 output->image[output->current_image]);
529
530 ec->renderer->repaint_output(&output->base, &total_damage);
531
532 pixman_region32_fini(&total_damage);
533 pixman_region32_fini(&previous_damage);
534}
535
536static void
537drm_output_render(struct drm_output *output, pixman_region32_t *damage)
538{
539 struct drm_compositor *c =
540 (struct drm_compositor *) output->base.compositor;
541
542 if (c->use_pixman)
543 drm_output_render_pixman(output, damage);
544 else
545 drm_output_render_gl(output, damage);
546
547 pixman_region32_subtract(&c->base.primary_plane.damage,
548 &c->base.primary_plane.damage, damage);
549}
550
551static void
Richard Hughese7299962013-05-01 21:52:12 +0100552drm_output_set_gamma(struct weston_output *output_base,
553 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
554{
555 int rc;
556 struct drm_output *output = (struct drm_output *) output_base;
557 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
558
559 /* check */
560 if (output_base->gamma_size != size)
561 return;
562 if (!output->original_crtc)
563 return;
564
565 rc = drmModeCrtcSetGamma(compositor->drm.fd,
566 output->crtc_id,
567 size, r, g, b);
568 if (rc)
569 weston_log("set gamma failed: %m\n");
570}
571
572static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500573drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400574 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100575{
576 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500577 struct drm_compositor *compositor =
578 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500579 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400580 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500581 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100582
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300583 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400584 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300585 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400586 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100587
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400588 mode = container_of(output->base.current, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300589 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400590 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300591 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400592 &output->connector_id, 1,
593 &mode->mode_info);
594 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200595 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400596 return;
597 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200598 }
599
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500600 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300601 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500602 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200603 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500604 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500605 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100606
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300607 output->page_flip_pending = 1;
608
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400609 drm_output_set_cursor(output);
610
Jesse Barnes58ef3792012-02-23 09:45:49 -0500611 /*
612 * Now, update all the sprite surfaces
613 */
614 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200615 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500616 drmVBlank vbl = {
617 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
618 .request.sequence = 1,
619 };
620
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200621 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200622 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500623 continue;
624
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200625 if (s->next && !compositor->sprites_hidden)
626 fb_id = s->next->fb_id;
627
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200629 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500630 s->dest_x, s->dest_y,
631 s->dest_w, s->dest_h,
632 s->src_x, s->src_y,
633 s->src_w, s->src_h);
634 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200635 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500636 ret, strerror(errno));
637
Rob Clark5ca1a472012-08-08 20:27:37 -0500638 if (output->pipe > 0)
639 vbl.request.type |= DRM_VBLANK_SECONDARY;
640
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 /*
642 * Queue a vblank signal so we know when the surface
643 * becomes active on the display or has been replaced.
644 */
645 vbl.request.signal = (unsigned long)s;
646 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
647 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200648 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649 ret, strerror(errno));
650 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300651
652 s->output = output;
653 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 }
655
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500656 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400657}
658
659static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200660drm_output_start_repaint_loop(struct weston_output *output_base)
661{
662 struct drm_output *output = (struct drm_output *) output_base;
663 struct drm_compositor *compositor = (struct drm_compositor *)
664 output_base->compositor;
665 uint32_t fb_id;
666
667 if (output->current)
668 fb_id = output->current->fb_id;
669 else
670 fb_id = output->original_crtc->buffer_id;
671
672 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
673 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
674 weston_log("queueing pageflip failed: %m\n");
675 return;
676 }
677}
678
679static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500680vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
681 void *data)
682{
683 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300684 struct drm_output *output = s->output;
685 uint32_t msecs;
686
687 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500688
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200689 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200690 s->current = s->next;
691 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300692
693 if (!output->page_flip_pending) {
694 msecs = sec * 1000 + usec / 1000;
695 weston_output_finish_frame(&output->base, msecs);
696 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697}
698
699static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400700page_flip_handler(int fd, unsigned int frame,
701 unsigned int sec, unsigned int usec, void *data)
702{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200703 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400704 uint32_t msecs;
705
Jonas Ådahle5a12252013-04-05 23:07:11 +0200706 /* We don't set page_flip_pending on start_repaint_loop, in that case
707 * we just want to page flip to the current buffer to get an accurate
708 * timestamp */
709 if (output->page_flip_pending) {
710 drm_output_release_fb(output, output->current);
711 output->current = output->next;
712 output->next = NULL;
713 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300714
Jonas Ådahle5a12252013-04-05 23:07:11 +0200715 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400716
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300717 if (!output->vblank_pending) {
718 msecs = sec * 1000 + usec / 1000;
719 weston_output_finish_frame(&output->base, msecs);
720 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200721}
722
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500723static uint32_t
724drm_output_check_sprite_format(struct drm_sprite *s,
725 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500726{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500727 uint32_t i, format;
728
729 format = gbm_bo_get_format(bo);
730
731 if (format == GBM_FORMAT_ARGB8888) {
732 pixman_region32_t r;
733
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500734 pixman_region32_init_rect(&r, 0, 0,
735 es->geometry.width,
736 es->geometry.height);
737 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500738
739 if (!pixman_region32_not_empty(&r))
740 format = GBM_FORMAT_XRGB8888;
741
742 pixman_region32_fini(&r);
743 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500744
745 for (i = 0; i < s->count_formats; i++)
746 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500747 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500748
749 return 0;
750}
751
752static int
753drm_surface_transform_supported(struct weston_surface *es)
754{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500755 return !es->transform.enabled ||
756 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500757}
758
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400759static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400761 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500762{
763 struct weston_compositor *ec = output_base->compositor;
764 struct drm_compositor *c =(struct drm_compositor *) ec;
765 struct drm_sprite *s;
766 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500767 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200769 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400771 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200773 if (c->gbm == NULL)
774 return NULL;
775
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200776 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200777 return NULL;
778
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500779 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400780 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500781
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300782 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400783 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300784
Pekka Paalanende685b82012-12-04 15:58:12 +0200785 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400786 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500787
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200788 if (es->alpha != 1.0f)
789 return NULL;
790
Pekka Paalanende685b82012-12-04 15:58:12 +0200791 if (wl_buffer_is_shm(es->buffer_ref.buffer))
Rob Clark702ffae2012-08-09 14:18:27 -0500792 return NULL;
793
Jesse Barnes58ef3792012-02-23 09:45:49 -0500794 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400795 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797 wl_list_for_each(s, &c->sprite_list, link) {
798 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
799 continue;
800
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200801 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802 found = 1;
803 break;
804 }
805 }
806
807 /* No sprites available */
808 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400809 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500810
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400811 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Pekka Paalanende685b82012-12-04 15:58:12 +0200812 es->buffer_ref.buffer, GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400813 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400814 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400815
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500816 format = drm_output_check_sprite_format(s, es, bo);
817 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200818 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400819 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500820 }
821
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200822 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200823 if (!s->next) {
824 gbm_bo_destroy(bo);
825 return NULL;
826 }
827
Pekka Paalanende685b82012-12-04 15:58:12 +0200828 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500829
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 box = pixman_region32_extents(&es->transform.boundingbox);
831 s->plane.x = box->x1;
832 s->plane.y = box->y1;
833
Jesse Barnes58ef3792012-02-23 09:45:49 -0500834 /*
835 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200836 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837 * for us already).
838 */
839 pixman_region32_init(&dest_rect);
840 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
841 &output_base->region);
842 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
843 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200844 tbox = weston_transformed_rect(output_base->width,
845 output_base->height,
846 output_base->transform, *box);
847 s->dest_x = tbox.x1;
848 s->dest_y = tbox.y1;
849 s->dest_w = tbox.x2 - tbox.x1;
850 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851 pixman_region32_fini(&dest_rect);
852
853 pixman_region32_init(&src_rect);
854 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
855 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500856 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400857
858 weston_surface_from_global_fixed(es,
859 wl_fixed_from_int(box->x1),
860 wl_fixed_from_int(box->y1),
861 &sx1, &sy1);
862 weston_surface_from_global_fixed(es,
863 wl_fixed_from_int(box->x2),
864 wl_fixed_from_int(box->y2),
865 &sx2, &sy2);
866
867 if (sx1 < 0)
868 sx1 = 0;
869 if (sy1 < 0)
870 sy1 = 0;
871 if (sx2 > wl_fixed_from_int(es->geometry.width))
872 sx2 = wl_fixed_from_int(es->geometry.width);
873 if (sy2 > wl_fixed_from_int(es->geometry.height))
874 sy2 = wl_fixed_from_int(es->geometry.height);
875
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200876 tbox.x1 = sx1;
877 tbox.y1 = sy1;
878 tbox.x2 = sx2;
879 tbox.y2 = sy2;
880
881 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
882 wl_fixed_from_int(es->geometry.height),
883 es->buffer_transform, tbox);
884
885 s->src_x = tbox.x1 << 8;
886 s->src_y = tbox.y1 << 8;
887 s->src_w = (tbox.x2 - tbox.x1) << 8;
888 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889 pixman_region32_fini(&src_rect);
890
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400891 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500892}
893
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400894static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400895drm_output_prepare_cursor_surface(struct weston_output *output_base,
896 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500897{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400898 struct drm_compositor *c =
899 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400900 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400901
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200902 if (c->gbm == NULL)
903 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200904 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
905 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400906 if (output->cursor_surface)
907 return NULL;
908 if (es->output_mask != (1u << output_base->id))
909 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500910 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400911 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200912 if (es->buffer_ref.buffer == NULL ||
913 !wl_buffer_is_shm(es->buffer_ref.buffer) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400914 es->geometry.width > 64 || es->geometry.height > 64)
915 return NULL;
916
917 output->cursor_surface = es;
918
919 return &output->cursor_plane;
920}
921
922static void
923drm_output_set_cursor(struct drm_output *output)
924{
925 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400926 struct drm_compositor *c =
927 (struct drm_compositor *) output->base.compositor;
928 EGLint handle, stride;
929 struct gbm_bo *bo;
930 uint32_t buf[64 * 64];
931 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400932 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500933
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400934 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400935 if (es == NULL) {
936 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
937 return;
938 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500939
Pekka Paalanende685b82012-12-04 15:58:12 +0200940 if (es->buffer_ref.buffer &&
941 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400942 pixman_region32_fini(&output->cursor_plane.damage);
943 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400944 output->current_cursor ^= 1;
945 bo = output->cursor_bo[output->current_cursor];
946 memset(buf, 0, sizeof buf);
Pekka Paalanende685b82012-12-04 15:58:12 +0200947 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer);
948 s = wl_shm_buffer_get_data(es->buffer_ref.buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400949 for (i = 0; i < es->geometry.height; i++)
950 memcpy(buf + i * 64, s + i * stride,
951 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500952
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400953 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300954 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400955
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400956 handle = gbm_bo_get_handle(bo).s32;
957 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500958 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300959 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500960 c->cursors_are_broken = 1;
961 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400962 }
963
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400964 x = es->geometry.x - output->base.x;
965 y = es->geometry.y - output->base.y;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400966 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500967 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400968 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500969 c->cursors_are_broken = 1;
970 }
971
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400972 output->cursor_plane.x = x;
973 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400974 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500975}
976
Jesse Barnes58ef3792012-02-23 09:45:49 -0500977static void
978drm_assign_planes(struct weston_output *output)
979{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400980 struct drm_compositor *c =
981 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400982 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500983 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400984 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500985
986 /*
987 * Find a surface for each sprite in the output using some heuristics:
988 * 1) size
989 * 2) frequency of update
990 * 3) opacity (though some hw might support alpha blending)
991 * 4) clipping (this can be fixed with color keys)
992 *
993 * The idea is to save on blitting since this should save power.
994 * If we can get a large video surface on the sprite for example,
995 * the main display surface may not need to update at all, and
996 * the client buffer can be used directly for the sprite surface
997 * as we do for flipping full screen surfaces.
998 */
999 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001000 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001001 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001002 /* test whether this buffer can ever go into a plane:
1003 * non-shm, or small enough to be a cursor
1004 */
1005 if ((es->buffer_ref.buffer &&
1006 !wl_buffer_is_shm(es->buffer_ref.buffer)) ||
1007 (es->geometry.width <= 64 && es->geometry.height <= 64))
1008 es->keep_buffer = 1;
1009 else
1010 es->keep_buffer = 0;
1011
Jesse Barnes58ef3792012-02-23 09:45:49 -05001012 pixman_region32_init(&surface_overlap);
1013 pixman_region32_intersect(&surface_overlap, &overlap,
1014 &es->transform.boundingbox);
1015
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001016 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001017 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001018 next_plane = primary;
1019 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001020 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001021 if (next_plane == NULL)
1022 next_plane = drm_output_prepare_scanout_surface(output, es);
1023 if (next_plane == NULL)
1024 next_plane = drm_output_prepare_overlay_surface(output, es);
1025 if (next_plane == NULL)
1026 next_plane = primary;
1027 weston_surface_move_to_plane(es, next_plane);
1028 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001029 pixman_region32_union(&overlap, &overlap,
1030 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001031
Jesse Barnes58ef3792012-02-23 09:45:49 -05001032 pixman_region32_fini(&surface_overlap);
1033 }
1034 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001035}
1036
Matt Roper361d2ad2011-08-29 13:52:23 -07001037static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001038drm_output_fini_pixman(struct drm_output *output);
1039
1040static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001041drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001042{
1043 struct drm_output *output = (struct drm_output *) output_base;
1044 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001045 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001046 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001047
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001048 if (output->backlight)
1049 backlight_destroy(output->backlight);
1050
Matt Roper361d2ad2011-08-29 13:52:23 -07001051 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001052 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001053
1054 /* Restore original CRTC state */
1055 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001056 origcrtc->x, origcrtc->y,
1057 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001058 drmModeFreeCrtc(origcrtc);
1059
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001060 c->crtc_allocator &= ~(1 << output->crtc_id);
1061 c->connector_allocator &= ~(1 << output->connector_id);
1062
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001063 if (c->use_pixman) {
1064 drm_output_fini_pixman(output);
1065 } else {
1066 gl_renderer_output_destroy(output_base);
1067 gbm_surface_destroy(output->surface);
1068 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001069
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001070 weston_plane_release(&output->fb_plane);
1071 weston_plane_release(&output->cursor_plane);
1072
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001073 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001074 wl_list_remove(&output->base.link);
1075
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001076 free(output->name);
Matt Roper361d2ad2011-08-29 13:52:23 -07001077 free(output);
1078}
1079
Alex Wub7b8bda2012-04-17 17:20:48 +08001080static struct drm_mode *
1081choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1082{
1083 struct drm_mode *tmp_mode = NULL, *mode;
1084
1085 if (output->base.current->width == target_mode->width &&
1086 output->base.current->height == target_mode->height &&
1087 (output->base.current->refresh == target_mode->refresh ||
1088 target_mode->refresh == 0))
1089 return (struct drm_mode *)output->base.current;
1090
1091 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1092 if (mode->mode_info.hdisplay == target_mode->width &&
1093 mode->mode_info.vdisplay == target_mode->height) {
1094 if (mode->mode_info.vrefresh == target_mode->refresh ||
1095 target_mode->refresh == 0) {
1096 return mode;
1097 } else if (!tmp_mode)
1098 tmp_mode = mode;
1099 }
1100 }
1101
1102 return tmp_mode;
1103}
1104
1105static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001106drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001107static int
1108drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001109
1110static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001111drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1112{
1113 struct drm_output *output;
1114 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001115 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001116
1117 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001118 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001119 return -1;
1120 }
1121
1122 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001123 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001124 return -1;
1125 }
1126
1127 ec = (struct drm_compositor *)output_base->compositor;
1128 output = (struct drm_output *)output_base;
1129 drm_mode = choose_mode (output, mode);
1130
1131 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001132 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001133 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001134 }
1135
1136 if (&drm_mode->base == output->base.current)
Alex Wub7b8bda2012-04-17 17:20:48 +08001137 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001138
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001139 output->base.current->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001140
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001141 output->base.current = &drm_mode->base;
1142 output->base.current->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001143 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1144
Alex Wub7b8bda2012-04-17 17:20:48 +08001145 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001146 drm_output_release_fb(output, output->current);
1147 drm_output_release_fb(output, output->next);
1148 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001149
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001150 if (ec->use_pixman) {
1151 drm_output_fini_pixman(output);
1152 if (drm_output_init_pixman(output, ec) < 0) {
1153 weston_log("failed to init output pixman state with "
1154 "new mode\n");
1155 return -1;
1156 }
1157 } else {
1158 gl_renderer_output_destroy(&output->base);
1159 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001160
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001161 if (drm_output_init_egl(output, ec) < 0) {
1162 weston_log("failed to init output egl state with "
1163 "new mode");
1164 return -1;
1165 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001166 }
1167
Alex Wub7b8bda2012-04-17 17:20:48 +08001168 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001169}
1170
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001171static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001172on_drm_input(int fd, uint32_t mask, void *data)
1173{
1174 drmEventContext evctx;
1175
1176 memset(&evctx, 0, sizeof evctx);
1177 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1178 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001179 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001180 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001181
1182 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001183}
1184
1185static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001186init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001187{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001188 const char *filename, *sysnum;
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001189 int fd;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001190
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001191 sysnum = udev_device_get_sysnum(device);
1192 if (sysnum)
1193 ec->drm.id = atoi(sysnum);
1194 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001195 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001196 return -1;
1197 }
1198
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001199 filename = udev_device_get_devnode(device);
David Herrmann63ff7062011-11-05 18:46:01 +01001200 fd = open(filename, O_RDWR | O_CLOEXEC);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001201 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001202 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001203 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001204 udev_device_get_devnode(device));
1205 return -1;
1206 }
1207
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001208 weston_log("using %s\n", filename);
1209
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001210 ec->drm.fd = fd;
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001211
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001212
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001213 return 0;
1214}
1215
1216static int
1217init_egl(struct drm_compositor *ec)
1218{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001219 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001220
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001221 if (!ec->gbm)
1222 return -1;
1223
John Kåre Alsaker779b52a2012-11-13 19:10:29 +01001224 if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001225 NULL) < 0) {
1226 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001227 return -1;
1228 }
1229
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001230 return 0;
1231}
1232
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001233static int
1234init_pixman(struct drm_compositor *ec)
1235{
1236 return pixman_renderer_init(&ec->base);
1237}
1238
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001239static struct drm_mode *
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001240drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1241{
1242 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001243 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001244
1245 mode = malloc(sizeof *mode);
1246 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001247 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001248
1249 mode->base.flags = 0;
1250 mode->base.width = info->hdisplay;
1251 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001252
1253 /* Calculate higher precision (mHz) refresh rate */
1254 refresh = (info->clock * 1000000LL / info->htotal +
1255 info->vtotal / 2) / info->vtotal;
1256
1257 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1258 refresh *= 2;
1259 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1260 refresh /= 2;
1261 if (info->vscan > 1)
1262 refresh /= info->vscan;
1263
1264 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001265 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001266
1267 if (info->type & DRM_MODE_TYPE_PREFERRED)
1268 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1269
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001270 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1271
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001272 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001273}
1274
1275static int
1276drm_subpixel_to_wayland(int drm_value)
1277{
1278 switch (drm_value) {
1279 default:
1280 case DRM_MODE_SUBPIXEL_UNKNOWN:
1281 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1282 case DRM_MODE_SUBPIXEL_NONE:
1283 return WL_OUTPUT_SUBPIXEL_NONE;
1284 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1285 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1286 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1287 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1288 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1289 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1290 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1291 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1292 }
1293}
1294
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001295/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001296static uint32_t
1297drm_get_backlight(struct drm_output *output)
1298{
1299 long brightness, max_brightness, norm;
1300
1301 brightness = backlight_get_brightness(output->backlight);
1302 max_brightness = backlight_get_max_brightness(output->backlight);
1303
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001304 /* convert it on a scale of 0 to 255 */
1305 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001306
1307 return (uint32_t) norm;
1308}
1309
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001310/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001311static void
1312drm_set_backlight(struct weston_output *output_base, uint32_t value)
1313{
1314 struct drm_output *output = (struct drm_output *) output_base;
1315 long max_brightness, new_brightness;
1316
1317 if (!output->backlight)
1318 return;
1319
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001320 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001321 return;
1322
1323 max_brightness = backlight_get_max_brightness(output->backlight);
1324
1325 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001326 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001327
1328 backlight_set_brightness(output->backlight, new_brightness);
1329}
1330
1331static drmModePropertyPtr
1332drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1333{
1334 drmModePropertyPtr props;
1335 int i;
1336
1337 for (i = 0; i < connector->count_props; i++) {
1338 props = drmModeGetProperty(fd, connector->props[i]);
1339 if (!props)
1340 continue;
1341
1342 if (!strcmp(props->name, name))
1343 return props;
1344
1345 drmModeFreeProperty(props);
1346 }
1347
1348 return NULL;
1349}
1350
1351static void
1352drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1353{
1354 struct drm_output *output = (struct drm_output *) output_base;
1355 struct weston_compositor *ec = output_base->compositor;
1356 struct drm_compositor *c = (struct drm_compositor *) ec;
1357 drmModeConnectorPtr connector;
1358 drmModePropertyPtr prop;
1359
1360 connector = drmModeGetConnector(c->drm.fd, output->connector_id);
1361 if (!connector)
1362 return;
1363
1364 prop = drm_get_prop(c->drm.fd, connector, "DPMS");
1365 if (!prop) {
1366 drmModeFreeConnector(connector);
1367 return;
1368 }
1369
1370 drmModeConnectorSetProperty(c->drm.fd, connector->connector_id,
1371 prop->prop_id, level);
1372 drmModeFreeProperty(prop);
1373 drmModeFreeConnector(connector);
1374}
1375
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001376static const char *connector_type_names[] = {
1377 "None",
1378 "VGA",
1379 "DVI",
1380 "DVI",
1381 "DVI",
1382 "Composite",
1383 "TV",
1384 "LVDS",
1385 "CTV",
1386 "DIN",
1387 "DP",
1388 "HDMI",
1389 "HDMI",
1390 "TV",
1391 "eDP",
1392};
1393
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001394static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001395find_crtc_for_connector(struct drm_compositor *ec,
1396 drmModeRes *resources, drmModeConnector *connector)
1397{
1398 drmModeEncoder *encoder;
1399 uint32_t possible_crtcs;
1400 int i, j;
1401
1402 for (j = 0; j < connector->count_encoders; j++) {
1403 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1404 if (encoder == NULL) {
1405 weston_log("Failed to get encoder.\n");
1406 return -1;
1407 }
1408 possible_crtcs = encoder->possible_crtcs;
1409 drmModeFreeEncoder(encoder);
1410
1411 for (i = 0; i < resources->count_crtcs; i++) {
1412 if (possible_crtcs & (1 << i) &&
1413 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1414 return i;
1415 }
1416 }
1417
1418 return -1;
1419}
1420
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001421/* Init output state that depends on gl or gbm */
1422static int
1423drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1424{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001425 int i, flags;
1426
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001427 output->surface = gbm_surface_create(ec->gbm,
1428 output->base.current->width,
1429 output->base.current->height,
1430 GBM_FORMAT_XRGB8888,
1431 GBM_BO_USE_SCANOUT |
1432 GBM_BO_USE_RENDERING);
1433 if (!output->surface) {
1434 weston_log("failed to create gbm surface\n");
1435 return -1;
1436 }
1437
1438 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001439 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001440 gbm_surface_destroy(output->surface);
1441 return -1;
1442 }
1443
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001444 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1445
1446 for (i = 0; i < 2; i++) {
1447 if (output->cursor_bo[i])
1448 continue;
1449
1450 output->cursor_bo[i] =
1451 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1452 flags);
1453 }
1454
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001455 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1456 weston_log("cursor buffers unavailable, using gl cursors\n");
1457 ec->cursors_are_broken = 1;
1458 }
1459
1460 return 0;
1461}
1462
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001463static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001464drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1465{
1466 int w = output->base.current->width;
1467 int h = output->base.current->height;
1468 unsigned int i;
1469
1470 /* FIXME error checking */
1471
1472 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1473 output->dumb[i] = drm_fb_create_dumb(c, w, h);
1474 if (!output->dumb[i])
1475 goto err;
1476
1477 output->image[i] =
1478 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
1479 output->dumb[i]->map,
1480 output->dumb[i]->stride);
1481 if (!output->image[i])
1482 goto err;
1483 }
1484
1485 if (pixman_renderer_output_create(&output->base) < 0)
1486 goto err;
1487
1488 pixman_region32_init_rect(&output->previous_damage,
1489 output->base.x, output->base.y, w, h);
1490
1491 return 0;
1492
1493err:
1494 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1495 if (output->dumb[i])
1496 drm_fb_destroy_dumb(output->dumb[i]);
1497 if (output->image[i])
1498 pixman_image_unref(output->image[i]);
1499
1500 output->dumb[i] = NULL;
1501 output->image[i] = NULL;
1502 }
1503
1504 return -1;
1505}
1506
1507static void
1508drm_output_fini_pixman(struct drm_output *output)
1509{
1510 unsigned int i;
1511
1512 pixman_renderer_output_destroy(&output->base);
1513 pixman_region32_fini(&output->previous_damage);
1514
1515 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1516 drm_fb_destroy_dumb(output->dumb[i]);
1517 pixman_image_unref(output->image[i]);
1518 output->dumb[i] = NULL;
1519 output->image[i] = NULL;
1520 }
1521}
1522
Richard Hughes2b2092a2013-04-24 14:58:02 +01001523static void
1524edid_parse_string(const uint8_t *data, char text[])
1525{
1526 int i;
1527 int replaced = 0;
1528
1529 /* this is always 12 bytes, but we can't guarantee it's null
1530 * terminated or not junk. */
1531 strncpy(text, (const char *) data, 12);
1532
1533 /* remove insane chars */
1534 for (i = 0; text[i] != '\0'; i++) {
1535 if (text[i] == '\n' ||
1536 text[i] == '\r') {
1537 text[i] = '\0';
1538 break;
1539 }
1540 }
1541
1542 /* ensure string is printable */
1543 for (i = 0; text[i] != '\0'; i++) {
1544 if (!isprint(text[i])) {
1545 text[i] = '-';
1546 replaced++;
1547 }
1548 }
1549
1550 /* if the string is random junk, ignore the string */
1551 if (replaced > 4)
1552 text[0] = '\0';
1553}
1554
1555#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1556#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1557#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1558#define EDID_OFFSET_DATA_BLOCKS 0x36
1559#define EDID_OFFSET_LAST_BLOCK 0x6c
1560#define EDID_OFFSET_PNPID 0x08
1561#define EDID_OFFSET_SERIAL 0x0c
1562
1563static int
1564edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1565{
1566 int i;
1567 uint32_t serial_number;
1568
1569 /* check header */
1570 if (length < 128)
1571 return -1;
1572 if (data[0] != 0x00 || data[1] != 0xff)
1573 return -1;
1574
1575 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1576 * /--08--\/--09--\
1577 * 7654321076543210
1578 * |\---/\---/\---/
1579 * R C1 C2 C3 */
1580 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1581 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1582 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1583 edid->pnp_id[3] = '\0';
1584
1585 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1586 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1587 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1588 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1589 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1590 if (serial_number > 0)
1591 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1592
1593 /* parse EDID data */
1594 for (i = EDID_OFFSET_DATA_BLOCKS;
1595 i <= EDID_OFFSET_LAST_BLOCK;
1596 i += 18) {
1597 /* ignore pixel clock data */
1598 if (data[i] != 0)
1599 continue;
1600 if (data[i+2] != 0)
1601 continue;
1602
1603 /* any useful blocks? */
1604 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1605 edid_parse_string(&data[i+5],
1606 edid->monitor_name);
1607 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1608 edid_parse_string(&data[i+5],
1609 edid->serial_number);
1610 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1611 edid_parse_string(&data[i+5],
1612 edid->eisa_id);
1613 }
1614 }
1615 return 0;
1616}
1617
1618static void
1619find_and_parse_output_edid(struct drm_compositor *ec,
1620 struct drm_output *output,
1621 drmModeConnector *connector)
1622{
1623 drmModePropertyBlobPtr edid_blob = NULL;
1624 drmModePropertyPtr property;
1625 int i;
1626 int rc;
1627
1628 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1629 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1630 if (!property)
1631 continue;
1632 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1633 !strcmp(property->name, "EDID")) {
1634 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1635 connector->prop_values[i]);
1636 }
1637 drmModeFreeProperty(property);
1638 }
1639 if (!edid_blob)
1640 return;
1641
1642 rc = edid_parse(&output->edid,
1643 edid_blob->data,
1644 edid_blob->length);
1645 if (!rc) {
1646 weston_log("EDID data '%s', '%s', '%s'\n",
1647 output->edid.pnp_id,
1648 output->edid.monitor_name,
1649 output->edid.serial_number);
1650 if (output->edid.pnp_id[0] != '\0')
1651 output->base.make = output->edid.pnp_id;
1652 if (output->edid.monitor_name[0] != '\0')
1653 output->base.model = output->edid.monitor_name;
1654 if (output->edid.serial_number[0] != '\0')
1655 output->base.serial_number = output->edid.serial_number;
1656 }
1657 drmModeFreePropertyBlob(edid_blob);
1658}
1659
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001660static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001661create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001662 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001663 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001664 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001665{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001666 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001667 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1668 struct weston_mode *m;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001669 struct drm_configured_output *o = NULL, *temp;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001670 drmModeEncoder *encoder;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001671 drmModeModeInfo crtc_mode;
1672 drmModeCrtc *crtc;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001673 int i;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001674 char name[32];
1675 const char *type_name;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001676
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001677 i = find_crtc_for_connector(ec, resources, connector);
1678 if (i < 0) {
1679 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001680 return -1;
1681 }
1682
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001683 output = malloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001684 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001685 return -1;
1686
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001687 memset(output, 0, sizeof *output);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001688 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1689 output->base.make = "unknown";
1690 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001691 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001692 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001693
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001694 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1695 type_name = connector_type_names[connector->connector_type];
1696 else
1697 type_name = "UNKNOWN";
1698 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
1699 output->name = strdup(name);
1700
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001701 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001702 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001703 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001704 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001705 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001706
Matt Roper361d2ad2011-08-29 13:52:23 -07001707 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
1708
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001709 /* Get the current mode on the crtc that's currently driving
1710 * this connector. */
1711 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001712 memset(&crtc_mode, 0, sizeof crtc_mode);
1713 if (encoder != NULL) {
1714 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1715 drmModeFreeEncoder(encoder);
1716 if (crtc == NULL)
1717 goto err_free;
1718 if (crtc->mode_valid)
1719 crtc_mode = crtc->mode;
1720 drmModeFreeCrtc(crtc);
1721 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001722
David Herrmann0f0d54e2011-12-08 17:05:45 +01001723 for (i = 0; i < connector->count_modes; i++) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001724 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
1725 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001726 goto err_free;
1727 }
1728
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001729 preferred = NULL;
1730 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001731 configured = NULL;
1732
1733 wl_list_for_each(temp, &configured_output_list, link) {
1734 if (strcmp(temp->name, output->name) == 0) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001735 if (temp->mode)
1736 weston_log("%s mode \"%s\" in config\n",
Scott Moreau8ab5d452012-07-30 19:51:08 -06001737 temp->name, temp->mode);
1738 o = temp;
1739 break;
1740 }
1741 }
1742
Ander Conselvan de Oliveiradc79e6d2012-08-09 16:45:01 +03001743 if (o && o->config == OUTPUT_CONFIG_OFF) {
Scott Moreau8ab5d452012-07-30 19:51:08 -06001744 weston_log("Disabling output %s\n", o->name);
1745
1746 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1747 0, 0, 0, 0, 0, NULL);
1748 goto err_free;
1749 }
1750
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001751 wl_list_for_each(drm_mode, &output->base.mode_list, base.link) {
Scott Moreau1bad5db2012-08-18 01:04:05 -06001752 if (o && o->config == OUTPUT_CONFIG_MODE &&
1753 o->width == drm_mode->base.width &&
1754 o->height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001755 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001756 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001757 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001758 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001759 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001760 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001761
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001762 if (o && o->config == OUTPUT_CONFIG_MODELINE) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001763 configured = drm_output_add_mode(output, &o->crtc_mode);
1764 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001765 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001766 current = configured;
1767 }
1768
Wang Quanxianacb805a2012-07-30 18:09:46 -04001769 if (current == NULL && crtc_mode.clock != 0) {
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001770 current = drm_output_add_mode(output, &crtc_mode);
1771 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001772 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001773 }
1774
Scott Moreau8ab5d452012-07-30 19:51:08 -06001775 if (o && o->config == OUTPUT_CONFIG_CURRENT)
1776 configured = current;
1777
Wang Quanxianacb805a2012-07-30 18:09:46 -04001778 if (option_current_mode && current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001779 output->base.current = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001780 else if (configured)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001781 output->base.current = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001782 else if (preferred)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001783 output->base.current = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001784 else if (current)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001785 output->base.current = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001786
1787 if (output->base.current == NULL) {
1788 weston_log("no available modes for %s\n", output->name);
1789 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001790 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001791
Wang Quanxianacb805a2012-07-30 18:09:46 -04001792 output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
1793
John Kåre Alsaker94659272012-11-13 19:10:18 +01001794 weston_output_init(&output->base, &ec->base, x, y,
1795 connector->mmWidth, connector->mmHeight,
1796 o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
1797
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001798 if (ec->use_pixman) {
1799 if (drm_output_init_pixman(output, ec) < 0) {
1800 weston_log("Failed to init output pixman state\n");
1801 goto err_output;
1802 }
1803 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001804 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001805 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001806 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001807
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001808 output->backlight = backlight_init(drm_device,
1809 connector->connector_type);
1810 if (output->backlight) {
1811 output->base.set_backlight = drm_set_backlight;
1812 output->base.backlight_current = drm_get_backlight(output);
1813 }
1814
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001815 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1816
Richard Hughes2b2092a2013-04-24 14:58:02 +01001817 find_and_parse_output_edid(ec, output, connector);
1818
Alex Wubd3354b2012-04-17 17:20:49 +08001819 output->base.origin = output->base.current;
Jonas Ådahle5a12252013-04-05 23:07:11 +02001820 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001821 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001822 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001823 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001824 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001825 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001826
Richard Hughese7299962013-05-01 21:52:12 +01001827 output->base.gamma_size = output->original_crtc->gamma_size;
1828 output->base.set_gamma = drm_output_set_gamma;
1829
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001830 weston_plane_init(&output->cursor_plane, 0, 0);
1831 weston_plane_init(&output->fb_plane, 0, 0);
1832
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001833 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1834 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1835 &ec->base.primary_plane);
1836
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001837 weston_log("Output %s, (connector %d, crtc %d)\n",
1838 output->name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001839 wl_list_for_each(m, &output->base.mode_list, link)
1840 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1841 m->width, m->height, m->refresh / 1000.0,
1842 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1843 ", preferred" : "",
1844 m->flags & WL_OUTPUT_MODE_CURRENT ?
1845 ", current" : "",
1846 connector->count_modes == 0 ?
1847 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001848
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001849 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001850
John Kåre Alsaker94659272012-11-13 19:10:18 +01001851err_output:
1852 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001853err_free:
1854 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1855 base.link) {
1856 wl_list_remove(&drm_mode->base.link);
1857 free(drm_mode);
1858 }
1859
1860 drmModeFreeCrtc(output->original_crtc);
1861 ec->crtc_allocator &= ~(1 << output->crtc_id);
1862 ec->connector_allocator &= ~(1 << output->connector_id);
Kristian Høgsberg148ef012012-07-26 23:03:57 -04001863 free(output->name);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001864 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001865
David Herrmann0f0d54e2011-12-08 17:05:45 +01001866 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001867}
1868
Jesse Barnes58ef3792012-02-23 09:45:49 -05001869static void
1870create_sprites(struct drm_compositor *ec)
1871{
1872 struct drm_sprite *sprite;
1873 drmModePlaneRes *plane_res;
1874 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001875 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001876
1877 plane_res = drmModeGetPlaneResources(ec->drm.fd);
1878 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02001879 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001880 strerror(errno));
1881 return;
1882 }
1883
1884 for (i = 0; i < plane_res->count_planes; i++) {
1885 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
1886 if (!plane)
1887 continue;
1888
1889 sprite = malloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
1890 plane->count_formats));
1891 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02001892 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05001893 __func__);
1894 free(plane);
1895 continue;
1896 }
1897
1898 memset(sprite, 0, sizeof *sprite);
1899
1900 sprite->possible_crtcs = plane->possible_crtcs;
1901 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02001902 sprite->current = NULL;
1903 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001904 sprite->compositor = ec;
1905 sprite->count_formats = plane->count_formats;
1906 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05001907 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05001908 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001909 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001910 weston_compositor_stack_plane(&ec->base, &sprite->plane,
1911 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001912
1913 wl_list_insert(&ec->sprite_list, &sprite->link);
1914 }
1915
1916 free(plane_res->planes);
1917 free(plane_res);
1918}
1919
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001920static void
1921destroy_sprites(struct drm_compositor *compositor)
1922{
1923 struct drm_sprite *sprite, *next;
1924 struct drm_output *output;
1925
1926 output = container_of(compositor->base.output_list.next,
1927 struct drm_output, base.link);
1928
1929 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
1930 drmModeSetPlane(compositor->drm.fd,
1931 sprite->plane_id,
1932 output->crtc_id, 0, 0,
1933 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001934 drm_output_release_fb(output, sprite->current);
1935 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001936 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05001937 free(sprite);
1938 }
1939}
Jesse Barnes58ef3792012-02-23 09:45:49 -05001940
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001941static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001942create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001943 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001944{
1945 drmModeConnector *connector;
1946 drmModeRes *resources;
1947 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001948 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001949
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001950 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001951 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02001952 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001953 return -1;
1954 }
1955
Jesse Barnes58ef3792012-02-23 09:45:49 -05001956 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001957 if (!ec->crtcs) {
1958 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001959 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001960 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05001961
Rob Clark4339add2012-08-09 14:18:28 -05001962 ec->min_width = resources->min_width;
1963 ec->max_width = resources->max_width;
1964 ec->min_height = resources->min_height;
1965 ec->max_height = resources->max_height;
1966
Jesse Barnes58ef3792012-02-23 09:45:49 -05001967 ec->num_crtcs = resources->count_crtcs;
1968 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
1969
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001970 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02001971 connector = drmModeGetConnector(ec->drm.fd,
1972 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001973 if (connector == NULL)
1974 continue;
1975
1976 if (connector->connection == DRM_MODE_CONNECTED &&
1977 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001978 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001979 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001980 connector, x, y,
1981 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02001982 drmModeFreeConnector(connector);
1983 continue;
1984 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001985
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001986 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001987 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06001988 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02001989 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001990
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001991 drmModeFreeConnector(connector);
1992 }
1993
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001994 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02001995 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05001996 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001997 return -1;
1998 }
1999
2000 drmModeFreeResources(resources);
2001
2002 return 0;
2003}
2004
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002005static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002006update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002007{
2008 drmModeConnector *connector;
2009 drmModeRes *resources;
2010 struct drm_output *output, *next;
2011 int x = 0, y = 0;
2012 int x_offset = 0, y_offset = 0;
2013 uint32_t connected = 0, disconnects = 0;
2014 int i;
2015
2016 resources = drmModeGetResources(ec->drm.fd);
2017 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002018 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002019 return;
2020 }
2021
2022 /* collect new connects */
2023 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002024 int connector_id = resources->connectors[i];
2025
2026 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002027 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002028 continue;
2029
David Herrmann7551cff2011-12-08 17:05:43 +01002030 if (connector->connection != DRM_MODE_CONNECTED) {
2031 drmModeFreeConnector(connector);
2032 continue;
2033 }
2034
Benjamin Franzke117483d2011-08-30 11:38:26 +02002035 connected |= (1 << connector_id);
2036
2037 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002038 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002039 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002040 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002041
2042 /* XXX: not yet needed, we die with 0 outputs */
2043 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002044 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002045 else
2046 x = 0;
2047 y = 0;
2048 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002049 connector, x, y,
2050 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002051 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002052
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002053 }
2054 drmModeFreeConnector(connector);
2055 }
2056 drmModeFreeResources(resources);
2057
2058 disconnects = ec->connector_allocator & ~connected;
2059 if (disconnects) {
2060 wl_list_for_each_safe(output, next, &ec->base.output_list,
2061 base.link) {
2062 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002063 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002064 output->base.x - x_offset,
2065 output->base.y - y_offset);
2066 }
2067
2068 if (disconnects & (1 << output->connector_id)) {
2069 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002070 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002071 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002072 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002073 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002074 }
2075 }
2076 }
2077
2078 /* FIXME: handle zero outputs, without terminating */
2079 if (ec->connector_allocator == 0)
2080 wl_display_terminate(ec->base.wl_display);
2081}
2082
2083static int
David Herrmannd7488c22012-03-11 20:05:21 +01002084udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002085{
David Herrmannd7488c22012-03-11 20:05:21 +01002086 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002087 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002088
2089 sysnum = udev_device_get_sysnum(device);
2090 if (!sysnum || atoi(sysnum) != ec->drm.id)
2091 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002092
David Herrmann6ac52db2012-03-11 20:05:22 +01002093 val = udev_device_get_property_value(device, "HOTPLUG");
2094 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002095 return 0;
2096
David Herrmann6ac52db2012-03-11 20:05:22 +01002097 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002098}
2099
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002100static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002101udev_drm_event(int fd, uint32_t mask, void *data)
2102{
2103 struct drm_compositor *ec = data;
2104 struct udev_device *event;
2105
2106 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002107
David Herrmannd7488c22012-03-11 20:05:21 +01002108 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002109 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002110
2111 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002112
2113 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002114}
2115
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002116static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002117drm_restore(struct weston_compositor *ec)
2118{
2119 struct drm_compositor *d = (struct drm_compositor *) ec;
2120
2121 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
2122 weston_log("failed to drop master: %m\n");
2123 tty_reset(d->tty);
2124}
2125
2126static void
Scott Moreauc50645c2012-07-31 22:29:56 -06002127drm_free_configured_output(struct drm_configured_output *output)
2128{
2129 free(output->name);
2130 free(output->mode);
2131 free(output);
2132}
2133
2134static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002135drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002136{
2137 struct drm_compositor *d = (struct drm_compositor *) ec;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002138 struct udev_seat *seat, *next;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002139 struct drm_configured_output *o, *n;
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002140
Kristian Høgsberge8091032013-02-18 15:43:29 -05002141 wl_list_for_each_safe(seat, next, &ec->seat_list, base.link)
2142 udev_seat_destroy(seat);
Scott Moreau8ab5d452012-07-30 19:51:08 -06002143 wl_list_for_each_safe(o, n, &configured_output_list, link)
Scott Moreauc50645c2012-07-31 22:29:56 -06002144 drm_free_configured_output(o);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002145
2146 wl_event_source_remove(d->udev_drm_source);
2147 wl_event_source_remove(d->drm_source);
2148
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002149 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002150
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002151 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002152
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002153 destroy_sprites(d);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002154
2155 if (d->gbm)
2156 gbm_device_destroy(d->gbm);
2157
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002158 if (weston_launcher_drm_set_master(&d->base, d->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002159 weston_log("failed to drop master: %m\n");
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002160 tty_destroy(d->tty);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002161
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002162 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002163}
2164
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002165static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002166drm_compositor_set_modes(struct drm_compositor *compositor)
2167{
2168 struct drm_output *output;
2169 struct drm_mode *drm_mode;
2170 int ret;
2171
2172 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002173 if (!output->current) {
2174 /* If something that would cause the output to
2175 * switch mode happened while in another vt, we
2176 * might not have a current drm_fb. In that case,
2177 * schedule a repaint and let drm_output_repaint
2178 * handle setting the mode. */
2179 weston_output_schedule_repaint(&output->base);
2180 continue;
2181 }
2182
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002183 drm_mode = (struct drm_mode *) output->base.current;
2184 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002185 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002186 &output->connector_id, 1,
2187 &drm_mode->mode_info);
2188 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002189 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002190 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002191 drm_mode->base.width, drm_mode->base.height,
2192 output->base.x, output->base.y);
2193 }
2194 }
2195}
2196
2197static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002198vt_func(struct weston_compositor *compositor, int event)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002199{
2200 struct drm_compositor *ec = (struct drm_compositor *) compositor;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002201 struct udev_seat *seat;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002202 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002203 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002204
2205 switch (event) {
2206 case TTY_ENTER_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002207 weston_log("entering VT\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002208 compositor->focus = 1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002209 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 1)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002210 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002211 wl_display_terminate(compositor->wl_display);
2212 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002213 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002214 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002215 weston_compositor_damage_all(compositor);
Kristian Høgsberg87644662013-02-18 16:50:19 -05002216 wl_list_for_each(seat, &compositor->seat_list, base.link)
2217 udev_seat_enable(seat, ec->udev);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002218 break;
2219 case TTY_LEAVE_VT:
Pekka Paalanen81a13a32012-08-03 14:39:10 +03002220 weston_log("leaving VT\n");
Kristian Høgsberg87644662013-02-18 16:50:19 -05002221 wl_list_for_each(seat, &compositor->seat_list, base.link)
2222 udev_seat_disable(seat);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002223
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002224 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002225 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002226 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002227
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002228 /* If we have a repaint scheduled (either from a
2229 * pending pageflip or the idle handler), make sure we
2230 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002231 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002232 * further attemps at repainting. When we switch
2233 * back, we schedule a repaint, which will process
2234 * pending frame callbacks. */
2235
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002236 wl_list_for_each(output, &ec->base.output_list, base.link) {
2237 output->base.repaint_needed = 0;
2238 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002239 }
2240
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002241 output = container_of(ec->base.output_list.next,
2242 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002243
2244 wl_list_for_each(sprite, &ec->sprite_list, link)
2245 drmModeSetPlane(ec->drm.fd,
2246 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002247 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002248 0, 0, 0, 0, 0, 0, 0, 0);
2249
Benjamin Franzkebfeda132012-01-30 14:04:04 +01002250 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002251 weston_log("failed to drop master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002252
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002253 break;
2254 };
2255}
2256
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002257static void
Daniel Stone325fc2d2012-05-30 16:31:58 +01002258switch_vt_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002259{
2260 struct drm_compositor *ec = data;
2261
Daniel Stone325fc2d2012-05-30 16:31:58 +01002262 tty_activate_vt(ec->tty, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002263}
2264
David Herrmann0af066f2012-10-29 19:21:16 +01002265/*
2266 * Find primary GPU
2267 * Some systems may have multiple DRM devices attached to a single seat. This
2268 * function loops over all devices and tries to find a PCI device with the
2269 * boot_vga sysfs attribute set to 1.
2270 * If no such device is found, the first DRM device reported by udev is used.
2271 */
2272static struct udev_device*
2273find_primary_gpu(struct drm_compositor *ec, const char *seat)
2274{
2275 struct udev_enumerate *e;
2276 struct udev_list_entry *entry;
2277 const char *path, *device_seat, *id;
2278 struct udev_device *device, *drm_device, *pci;
2279
2280 e = udev_enumerate_new(ec->udev);
2281 udev_enumerate_add_match_subsystem(e, "drm");
2282 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2283
2284 udev_enumerate_scan_devices(e);
2285 drm_device = NULL;
2286 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2287 path = udev_list_entry_get_name(entry);
2288 device = udev_device_new_from_syspath(ec->udev, path);
2289 if (!device)
2290 continue;
2291 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2292 if (!device_seat)
2293 device_seat = default_seat;
2294 if (strcmp(device_seat, seat)) {
2295 udev_device_unref(device);
2296 continue;
2297 }
2298
2299 pci = udev_device_get_parent_with_subsystem_devtype(device,
2300 "pci", NULL);
2301 if (pci) {
2302 id = udev_device_get_sysattr_value(pci, "boot_vga");
2303 if (id && !strcmp(id, "1")) {
2304 if (drm_device)
2305 udev_device_unref(drm_device);
2306 drm_device = device;
2307 break;
2308 }
2309 }
2310
2311 if (!drm_device)
2312 drm_device = device;
2313 else
2314 udev_device_unref(device);
2315 }
2316
2317 udev_enumerate_unref(e);
2318 return drm_device;
2319}
2320
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002321static void
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002322planes_binding(struct wl_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002323{
2324 struct drm_compositor *c = data;
2325
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002326 switch (key) {
2327 case KEY_C:
2328 c->cursors_are_broken ^= 1;
2329 break;
2330 case KEY_V:
2331 c->sprites_are_broken ^= 1;
2332 break;
2333 case KEY_O:
2334 c->sprites_hidden ^= 1;
2335 break;
2336 default:
2337 break;
2338 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002339}
2340
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002341static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002342drm_compositor_create(struct wl_display *display,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002343 int connector, const char *seat, int tty, int pixman,
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002344 int *argc, char *argv[], const char *config_file)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002345{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002346 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002347 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002348 struct wl_event_loop *loop;
Kristian Høgsberge8091032013-02-18 15:43:29 -05002349 struct udev_seat *udev_seat, *next;
David Herrmann0af066f2012-10-29 19:21:16 +01002350 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002351 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002352
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002353 weston_log("initializing drm backend\n");
2354
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002355 ec = malloc(sizeof *ec);
2356 if (ec == NULL)
2357 return NULL;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002358 memset(ec, 0, sizeof *ec);
Daniel Stone725c2c32012-06-22 14:04:36 +01002359
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002360 /* KMS support for sprites is not complete yet, so disable the
2361 * functionality for now. */
2362 ec->sprites_are_broken = 1;
2363
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002364 ec->use_pixman = pixman;
2365
Daniel Stone725c2c32012-06-22 14:04:36 +01002366 if (weston_compositor_init(&ec->base, display, argc, argv,
Daniel Stonea96b93c2012-06-22 14:04:37 +01002367 config_file) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002368 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002369 goto err_base;
2370 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002371
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002372 /* Check if we run drm-backend using weston-launch */
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002373 if (ec->base.launcher_sock == -1 && geteuid() != 0) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002374 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002375 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002376 goto err_compositor;
2377 }
2378
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002379 ec->udev = udev_new();
2380 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002381 weston_log("failed to initialize udev context\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002382 goto err_compositor;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002383 }
2384
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002385 ec->base.wl_display = display;
2386 ec->tty = tty_create(&ec->base, vt_func, tty);
2387 if (!ec->tty) {
Martin Minarik6d118362012-06-07 18:01:59 +02002388 weston_log("failed to initialize tty\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002389 goto err_udev;
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002390 }
2391
David Herrmann0af066f2012-10-29 19:21:16 +01002392 drm_device = find_primary_gpu(ec, seat);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002393 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002394 weston_log("no drm device found\n");
David Herrmann0af066f2012-10-29 19:21:16 +01002395 goto err_tty;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002396 }
David Herrmann0af066f2012-10-29 19:21:16 +01002397 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002398
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002399 if (init_drm(ec, drm_device) < 0) {
2400 weston_log("failed to initialize kms\n");
2401 goto err_udev_dev;
2402 }
2403
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002404 if (ec->use_pixman) {
2405 if (init_pixman(ec) < 0) {
2406 weston_log("failed to initialize pixman renderer\n");
2407 goto err_udev_dev;
2408 }
2409 } else {
2410 if (init_egl(ec) < 0) {
2411 weston_log("failed to initialize egl\n");
2412 goto err_udev_dev;
2413 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002414 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002415
2416 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002417 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002418
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002419 ec->base.focus = 1;
2420
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002421 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002422
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002423 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002424 weston_compositor_add_key_binding(&ec->base, key,
2425 MODIFIER_CTRL | MODIFIER_ALT,
2426 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002427
Jesse Barnes58ef3792012-02-23 09:45:49 -05002428 wl_list_init(&ec->sprite_list);
2429 create_sprites(ec);
2430
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002431 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002432 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002433 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002434 }
2435
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002436 path = NULL;
2437
Kristian Høgsberge8091032013-02-18 15:43:29 -05002438 if (udev_seat_create(&ec->base, ec->udev, seat) == NULL) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002439 weston_log("failed to create input devices\n");
2440 goto err_sprite;
2441 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002442
2443 loop = wl_display_get_event_loop(ec->base.wl_display);
2444 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002445 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002446 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002447
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002448 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2449 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002450 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002451 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002452 }
2453 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2454 "drm", NULL);
2455 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002456 wl_event_loop_add_fd(loop,
2457 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002458 WL_EVENT_READABLE, udev_drm_event, ec);
2459
2460 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002461 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002462 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002463 }
2464
Daniel Stonea96b93c2012-06-22 14:04:37 +01002465 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002466
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002467 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002468 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002469 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002470 planes_binding, ec);
2471 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2472 planes_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002473
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002474 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002475
2476err_udev_monitor:
2477 wl_event_source_remove(ec->udev_drm_source);
2478 udev_monitor_unref(ec->udev_monitor);
2479err_drm_source:
2480 wl_event_source_remove(ec->drm_source);
Kristian Høgsberge8091032013-02-18 15:43:29 -05002481 wl_list_for_each_safe(udev_seat, next, &ec->base.seat_list, base.link)
2482 udev_seat_destroy(udev_seat);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002483err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002484 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002485 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002486 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002487err_udev_dev:
2488 udev_device_unref(drm_device);
David Herrmann0af066f2012-10-29 19:21:16 +01002489err_tty:
Kristian Høgsberg50623842013-02-18 15:02:27 -05002490 if (weston_launcher_drm_set_master(&ec->base, ec->drm.fd, 0) < 0)
2491 weston_log("failed to drop master: %m\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002492 tty_destroy(ec->tty);
2493err_udev:
2494 udev_unref(ec->udev);
2495err_compositor:
2496 weston_compositor_shutdown(&ec->base);
2497err_base:
2498 free(ec);
2499 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002500}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002501
Scott Moreau8f37e0b2012-07-31 15:30:41 -06002502static int
2503set_sync_flags(drmModeModeInfo *mode, char *hsync, char *vsync)
2504{
2505 mode->flags = 0;
2506
2507 if (strcmp(hsync, "+hsync") == 0)
2508 mode->flags |= DRM_MODE_FLAG_PHSYNC;
2509 else if (strcmp(hsync, "-hsync") == 0)
2510 mode->flags |= DRM_MODE_FLAG_NHSYNC;
2511 else
2512 return -1;
2513
2514 if (strcmp(vsync, "+vsync") == 0)
2515 mode->flags |= DRM_MODE_FLAG_PVSYNC;
2516 else if (strcmp(vsync, "-vsync") == 0)
2517 mode->flags |= DRM_MODE_FLAG_NVSYNC;
2518 else
2519 return -1;
2520
2521 return 0;
2522}
2523
2524static int
2525check_for_modeline(struct drm_configured_output *output)
2526{
2527 drmModeModeInfo mode;
2528 char hsync[16];
2529 char vsync[16];
2530 char mode_name[16];
2531 float fclock;
2532
2533 mode.type = DRM_MODE_TYPE_USERDEF;
2534 mode.hskew = 0;
2535 mode.vscan = 0;
2536 mode.vrefresh = 0;
2537
2538 if (sscanf(output_mode, "%f %hd %hd %hd %hd %hd %hd %hd %hd %s %s",
2539 &fclock, &mode.hdisplay,
2540 &mode.hsync_start,
2541 &mode.hsync_end, &mode.htotal,
2542 &mode.vdisplay,
2543 &mode.vsync_start,
2544 &mode.vsync_end, &mode.vtotal,
2545 hsync, vsync) == 11) {
2546 if (set_sync_flags(&mode, hsync, vsync))
2547 return -1;
2548
2549 sprintf(mode_name, "%dx%d", mode.hdisplay, mode.vdisplay);
2550 strcpy(mode.name, mode_name);
2551
2552 mode.clock = fclock * 1000;
2553 } else
2554 return -1;
2555
2556 output->crtc_mode = mode;
2557
2558 return 0;
2559}
2560
Scott Moreau8ab5d452012-07-30 19:51:08 -06002561static void
Scott Moreau1bad5db2012-08-18 01:04:05 -06002562drm_output_set_transform(struct drm_configured_output *output)
2563{
2564 if (!output_transform) {
2565 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2566 return;
2567 }
2568
2569 if (!strcmp(output_transform, "normal"))
2570 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2571 else if (!strcmp(output_transform, "90"))
2572 output->transform = WL_OUTPUT_TRANSFORM_90;
2573 else if (!strcmp(output_transform, "180"))
2574 output->transform = WL_OUTPUT_TRANSFORM_180;
2575 else if (!strcmp(output_transform, "270"))
2576 output->transform = WL_OUTPUT_TRANSFORM_270;
2577 else if (!strcmp(output_transform, "flipped"))
2578 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
2579 else if (!strcmp(output_transform, "flipped-90"))
2580 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
2581 else if (!strcmp(output_transform, "flipped-180"))
2582 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
2583 else if (!strcmp(output_transform, "flipped-270"))
2584 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
2585 else {
2586 weston_log("Invalid transform \"%s\" for output %s\n",
2587 output_transform, output_name);
2588 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
2589 }
2590
2591 free(output_transform);
2592 output_transform = NULL;
2593}
2594
2595static void
Scott Moreau8ab5d452012-07-30 19:51:08 -06002596output_section_done(void *data)
2597{
2598 struct drm_configured_output *output;
2599
2600 output = malloc(sizeof *output);
2601
Scott Moreau1bad5db2012-08-18 01:04:05 -06002602 if (!output || !output_name || (output_name[0] == 'X') ||
2603 (!output_mode && !output_transform)) {
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002604 free(output_name);
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002605 free(output_mode);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002606 free(output_transform);
Rob Bradford6b6795f2012-10-09 18:44:35 +01002607 free(output);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002608 output_name = NULL;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002609 output_mode = NULL;
Scott Moreau1bad5db2012-08-18 01:04:05 -06002610 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002611 return;
Kristian Høgsberg8ff69152012-07-31 22:18:28 -04002612 }
Scott Moreau8ab5d452012-07-30 19:51:08 -06002613
2614 output->config = OUTPUT_CONFIG_INVALID;
2615 output->name = output_name;
2616 output->mode = output_mode;
2617
Scott Moreau1bad5db2012-08-18 01:04:05 -06002618 if (output_mode) {
2619 if (strcmp(output_mode, "off") == 0)
2620 output->config = OUTPUT_CONFIG_OFF;
2621 else if (strcmp(output_mode, "preferred") == 0)
2622 output->config = OUTPUT_CONFIG_PREFERRED;
2623 else if (strcmp(output_mode, "current") == 0)
2624 output->config = OUTPUT_CONFIG_CURRENT;
2625 else if (sscanf(output_mode, "%dx%d",
2626 &output->width, &output->height) == 2)
2627 output->config = OUTPUT_CONFIG_MODE;
2628 else if (check_for_modeline(output) == 0)
2629 output->config = OUTPUT_CONFIG_MODELINE;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002630
Scott Moreau1bad5db2012-08-18 01:04:05 -06002631 if (output->config == OUTPUT_CONFIG_INVALID)
2632 weston_log("Invalid mode \"%s\" for output %s\n",
2633 output_mode, output_name);
2634 output_mode = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002635 }
Scott Moreau1bad5db2012-08-18 01:04:05 -06002636
2637 drm_output_set_transform(output);
2638
2639 wl_list_insert(&configured_output_list, &output->link);
2640
2641 if (output_transform)
2642 free(output_transform);
2643 output_transform = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06002644}
2645
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002646WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002647backend_init(struct wl_display *display, int *argc, char *argv[],
Daniel Stonec1be8e52012-06-01 11:14:02 -04002648 const char *config_file)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002649{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002650 int connector = 0, tty = 0, use_pixman = 0;
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002651 const char *seat = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002652
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002653 const struct weston_option drm_options[] = {
2654 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
2655 { WESTON_OPTION_STRING, "seat", 0, &seat },
2656 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002657 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002658 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002659 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002660
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002661 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002662
Scott Moreau8ab5d452012-07-30 19:51:08 -06002663 wl_list_init(&configured_output_list);
2664
2665 const struct config_key drm_config_keys[] = {
2666 { "name", CONFIG_KEY_STRING, &output_name },
2667 { "mode", CONFIG_KEY_STRING, &output_mode },
Scott Moreau1bad5db2012-08-18 01:04:05 -06002668 { "transform", CONFIG_KEY_STRING, &output_transform },
Scott Moreau8ab5d452012-07-30 19:51:08 -06002669 };
2670
2671 const struct config_section config_section[] = {
2672 { "output", drm_config_keys,
2673 ARRAY_LENGTH(drm_config_keys), output_section_done },
2674 };
2675
2676 parse_config_file(config_file, config_section,
2677 ARRAY_LENGTH(config_section), NULL);
2678
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002679 return drm_compositor_create(display, connector, seat, tty, use_pixman,
2680 argc, argv, config_file);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002681}