blob: 154e15e4c79ba40d70c98b6688d8720a0892f3c1 [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
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020044#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040045#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020046
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050050#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030054#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
55#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
56#endif
57
Kristian Høgsberg061c4252012-06-28 11:28:15 -040058static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060059
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
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050070 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
72 struct udev *udev;
73 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010075 struct udev_monitor *udev_monitor;
76 struct wl_event_source *udev_drm_source;
77
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010079 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030081 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020083 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050084 uint32_t *crtcs;
85 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050086 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010087 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070088 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -070089 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020095 uint32_t min_width, max_width;
96 uint32_t min_height, max_height;
97 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050098
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200101 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102
Rob Clarkab5b1e32012-08-09 13:24:45 -0500103 int cursors_are_broken;
104
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200105 int use_pixman;
106
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200107 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300108
109 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100110 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400111};
112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400115 drmModeModeInfo mode_info;
116};
117
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118struct drm_output;
119
120struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122 uint32_t fb_id, stride, handle, size;
123 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200125 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200126
127 /* Used by gbm fbs */
128 struct gbm_bo *bo;
129
130 /* Used by dumb fbs */
131 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132};
133
Richard Hughes2b2092a2013-04-24 14:58:02 +0100134struct drm_edid {
135 char eisa_id[13];
136 char monitor_name[13];
137 char pnp_id[5];
138 char serial_number[13];
139};
140
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400141struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500142 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500145 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700147 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100148 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300149 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200150
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300151 int vblank_pending;
152 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800153 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300154
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400155 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400156 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400157 struct weston_plane cursor_plane;
158 struct weston_plane fb_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500159 struct weston_view *cursor_view;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400160 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300161 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200162 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200163
164 struct drm_fb *dumb[2];
165 pixman_image_t *image[2];
166 int current_image;
167 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300168
169 struct vaapi_recorder *recorder;
170 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400171};
172
Jesse Barnes58ef3792012-02-23 09:45:49 -0500173/*
174 * An output has a primary display plane plus zero or more sprites for
175 * blending display contents.
176 */
177struct drm_sprite {
178 struct wl_list link;
179
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400180 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200182 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300183 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184 struct drm_compositor *compositor;
185
Jesse Barnes58ef3792012-02-23 09:45:49 -0500186 uint32_t possible_crtcs;
187 uint32_t plane_id;
188 uint32_t count_formats;
189
190 int32_t src_x, src_y;
191 uint32_t src_w, src_h;
192 uint32_t dest_x, dest_y;
193 uint32_t dest_w, dest_h;
194
195 uint32_t formats[];
196};
197
Kristian Høgsbergd8e98332013-10-16 16:15:11 -0700198struct drm_parameters {
199 int connector;
200 int tty;
201 int use_pixman;
202 const char *seat_id;
203};
204
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300205static struct gl_renderer_interface *gl_renderer;
206
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500207static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400208
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400209static void
210drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400211
Jesse Barnes58ef3792012-02-23 09:45:49 -0500212static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500213drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
214{
215 struct weston_compositor *ec = output_base->compositor;
216 struct drm_compositor *c =(struct drm_compositor *) ec;
217 struct drm_output *output = (struct drm_output *) output_base;
218 int crtc;
219
220 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
221 if (c->crtcs[crtc] != output->crtc_id)
222 continue;
223
224 if (supported & (1 << crtc))
225 return -1;
226 }
227
228 return 0;
229}
230
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300231static void
232drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
233{
234 struct drm_fb *fb = data;
235 struct gbm_device *gbm = gbm_bo_get_device(bo);
236
237 if (fb->fb_id)
238 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
239
Pekka Paalanende685b82012-12-04 15:58:12 +0200240 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300241
242 free(data);
243}
244
245static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200246drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
247{
248 struct drm_fb *fb;
249 int ret;
250
251 struct drm_mode_create_dumb create_arg;
252 struct drm_mode_destroy_dumb destroy_arg;
253 struct drm_mode_map_dumb map_arg;
254
Peter Huttererf3d62272013-08-08 11:57:05 +1000255 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200256 if (!fb)
257 return NULL;
258
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700259 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200260 create_arg.bpp = 32;
261 create_arg.width = width;
262 create_arg.height = height;
263
264 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
265 if (ret)
266 goto err_fb;
267
268 fb->handle = create_arg.handle;
269 fb->stride = create_arg.pitch;
270 fb->size = create_arg.size;
271 fb->fd = ec->drm.fd;
272
273 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
274 fb->stride, fb->handle, &fb->fb_id);
275 if (ret)
276 goto err_bo;
277
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700278 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200279 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400280 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200281 if (ret)
282 goto err_add_fb;
283
284 fb->map = mmap(0, fb->size, PROT_WRITE,
285 MAP_SHARED, ec->drm.fd, map_arg.offset);
286 if (fb->map == MAP_FAILED)
287 goto err_add_fb;
288
289 return fb;
290
291err_add_fb:
292 drmModeRmFB(ec->drm.fd, fb->fb_id);
293err_bo:
294 memset(&destroy_arg, 0, sizeof(destroy_arg));
295 destroy_arg.handle = create_arg.handle;
296 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
297err_fb:
298 free(fb);
299 return NULL;
300}
301
302static void
303drm_fb_destroy_dumb(struct drm_fb *fb)
304{
305 struct drm_mode_destroy_dumb destroy_arg;
306
307 if (!fb->map)
308 return;
309
310 if (fb->fb_id)
311 drmModeRmFB(fb->fd, fb->fb_id);
312
313 weston_buffer_reference(&fb->buffer_ref, NULL);
314
315 munmap(fb->map, fb->size);
316
317 memset(&destroy_arg, 0, sizeof(destroy_arg));
318 destroy_arg.handle = fb->handle;
319 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
320
321 free(fb);
322}
323
324static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500325drm_fb_get_from_bo(struct gbm_bo *bo,
326 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300327{
328 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200330 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331 int ret;
332
333 if (fb)
334 return fb;
335
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200336 fb = calloc(1, sizeof *fb);
337 if (!fb)
338 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300339
340 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341
342 width = gbm_bo_get_width(bo);
343 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200344 fb->stride = gbm_bo_get_stride(bo);
345 fb->handle = gbm_bo_get_handle(bo).u32;
346 fb->size = fb->stride * height;
347 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300348
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200349 if (compositor->min_width > width || width > compositor->max_width ||
350 compositor->min_height > height ||
351 height > compositor->max_height) {
352 weston_log("bo geometry out of bounds\n");
353 goto err_free;
354 }
355
356 ret = -1;
357
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200358 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200359 handles[0] = fb->handle;
360 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200361 offsets[0] = 0;
362
363 ret = drmModeAddFB2(compositor->drm.fd, width, height,
364 format, handles, pitches, offsets,
365 &fb->fb_id, 0);
366 if (ret) {
367 weston_log("addfb2 failed: %m\n");
368 compositor->no_addfb2 = 1;
369 compositor->sprites_are_broken = 1;
370 }
371 }
372
373 if (ret)
374 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200375 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200376
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300377 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200378 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200379 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300380 }
381
382 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
383
384 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
386err_free:
387 free(fb);
388 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300389}
390
391static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500392drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200393{
Pekka Paalanende685b82012-12-04 15:58:12 +0200394 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200395
396 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200397
Pekka Paalanende685b82012-12-04 15:58:12 +0200398 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200399}
400
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200401static void
402drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
403{
404 if (!fb)
405 return;
406
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200407 if (fb->map &&
408 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200409 drm_fb_destroy_dumb(fb);
410 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200411 if (fb->is_client_buffer)
412 gbm_bo_destroy(fb->bo);
413 else
414 gbm_surface_release_buffer(output->surface,
Jason Ekstrand3ec57f52013-11-14 20:52:35 -0600415 fb->bo);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200416 }
417}
418
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500419static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200420drm_output_check_scanout_format(struct drm_output *output,
421 struct weston_surface *es, struct gbm_bo *bo)
422{
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700423 struct drm_compositor *c =
424 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200425 uint32_t format;
426 pixman_region32_t r;
427
428 format = gbm_bo_get_format(bo);
429
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700430 if (format == GBM_FORMAT_ARGB8888) {
431 /* We can scanout an ARGB buffer if the surface's
432 * opaque region covers the whole output, but we have
433 * to use XRGB as the KMS format code. */
Kristian Høgsberg1be87e32014-01-17 14:22:41 -0800434 pixman_region32_init_rect(&r, 0, 0,
435 output->base.width,
436 output->base.height);
437 pixman_region32_subtract(&r, &r, &es->opaque);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200438
439 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500440 format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200441
442 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500443 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700444
445 if (c->format == format)
446 return format;
447
448 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200449}
450
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400451static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500452drm_output_prepare_scanout_view(struct weston_output *_output,
453 struct weston_view *ev)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500454{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400455 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500456 struct drm_compositor *c =
457 (struct drm_compositor *) output->base.compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500458 struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300459 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500460 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500461
Jason Ekstranda7af7042013-10-12 22:38:11 -0500462 if (ev->geometry.x != output->base.x ||
463 ev->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200464 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200465 buffer->width != output->base.current_mode->width ||
466 buffer->height != output->base.current_mode->height ||
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100467 output->base.transform != ev->surface->buffer_viewport.transform ||
Jason Ekstranda7af7042013-10-12 22:38:11 -0500468 ev->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400469 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500470
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400471 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700472 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500473
Rob Bradford9b101872012-09-14 23:25:41 +0100474 /* Unable to use the buffer for scanout */
475 if (!bo)
476 return NULL;
477
Jason Ekstranda7af7042013-10-12 22:38:11 -0500478 format = drm_output_check_scanout_format(output, ev->surface, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500479 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300480 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400481 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300482 }
483
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500484 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300485 if (!output->next) {
486 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400487 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300488 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500489
Pekka Paalanende685b82012-12-04 15:58:12 +0200490 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500491
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400492 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500493}
494
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500495static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200496drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400497{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200498 struct drm_compositor *c =
499 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300500 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400501
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200502 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400503
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300504 bo = gbm_surface_lock_front_buffer(output->surface);
505 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200506 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400507 return;
508 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300509
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700510 output->next = drm_fb_get_from_bo(bo, c, c->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300511 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200512 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300513 gbm_surface_release_buffer(output->surface, bo);
514 return;
515 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400516}
517
518static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200519drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
520{
521 struct weston_compositor *ec = output->base.compositor;
522 pixman_region32_t total_damage, previous_damage;
523
524 pixman_region32_init(&total_damage);
525 pixman_region32_init(&previous_damage);
526
527 pixman_region32_copy(&previous_damage, damage);
528
529 pixman_region32_union(&total_damage, damage, &output->previous_damage);
530 pixman_region32_copy(&output->previous_damage, &previous_damage);
531
532 output->current_image ^= 1;
533
534 output->next = output->dumb[output->current_image];
535 pixman_renderer_output_set_buffer(&output->base,
536 output->image[output->current_image]);
537
538 ec->renderer->repaint_output(&output->base, &total_damage);
539
540 pixman_region32_fini(&total_damage);
541 pixman_region32_fini(&previous_damage);
542}
543
544static void
545drm_output_render(struct drm_output *output, pixman_region32_t *damage)
546{
547 struct drm_compositor *c =
548 (struct drm_compositor *) output->base.compositor;
549
550 if (c->use_pixman)
551 drm_output_render_pixman(output, damage);
552 else
553 drm_output_render_gl(output, damage);
554
555 pixman_region32_subtract(&c->base.primary_plane.damage,
556 &c->base.primary_plane.damage, damage);
557}
558
559static void
Richard Hughese7299962013-05-01 21:52:12 +0100560drm_output_set_gamma(struct weston_output *output_base,
561 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
562{
563 int rc;
564 struct drm_output *output = (struct drm_output *) output_base;
565 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
566
567 /* check */
568 if (output_base->gamma_size != size)
569 return;
570 if (!output->original_crtc)
571 return;
572
573 rc = drmModeCrtcSetGamma(compositor->drm.fd,
574 output->crtc_id,
575 size, r, g, b);
576 if (rc)
577 weston_log("set gamma failed: %m\n");
578}
579
David Herrmann1edf44c2013-10-22 17:11:26 +0200580static int
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500581drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400582 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100583{
584 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500585 struct drm_compositor *compositor =
586 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500587 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400588 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500589 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100590
Xiong Zhangabd5d472013-10-11 14:43:07 +0800591 if (output->destroy_pending)
David Herrmann1edf44c2013-10-22 17:11:26 +0200592 return -1;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800593
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300594 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400595 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300596 if (!output->next)
David Herrmann1edf44c2013-10-22 17:11:26 +0200597 return -1;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100598
Hardeningff39efa2013-09-18 23:56:35 +0200599 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +0200600 if (!output->current ||
601 output->current->stride != output->next->stride) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400602 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300603 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400604 &output->connector_id, 1,
605 &mode->mode_info);
606 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200607 weston_log("set mode failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200608 goto err_pageflip;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400609 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300610 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200611 }
612
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500613 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300614 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500615 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200616 weston_log("queueing pageflip failed: %m\n");
David Herrmann1edf44c2013-10-22 17:11:26 +0200617 goto err_pageflip;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500618 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100619
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300620 output->page_flip_pending = 1;
621
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400622 drm_output_set_cursor(output);
623
Jesse Barnes58ef3792012-02-23 09:45:49 -0500624 /*
625 * Now, update all the sprite surfaces
626 */
627 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200628 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500629 drmVBlank vbl = {
630 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
631 .request.sequence = 1,
632 };
633
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200634 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200635 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500636 continue;
637
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200638 if (s->next && !compositor->sprites_hidden)
639 fb_id = s->next->fb_id;
640
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200642 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 s->dest_x, s->dest_y,
644 s->dest_w, s->dest_h,
645 s->src_x, s->src_y,
646 s->src_w, s->src_h);
647 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200648 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500649 ret, strerror(errno));
650
Rob Clark5ca1a472012-08-08 20:27:37 -0500651 if (output->pipe > 0)
652 vbl.request.type |= DRM_VBLANK_SECONDARY;
653
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 /*
655 * Queue a vblank signal so we know when the surface
656 * becomes active on the display or has been replaced.
657 */
658 vbl.request.signal = (unsigned long)s;
659 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
660 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200661 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500662 ret, strerror(errno));
663 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300664
665 s->output = output;
666 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500667 }
668
David Herrmann1edf44c2013-10-22 17:11:26 +0200669 return 0;
670
671err_pageflip:
Kristian Høgsbergb3955b02014-01-23 16:25:06 -0800672 output->cursor_view = NULL;
David Herrmann1edf44c2013-10-22 17:11:26 +0200673 if (output->next) {
674 drm_output_release_fb(output, output->next);
675 output->next = NULL;
676 }
677
678 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400679}
680
681static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200682drm_output_start_repaint_loop(struct weston_output *output_base)
683{
684 struct drm_output *output = (struct drm_output *) output_base;
685 struct drm_compositor *compositor = (struct drm_compositor *)
686 output_base->compositor;
687 uint32_t fb_id;
David Herrmann3c688c52013-10-22 17:11:25 +0200688 uint32_t msec;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300689 struct timespec ts;
690
Xiong Zhangabd5d472013-10-11 14:43:07 +0800691 if (output->destroy_pending)
692 return;
693
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300694 if (!output->current) {
695 /* We can't page flip if there's no mode set */
David Herrmann3c688c52013-10-22 17:11:25 +0200696 goto finish_frame;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300697 }
698
699 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200700
701 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
702 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
703 weston_log("queueing pageflip failed: %m\n");
David Herrmann3c688c52013-10-22 17:11:25 +0200704 goto finish_frame;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200705 }
David Herrmann3c688c52013-10-22 17:11:25 +0200706
707 return;
708
709finish_frame:
710 /* if we cannot page-flip, immediately finish frame */
711 clock_gettime(compositor->clock, &ts);
712 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
713 weston_output_finish_frame(output_base, msec);
Jonas Ådahle5a12252013-04-05 23:07:11 +0200714}
715
716static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500717vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
718 void *data)
719{
720 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300721 struct drm_output *output = s->output;
722 uint32_t msecs;
723
724 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500725
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200726 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200727 s->current = s->next;
728 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300729
730 if (!output->page_flip_pending) {
731 msecs = sec * 1000 + usec / 1000;
732 weston_output_finish_frame(&output->base, msecs);
733 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500734}
735
736static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800737drm_output_destroy(struct weston_output *output_base);
738
739static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400740page_flip_handler(int fd, unsigned int frame,
741 unsigned int sec, unsigned int usec, void *data)
742{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200743 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400744 uint32_t msecs;
745
Jonas Ådahle5a12252013-04-05 23:07:11 +0200746 /* We don't set page_flip_pending on start_repaint_loop, in that case
747 * we just want to page flip to the current buffer to get an accurate
748 * timestamp */
749 if (output->page_flip_pending) {
750 drm_output_release_fb(output, output->current);
751 output->current = output->next;
752 output->next = NULL;
753 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300754
Jonas Ådahle5a12252013-04-05 23:07:11 +0200755 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400756
Xiong Zhangabd5d472013-10-11 14:43:07 +0800757 if (output->destroy_pending)
758 drm_output_destroy(&output->base);
759 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300760 msecs = sec * 1000 + usec / 1000;
761 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300762
763 /* We can't call this from frame_notify, because the output's
764 * repaint needed flag is cleared just after that */
765 if (output->recorder)
766 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300767 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200768}
769
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500770static uint32_t
771drm_output_check_sprite_format(struct drm_sprite *s,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500772 struct weston_view *ev, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500773{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500774 uint32_t i, format;
775
776 format = gbm_bo_get_format(bo);
777
778 if (format == GBM_FORMAT_ARGB8888) {
779 pixman_region32_t r;
780
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500781 pixman_region32_init_rect(&r, 0, 0,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600782 ev->surface->width,
783 ev->surface->height);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500784 pixman_region32_subtract(&r, &r, &ev->surface->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500785
786 if (!pixman_region32_not_empty(&r))
787 format = GBM_FORMAT_XRGB8888;
788
789 pixman_region32_fini(&r);
790 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791
792 for (i = 0; i < s->count_formats; i++)
793 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500794 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795
796 return 0;
797}
798
799static int
Jason Ekstranda7af7042013-10-12 22:38:11 -0500800drm_view_transform_supported(struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500801{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500802 return !ev->transform.enabled ||
803 (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500804}
805
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400806static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500807drm_output_prepare_overlay_view(struct weston_output *output_base,
808 struct weston_view *ev)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809{
810 struct weston_compositor *ec = output_base->compositor;
811 struct drm_compositor *c =(struct drm_compositor *) ec;
812 struct drm_sprite *s;
813 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500815 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200816 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400818 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500819
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200820 if (c->gbm == NULL)
821 return NULL;
822
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100823 if (ev->surface->buffer_viewport.transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200824 return NULL;
825
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100826 if (ev->surface->buffer_viewport.scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200827 return NULL;
828
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500829 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500831
Jason Ekstranda7af7042013-10-12 22:38:11 -0500832 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400833 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300834
Jason Ekstranda7af7042013-10-12 22:38:11 -0500835 if (ev->surface->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400836 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837
Jason Ekstranda7af7042013-10-12 22:38:11 -0500838 if (ev->alpha != 1.0f)
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200839 return NULL;
840
Jason Ekstranda7af7042013-10-12 22:38:11 -0500841 if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500842 return NULL;
843
Jason Ekstranda7af7042013-10-12 22:38:11 -0500844 if (!drm_view_transform_supported(ev))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400845 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500846
Jesse Barnes58ef3792012-02-23 09:45:49 -0500847 wl_list_for_each(s, &c->sprite_list, link) {
848 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
849 continue;
850
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200851 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500852 found = 1;
853 break;
854 }
855 }
856
857 /* No sprites available */
858 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400859 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500860
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400861 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Jason Ekstranda7af7042013-10-12 22:38:11 -0500862 ev->surface->buffer_ref.buffer->resource,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700863 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400864 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400865 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400866
Jason Ekstranda7af7042013-10-12 22:38:11 -0500867 format = drm_output_check_sprite_format(s, ev, bo);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500868 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200869 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400870 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500871 }
872
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200873 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200874 if (!s->next) {
875 gbm_bo_destroy(bo);
876 return NULL;
877 }
878
Jason Ekstranda7af7042013-10-12 22:38:11 -0500879 drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500880
Jason Ekstranda7af7042013-10-12 22:38:11 -0500881 box = pixman_region32_extents(&ev->transform.boundingbox);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400882 s->plane.x = box->x1;
883 s->plane.y = box->y1;
884
Jesse Barnes58ef3792012-02-23 09:45:49 -0500885 /*
886 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200887 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500888 * for us already).
889 */
890 pixman_region32_init(&dest_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500891 pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500892 &output_base->region);
893 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
894 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200895 tbox = weston_transformed_rect(output_base->width,
896 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200897 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200898 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200899 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200900 s->dest_x = tbox.x1;
901 s->dest_y = tbox.y1;
902 s->dest_w = tbox.x2 - tbox.x1;
903 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500904 pixman_region32_fini(&dest_rect);
905
906 pixman_region32_init(&src_rect);
Jason Ekstranda7af7042013-10-12 22:38:11 -0500907 pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500908 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500909 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400910
Jason Ekstranda7af7042013-10-12 22:38:11 -0500911 weston_view_from_global_fixed(ev,
912 wl_fixed_from_int(box->x1),
913 wl_fixed_from_int(box->y1),
914 &sx1, &sy1);
915 weston_view_from_global_fixed(ev,
916 wl_fixed_from_int(box->x2),
917 wl_fixed_from_int(box->y2),
918 &sx2, &sy2);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400919
920 if (sx1 < 0)
921 sx1 = 0;
922 if (sy1 < 0)
923 sy1 = 0;
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600924 if (sx2 > wl_fixed_from_int(ev->surface->width))
925 sx2 = wl_fixed_from_int(ev->surface->width);
926 if (sy2 > wl_fixed_from_int(ev->surface->height))
927 sy2 = wl_fixed_from_int(ev->surface->height);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400928
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200929 tbox.x1 = sx1;
930 tbox.y1 = sy1;
931 tbox.x2 = sx2;
932 tbox.y2 = sy2;
933
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600934 tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
935 wl_fixed_from_int(ev->surface->height),
Pekka Paalanen1fd9c0f2013-11-26 18:19:41 +0100936 ev->surface->buffer_viewport.transform,
937 ev->surface->buffer_viewport.scale,
938 tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200939
940 s->src_x = tbox.x1 << 8;
941 s->src_y = tbox.y1 << 8;
942 s->src_w = (tbox.x2 - tbox.x1) << 8;
943 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500944 pixman_region32_fini(&src_rect);
945
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400946 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500947}
948
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400949static struct weston_plane *
Jason Ekstranda7af7042013-10-12 22:38:11 -0500950drm_output_prepare_cursor_view(struct weston_output *output_base,
951 struct weston_view *ev)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500952{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400953 struct drm_compositor *c =
954 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400955 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400956
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200957 if (c->gbm == NULL)
958 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200959 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
960 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500961 if (output->cursor_view)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400962 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500963 if (ev->output_mask != (1u << output_base->id))
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400964 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500965 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400966 return NULL;
Jason Ekstranda7af7042013-10-12 22:38:11 -0500967 if (ev->surface->buffer_ref.buffer == NULL ||
968 !wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -0600969 ev->surface->width > 64 || ev->surface->height > 64)
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400970 return NULL;
971
Jason Ekstranda7af7042013-10-12 22:38:11 -0500972 output->cursor_view = ev;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400973
974 return &output->cursor_plane;
975}
976
977static void
978drm_output_set_cursor(struct drm_output *output)
979{
Jason Ekstranda7af7042013-10-12 22:38:11 -0500980 struct weston_view *ev = output->cursor_view;
Neil Robertse5051712013-11-13 15:44:06 +0000981 struct weston_buffer *buffer;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400982 struct drm_compositor *c =
983 (struct drm_compositor *) output->base.compositor;
984 EGLint handle, stride;
985 struct gbm_bo *bo;
986 uint32_t buf[64 * 64];
987 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400988 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500989
Jason Ekstranda7af7042013-10-12 22:38:11 -0500990 output->cursor_view = NULL;
991 if (ev == NULL) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400992 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
993 return;
994 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500995
Neil Robertse5051712013-11-13 15:44:06 +0000996 buffer = ev->surface->buffer_ref.buffer;
997
998 if (buffer &&
Pekka Paalanende685b82012-12-04 15:58:12 +0200999 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001000 pixman_region32_fini(&output->cursor_plane.damage);
1001 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001002 output->current_cursor ^= 1;
1003 bo = output->cursor_bo[output->current_cursor];
1004 memset(buf, 0, sizeof buf);
Neil Robertse5051712013-11-13 15:44:06 +00001005 stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
1006 s = wl_shm_buffer_get_data(buffer->shm_buffer);
1007 wl_shm_buffer_begin_access(buffer->shm_buffer);
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001008 for (i = 0; i < ev->surface->height; i++)
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001009 memcpy(buf + i * 64, s + i * stride,
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001010 ev->surface->width * 4);
Neil Robertse5051712013-11-13 15:44:06 +00001011 wl_shm_buffer_end_access(buffer->shm_buffer);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001012
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001013 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +03001014 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001015
Kristian Høgsberg1f5de352012-07-18 12:09:58 -04001016 handle = gbm_bo_get_handle(bo).s32;
1017 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -05001018 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +03001019 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001020 c->cursors_are_broken = 1;
1021 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001022 }
1023
Jason Ekstranda7af7042013-10-12 22:38:11 -05001024 x = (ev->geometry.x - output->base.x) * output->base.current_scale;
1025 y = (ev->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001026 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001027 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001028 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001029 c->cursors_are_broken = 1;
1030 }
1031
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001032 output->cursor_plane.x = x;
1033 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001034 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001035}
1036
Jesse Barnes58ef3792012-02-23 09:45:49 -05001037static void
1038drm_assign_planes(struct weston_output *output)
1039{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001040 struct drm_compositor *c =
1041 (struct drm_compositor *) output->compositor;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001042 struct weston_view *ev, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001043 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001044 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001045
1046 /*
1047 * Find a surface for each sprite in the output using some heuristics:
1048 * 1) size
1049 * 2) frequency of update
1050 * 3) opacity (though some hw might support alpha blending)
1051 * 4) clipping (this can be fixed with color keys)
1052 *
1053 * The idea is to save on blitting since this should save power.
1054 * If we can get a large video surface on the sprite for example,
1055 * the main display surface may not need to update at all, and
1056 * the client buffer can be used directly for the sprite surface
1057 * as we do for flipping full screen surfaces.
1058 */
1059 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001060 primary = &c->base.primary_plane;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001061
Jason Ekstranda7af7042013-10-12 22:38:11 -05001062 wl_list_for_each_safe(ev, next, &c->base.view_list, link) {
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001063 struct weston_surface *es = ev->surface;
1064
1065 /* Test whether this buffer can ever go into a plane:
1066 * non-shm, or small enough to be a cursor.
1067 *
1068 * Also, keep a reference when using the pixman renderer.
1069 * That makes it possible to do a seamless switch to the GL
1070 * renderer and since the pixman renderer keeps a reference
1071 * to the buffer anyway, there is no side effects.
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001072 */
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001073 if (c->use_pixman ||
1074 (es->buffer_ref.buffer &&
1075 (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Jason Ekstrand918f2dd2013-12-02 21:01:53 -06001076 (ev->surface->width <= 64 && ev->surface->height <= 64))))
Ander Conselvan de Oliveira895b1fd2013-11-19 15:22:05 +02001077 es->keep_buffer = 1;
1078 else
1079 es->keep_buffer = 0;
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001080
Jesse Barnes58ef3792012-02-23 09:45:49 -05001081 pixman_region32_init(&surface_overlap);
1082 pixman_region32_intersect(&surface_overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001083 &ev->transform.boundingbox);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001084
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001085 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001086 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001087 next_plane = primary;
1088 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001089 next_plane = drm_output_prepare_cursor_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001090 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001091 next_plane = drm_output_prepare_scanout_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001092 if (next_plane == NULL)
Jason Ekstranda7af7042013-10-12 22:38:11 -05001093 next_plane = drm_output_prepare_overlay_view(output, ev);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001094 if (next_plane == NULL)
1095 next_plane = primary;
Jason Ekstranda7af7042013-10-12 22:38:11 -05001096 weston_view_move_to_plane(ev, next_plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001097 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001098 pixman_region32_union(&overlap, &overlap,
Jason Ekstranda7af7042013-10-12 22:38:11 -05001099 &ev->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001100
Jesse Barnes58ef3792012-02-23 09:45:49 -05001101 pixman_region32_fini(&surface_overlap);
1102 }
1103 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001104}
1105
Matt Roper361d2ad2011-08-29 13:52:23 -07001106static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001107drm_output_fini_pixman(struct drm_output *output);
1108
1109static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001110drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001111{
1112 struct drm_output *output = (struct drm_output *) output_base;
1113 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001114 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001115 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001116
Xiong Zhangabd5d472013-10-11 14:43:07 +08001117 if (output->page_flip_pending) {
1118 output->destroy_pending = 1;
1119 weston_log("destroy output while page flip pending\n");
1120 return;
1121 }
1122
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001123 if (output->backlight)
1124 backlight_destroy(output->backlight);
1125
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001126 drmModeFreeProperty(output->dpms_prop);
1127
Matt Roper361d2ad2011-08-29 13:52:23 -07001128 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001129 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001130
1131 /* Restore original CRTC state */
1132 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001133 origcrtc->x, origcrtc->y,
1134 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001135 drmModeFreeCrtc(origcrtc);
1136
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001137 c->crtc_allocator &= ~(1 << output->crtc_id);
1138 c->connector_allocator &= ~(1 << output->connector_id);
1139
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001140 if (c->use_pixman) {
1141 drm_output_fini_pixman(output);
1142 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001143 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001144 gbm_surface_destroy(output->surface);
1145 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001146
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001147 weston_plane_release(&output->fb_plane);
1148 weston_plane_release(&output->cursor_plane);
1149
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001150 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001151
Matt Roper361d2ad2011-08-29 13:52:23 -07001152 free(output);
1153}
1154
Alex Wub7b8bda2012-04-17 17:20:48 +08001155static struct drm_mode *
1156choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1157{
1158 struct drm_mode *tmp_mode = NULL, *mode;
1159
Hardeningff39efa2013-09-18 23:56:35 +02001160 if (output->base.current_mode->width == target_mode->width &&
1161 output->base.current_mode->height == target_mode->height &&
1162 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001163 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001164 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001165
1166 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1167 if (mode->mode_info.hdisplay == target_mode->width &&
1168 mode->mode_info.vdisplay == target_mode->height) {
1169 if (mode->mode_info.vrefresh == target_mode->refresh ||
1170 target_mode->refresh == 0) {
1171 return mode;
1172 } else if (!tmp_mode)
1173 tmp_mode = mode;
1174 }
1175 }
1176
1177 return tmp_mode;
1178}
1179
1180static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001181drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001182static int
1183drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001184
1185static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001186drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1187{
1188 struct drm_output *output;
1189 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001190 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001191
1192 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001193 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001194 return -1;
1195 }
1196
1197 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001198 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001199 return -1;
1200 }
1201
1202 ec = (struct drm_compositor *)output_base->compositor;
1203 output = (struct drm_output *)output_base;
1204 drm_mode = choose_mode (output, mode);
1205
1206 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001207 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001208 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001209 }
1210
Hardeningff39efa2013-09-18 23:56:35 +02001211 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001212 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001213
Hardeningff39efa2013-09-18 23:56:35 +02001214 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001215
Hardeningff39efa2013-09-18 23:56:35 +02001216 output->base.current_mode = &drm_mode->base;
1217 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001218 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1219
Alex Wub7b8bda2012-04-17 17:20:48 +08001220 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001221 drm_output_release_fb(output, output->current);
1222 drm_output_release_fb(output, output->next);
1223 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001224
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001225 if (ec->use_pixman) {
1226 drm_output_fini_pixman(output);
1227 if (drm_output_init_pixman(output, ec) < 0) {
1228 weston_log("failed to init output pixman state with "
1229 "new mode\n");
1230 return -1;
1231 }
1232 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001233 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001234 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001235
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001236 if (drm_output_init_egl(output, ec) < 0) {
1237 weston_log("failed to init output egl state with "
1238 "new mode");
1239 return -1;
1240 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001241 }
1242
Alex Wub7b8bda2012-04-17 17:20:48 +08001243 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001244}
1245
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001246static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001247on_drm_input(int fd, uint32_t mask, void *data)
1248{
1249 drmEventContext evctx;
1250
1251 memset(&evctx, 0, sizeof evctx);
1252 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1253 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001254 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001255 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001256
1257 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001258}
1259
1260static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001261init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001262{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001263 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001264 uint64_t cap;
1265 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001266
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001267 sysnum = udev_device_get_sysnum(device);
1268 if (sysnum)
1269 ec->drm.id = atoi(sysnum);
1270 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001271 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001272 return -1;
1273 }
1274
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001275 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001276 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001277 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001278 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001279 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001280 udev_device_get_devnode(device));
1281 return -1;
1282 }
1283
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001284 weston_log("using %s\n", filename);
1285
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001286 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001287 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001288
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001289 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1290 if (ret == 0 && cap == 1)
1291 ec->clock = CLOCK_MONOTONIC;
1292 else
1293 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001294
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001295 return 0;
1296}
1297
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001298static struct gbm_device *
1299create_gbm_device(int fd)
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001300{
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001301 struct gbm_device *gbm;
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001302
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001303 gl_renderer = weston_load_module("gl-renderer.so",
1304 "gl_renderer_interface");
1305 if (!gl_renderer)
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001306 return NULL;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001307
1308 /* GBM will load a dri driver, but even though they need symbols from
1309 * libglapi, in some version of Mesa they are not linked to it. Since
1310 * only the gl-renderer module links to it, the call above won't make
1311 * these symbols globally available, and loading the DRI driver fails.
1312 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1313 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1314
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001315 gbm = gbm_create_device(fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001316
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001317 return gbm;
1318}
1319
1320static int
1321drm_compositor_create_gl_renderer(struct drm_compositor *ec)
1322{
1323 EGLint format;
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001324
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001325 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001326 if (gl_renderer->create(&ec->base, ec->gbm,
1327 gl_renderer->opaque_attribs, &format) < 0) {
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02001328 return -1;
1329 }
1330
1331 return 0;
1332}
1333
1334static int
1335init_egl(struct drm_compositor *ec)
1336{
1337 ec->gbm = create_gbm_device(ec->drm.fd);
1338
1339 if (!ec->gbm)
1340 return -1;
1341
1342 if (drm_compositor_create_gl_renderer(ec) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001343 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001344 return -1;
1345 }
1346
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001347 return 0;
1348}
1349
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001350static int
1351init_pixman(struct drm_compositor *ec)
1352{
1353 return pixman_renderer_init(&ec->base);
1354}
1355
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001356static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001357drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001358{
1359 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001360 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001361
1362 mode = malloc(sizeof *mode);
1363 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001364 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001365
1366 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001367 mode->base.width = info->hdisplay;
1368 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001369
1370 /* Calculate higher precision (mHz) refresh rate */
1371 refresh = (info->clock * 1000000LL / info->htotal +
1372 info->vtotal / 2) / info->vtotal;
1373
1374 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1375 refresh *= 2;
1376 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1377 refresh /= 2;
1378 if (info->vscan > 1)
1379 refresh /= info->vscan;
1380
1381 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001382 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001383
1384 if (info->type & DRM_MODE_TYPE_PREFERRED)
1385 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1386
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001387 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1388
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001389 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001390}
1391
1392static int
1393drm_subpixel_to_wayland(int drm_value)
1394{
1395 switch (drm_value) {
1396 default:
1397 case DRM_MODE_SUBPIXEL_UNKNOWN:
1398 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1399 case DRM_MODE_SUBPIXEL_NONE:
1400 return WL_OUTPUT_SUBPIXEL_NONE;
1401 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1402 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1403 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1404 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1405 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1406 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1407 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1408 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1409 }
1410}
1411
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001412/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001413static uint32_t
1414drm_get_backlight(struct drm_output *output)
1415{
1416 long brightness, max_brightness, norm;
1417
1418 brightness = backlight_get_brightness(output->backlight);
1419 max_brightness = backlight_get_max_brightness(output->backlight);
1420
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001421 /* convert it on a scale of 0 to 255 */
1422 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001423
1424 return (uint32_t) norm;
1425}
1426
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001427/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001428static void
1429drm_set_backlight(struct weston_output *output_base, uint32_t value)
1430{
1431 struct drm_output *output = (struct drm_output *) output_base;
1432 long max_brightness, new_brightness;
1433
1434 if (!output->backlight)
1435 return;
1436
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001437 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001438 return;
1439
1440 max_brightness = backlight_get_max_brightness(output->backlight);
1441
1442 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001443 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001444
1445 backlight_set_brightness(output->backlight, new_brightness);
1446}
1447
1448static drmModePropertyPtr
1449drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1450{
1451 drmModePropertyPtr props;
1452 int i;
1453
1454 for (i = 0; i < connector->count_props; i++) {
1455 props = drmModeGetProperty(fd, connector->props[i]);
1456 if (!props)
1457 continue;
1458
1459 if (!strcmp(props->name, name))
1460 return props;
1461
1462 drmModeFreeProperty(props);
1463 }
1464
1465 return NULL;
1466}
1467
1468static void
1469drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1470{
1471 struct drm_output *output = (struct drm_output *) output_base;
1472 struct weston_compositor *ec = output_base->compositor;
1473 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001474
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001475 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001476 return;
1477
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001478 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1479 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001480}
1481
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001482static const char *connector_type_names[] = {
1483 "None",
1484 "VGA",
1485 "DVI",
1486 "DVI",
1487 "DVI",
1488 "Composite",
1489 "TV",
1490 "LVDS",
1491 "CTV",
1492 "DIN",
1493 "DP",
1494 "HDMI",
1495 "HDMI",
1496 "TV",
1497 "eDP",
1498};
1499
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001500static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001501find_crtc_for_connector(struct drm_compositor *ec,
1502 drmModeRes *resources, drmModeConnector *connector)
1503{
1504 drmModeEncoder *encoder;
1505 uint32_t possible_crtcs;
1506 int i, j;
1507
1508 for (j = 0; j < connector->count_encoders; j++) {
1509 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1510 if (encoder == NULL) {
1511 weston_log("Failed to get encoder.\n");
1512 return -1;
1513 }
1514 possible_crtcs = encoder->possible_crtcs;
1515 drmModeFreeEncoder(encoder);
1516
1517 for (i = 0; i < resources->count_crtcs; i++) {
1518 if (possible_crtcs & (1 << i) &&
1519 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1520 return i;
1521 }
1522 }
1523
1524 return -1;
1525}
1526
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001527/* Init output state that depends on gl or gbm */
1528static int
1529drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1530{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001531 int i, flags;
1532
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001533 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001534 output->base.current_mode->width,
1535 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001536 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001537 GBM_BO_USE_SCANOUT |
1538 GBM_BO_USE_RENDERING);
1539 if (!output->surface) {
1540 weston_log("failed to create gbm surface\n");
1541 return -1;
1542 }
1543
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001544 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001545 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001546 gbm_surface_destroy(output->surface);
1547 return -1;
1548 }
1549
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001550 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1551
1552 for (i = 0; i < 2; i++) {
1553 if (output->cursor_bo[i])
1554 continue;
1555
1556 output->cursor_bo[i] =
1557 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1558 flags);
1559 }
1560
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001561 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1562 weston_log("cursor buffers unavailable, using gl cursors\n");
1563 ec->cursors_are_broken = 1;
1564 }
1565
1566 return 0;
1567}
1568
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001569static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001570drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1571{
Hardeningff39efa2013-09-18 23:56:35 +02001572 int w = output->base.current_mode->width;
1573 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001574 unsigned int i;
1575
1576 /* FIXME error checking */
1577
1578 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001579 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001580 if (!output->dumb[i])
1581 goto err;
1582
1583 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001584 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001585 output->dumb[i]->map,
1586 output->dumb[i]->stride);
1587 if (!output->image[i])
1588 goto err;
1589 }
1590
1591 if (pixman_renderer_output_create(&output->base) < 0)
1592 goto err;
1593
1594 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001595 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001596
1597 return 0;
1598
1599err:
1600 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1601 if (output->dumb[i])
1602 drm_fb_destroy_dumb(output->dumb[i]);
1603 if (output->image[i])
1604 pixman_image_unref(output->image[i]);
1605
1606 output->dumb[i] = NULL;
1607 output->image[i] = NULL;
1608 }
1609
1610 return -1;
1611}
1612
1613static void
1614drm_output_fini_pixman(struct drm_output *output)
1615{
1616 unsigned int i;
1617
1618 pixman_renderer_output_destroy(&output->base);
1619 pixman_region32_fini(&output->previous_damage);
1620
1621 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1622 drm_fb_destroy_dumb(output->dumb[i]);
1623 pixman_image_unref(output->image[i]);
1624 output->dumb[i] = NULL;
1625 output->image[i] = NULL;
1626 }
1627}
1628
Richard Hughes2b2092a2013-04-24 14:58:02 +01001629static void
1630edid_parse_string(const uint8_t *data, char text[])
1631{
1632 int i;
1633 int replaced = 0;
1634
1635 /* this is always 12 bytes, but we can't guarantee it's null
1636 * terminated or not junk. */
1637 strncpy(text, (const char *) data, 12);
1638
1639 /* remove insane chars */
1640 for (i = 0; text[i] != '\0'; i++) {
1641 if (text[i] == '\n' ||
1642 text[i] == '\r') {
1643 text[i] = '\0';
1644 break;
1645 }
1646 }
1647
1648 /* ensure string is printable */
1649 for (i = 0; text[i] != '\0'; i++) {
1650 if (!isprint(text[i])) {
1651 text[i] = '-';
1652 replaced++;
1653 }
1654 }
1655
1656 /* if the string is random junk, ignore the string */
1657 if (replaced > 4)
1658 text[0] = '\0';
1659}
1660
1661#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1662#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1663#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1664#define EDID_OFFSET_DATA_BLOCKS 0x36
1665#define EDID_OFFSET_LAST_BLOCK 0x6c
1666#define EDID_OFFSET_PNPID 0x08
1667#define EDID_OFFSET_SERIAL 0x0c
1668
1669static int
1670edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1671{
1672 int i;
1673 uint32_t serial_number;
1674
1675 /* check header */
1676 if (length < 128)
1677 return -1;
1678 if (data[0] != 0x00 || data[1] != 0xff)
1679 return -1;
1680
1681 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1682 * /--08--\/--09--\
1683 * 7654321076543210
1684 * |\---/\---/\---/
1685 * R C1 C2 C3 */
1686 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1687 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1688 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1689 edid->pnp_id[3] = '\0';
1690
1691 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1692 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1693 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1694 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1695 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1696 if (serial_number > 0)
1697 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1698
1699 /* parse EDID data */
1700 for (i = EDID_OFFSET_DATA_BLOCKS;
1701 i <= EDID_OFFSET_LAST_BLOCK;
1702 i += 18) {
1703 /* ignore pixel clock data */
1704 if (data[i] != 0)
1705 continue;
1706 if (data[i+2] != 0)
1707 continue;
1708
1709 /* any useful blocks? */
1710 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1711 edid_parse_string(&data[i+5],
1712 edid->monitor_name);
1713 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1714 edid_parse_string(&data[i+5],
1715 edid->serial_number);
1716 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1717 edid_parse_string(&data[i+5],
1718 edid->eisa_id);
1719 }
1720 }
1721 return 0;
1722}
1723
1724static void
1725find_and_parse_output_edid(struct drm_compositor *ec,
1726 struct drm_output *output,
1727 drmModeConnector *connector)
1728{
1729 drmModePropertyBlobPtr edid_blob = NULL;
1730 drmModePropertyPtr property;
1731 int i;
1732 int rc;
1733
1734 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1735 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1736 if (!property)
1737 continue;
1738 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1739 !strcmp(property->name, "EDID")) {
1740 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1741 connector->prop_values[i]);
1742 }
1743 drmModeFreeProperty(property);
1744 }
1745 if (!edid_blob)
1746 return;
1747
1748 rc = edid_parse(&output->edid,
1749 edid_blob->data,
1750 edid_blob->length);
1751 if (!rc) {
1752 weston_log("EDID data '%s', '%s', '%s'\n",
1753 output->edid.pnp_id,
1754 output->edid.monitor_name,
1755 output->edid.serial_number);
1756 if (output->edid.pnp_id[0] != '\0')
1757 output->base.make = output->edid.pnp_id;
1758 if (output->edid.monitor_name[0] != '\0')
1759 output->base.model = output->edid.monitor_name;
1760 if (output->edid.serial_number[0] != '\0')
1761 output->base.serial_number = output->edid.serial_number;
1762 }
1763 drmModeFreePropertyBlob(edid_blob);
1764}
1765
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001766
1767
1768static int
1769parse_modeline(const char *s, drmModeModeInfo *mode)
1770{
1771 char hsync[16];
1772 char vsync[16];
1773 float fclock;
1774
1775 mode->type = DRM_MODE_TYPE_USERDEF;
1776 mode->hskew = 0;
1777 mode->vscan = 0;
1778 mode->vrefresh = 0;
1779 mode->flags = 0;
1780
Rob Bradford307e09e2013-07-26 16:29:40 +01001781 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001782 &fclock,
1783 &mode->hdisplay,
1784 &mode->hsync_start,
1785 &mode->hsync_end,
1786 &mode->htotal,
1787 &mode->vdisplay,
1788 &mode->vsync_start,
1789 &mode->vsync_end,
1790 &mode->vtotal, hsync, vsync) != 11)
1791 return -1;
1792
1793 mode->clock = fclock * 1000;
1794 if (strcmp(hsync, "+hsync") == 0)
1795 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1796 else if (strcmp(hsync, "-hsync") == 0)
1797 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1798 else
1799 return -1;
1800
1801 if (strcmp(vsync, "+vsync") == 0)
1802 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1803 else if (strcmp(vsync, "-vsync") == 0)
1804 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1805 else
1806 return -1;
1807
1808 return 0;
1809}
1810
1811static uint32_t
1812parse_transform(const char *transform, const char *output_name)
1813{
1814 static const struct { const char *name; uint32_t token; } names[] = {
1815 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1816 { "90", WL_OUTPUT_TRANSFORM_90 },
1817 { "180", WL_OUTPUT_TRANSFORM_180 },
1818 { "270", WL_OUTPUT_TRANSFORM_270 },
1819 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1820 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1821 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1822 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1823 };
1824 unsigned int i;
1825
1826 for (i = 0; i < ARRAY_LENGTH(names); i++)
1827 if (strcmp(names[i].name, transform) == 0)
1828 return names[i].token;
1829
1830 weston_log("Invalid transform \"%s\" for output %s\n",
1831 transform, output_name);
1832
1833 return WL_OUTPUT_TRANSFORM_NORMAL;
1834}
1835
Rob Bradford66bd9f52013-06-25 18:56:42 +01001836static void
1837setup_output_seat_constraint(struct drm_compositor *ec,
1838 struct weston_output *output,
1839 const char *s)
1840{
1841 if (strcmp(s, "") != 0) {
1842 struct udev_seat *seat;
1843
1844 seat = udev_seat_get_named(&ec->base, s);
1845 if (seat)
1846 seat->base.output = output;
1847
1848 if (seat && seat->base.pointer)
1849 weston_pointer_clamp(seat->base.pointer,
1850 &seat->base.pointer->x,
1851 &seat->base.pointer->y);
1852 }
1853}
1854
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001855static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001856create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001857 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001858 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001859 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001860{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001861 struct drm_output *output;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001862 struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001863 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001864 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001865 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001866 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001867 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001868 int i, width, height, scale;
1869 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001870 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001871 enum output_config config;
1872 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001873
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001874 i = find_crtc_for_connector(ec, resources, connector);
1875 if (i < 0) {
1876 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001877 return -1;
1878 }
1879
Peter Huttererf3d62272013-08-08 11:57:05 +10001880 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001881 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001882 return -1;
1883
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001884 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1885 output->base.make = "unknown";
1886 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001887 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001888 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001889
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001890 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1891 type_name = connector_type_names[connector->connector_type];
1892 else
1893 type_name = "UNKNOWN";
1894 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001895 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001896
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001897 section = weston_config_get_section(ec->base.config, "output", "name",
1898 output->base.name);
1899 weston_config_section_get_string(section, "mode", &s, "preferred");
1900 if (strcmp(s, "off") == 0)
1901 config = OUTPUT_CONFIG_OFF;
1902 else if (strcmp(s, "preferred") == 0)
1903 config = OUTPUT_CONFIG_PREFERRED;
1904 else if (strcmp(s, "current") == 0)
1905 config = OUTPUT_CONFIG_CURRENT;
1906 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1907 config = OUTPUT_CONFIG_MODE;
1908 else if (parse_modeline(s, &modeline) == 0)
1909 config = OUTPUT_CONFIG_MODELINE;
1910 else {
1911 weston_log("Invalid mode \"%s\" for output %s\n",
1912 s, output->base.name);
1913 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001914 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001915 free(s);
1916
1917 weston_config_section_get_int(section, "scale", &scale, 1);
1918 weston_config_section_get_string(section, "transform", &s, "normal");
1919 transform = parse_transform(s, output->base.name);
1920 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001921
Rob Bradford66bd9f52013-06-25 18:56:42 +01001922 weston_config_section_get_string(section, "seat", &s, "");
1923 setup_output_seat_constraint(ec, &output->base, s);
1924 free(s);
1925
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001926 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001927 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001928 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001929 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001930 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001931
Matt Roper361d2ad2011-08-29 13:52:23 -07001932 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001933 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001934
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001935 /* Get the current mode on the crtc that's currently driving
1936 * this connector. */
1937 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001938 memset(&crtc_mode, 0, sizeof crtc_mode);
1939 if (encoder != NULL) {
1940 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1941 drmModeFreeEncoder(encoder);
1942 if (crtc == NULL)
1943 goto err_free;
1944 if (crtc->mode_valid)
1945 crtc_mode = crtc->mode;
1946 drmModeFreeCrtc(crtc);
1947 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001948
David Herrmann0f0d54e2011-12-08 17:05:45 +01001949 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001950 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001951 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001952 goto err_free;
1953 }
1954
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001955 if (config == OUTPUT_CONFIG_OFF) {
1956 weston_log("Disabling output %s\n", output->base.name);
1957 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1958 0, 0, 0, 0, 0, NULL);
1959 goto err_free;
1960 }
1961
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001962 preferred = NULL;
1963 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001964 configured = NULL;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001965 best = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001966
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001967 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001968 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001969 width == drm_mode->base.width &&
1970 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001971 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001972 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001973 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001974 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001975 preferred = drm_mode;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01001976 best = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001977 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001978
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001979 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001980 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001981 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001982 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001983 }
1984
Wang Quanxianacb805a2012-07-30 18:09:46 -04001985 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001986 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001987 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001988 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001989 }
1990
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001991 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001992 configured = current;
1993
Wang Quanxianacb805a2012-07-30 18:09:46 -04001994 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001995 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001996 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001997 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001998 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001999 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002000 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02002001 output->base.current_mode = &current->base;
Fabien DESSENNE4b255872013-12-12 17:13:56 +01002002 else if (best)
2003 output->base.current_mode = &best->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002004
Hardeningff39efa2013-09-18 23:56:35 +02002005 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01002006 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04002007 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002008 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04002009
Hardeningff39efa2013-09-18 23:56:35 +02002010 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04002011
John Kåre Alsaker94659272012-11-13 19:10:18 +01002012 weston_output_init(&output->base, &ec->base, x, y,
2013 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04002014 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01002015
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002016 if (ec->use_pixman) {
2017 if (drm_output_init_pixman(output, ec) < 0) {
2018 weston_log("Failed to init output pixman state\n");
2019 goto err_output;
2020 }
2021 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02002022 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01002023 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04002024 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04002025
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002026 output->backlight = backlight_init(drm_device,
2027 connector->connector_type);
2028 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002029 weston_log("Initialized backlight, device %s\n",
2030 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002031 output->base.set_backlight = drm_set_backlight;
2032 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04002033 } else {
2034 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002035 }
2036
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04002037 wl_list_insert(ec->base.output_list.prev, &output->base.link);
2038
Richard Hughes2b2092a2013-04-24 14:58:02 +01002039 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01002040 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
2041 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01002042
Jonas Ådahle5a12252013-04-05 23:07:11 +02002043 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05002044 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07002045 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002046 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002047 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08002048 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002049
Richard Hughese7299962013-05-01 21:52:12 +01002050 output->base.gamma_size = output->original_crtc->gamma_size;
2051 output->base.set_gamma = drm_output_set_gamma;
2052
Xiong Zhang97116532013-10-23 13:58:31 +08002053 weston_plane_init(&output->cursor_plane, &ec->base, 0, 0);
2054 weston_plane_init(&output->fb_plane, &ec->base, 0, 0);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002055
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002056 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
2057 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
2058 &ec->base.primary_plane);
2059
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002060 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002061 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002062 wl_list_for_each(m, &output->base.mode_list, link)
U. Artie Eoffd3ed6cb2014-01-10 10:15:17 -08002063 weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002064 m->width, m->height, m->refresh / 1000.0,
2065 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2066 ", preferred" : "",
2067 m->flags & WL_OUTPUT_MODE_CURRENT ?
2068 ", current" : "",
2069 connector->count_modes == 0 ?
2070 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002071
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002072 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002073
John Kåre Alsaker94659272012-11-13 19:10:18 +01002074err_output:
2075 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002076err_free:
2077 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2078 base.link) {
2079 wl_list_remove(&drm_mode->base.link);
2080 free(drm_mode);
2081 }
2082
2083 drmModeFreeCrtc(output->original_crtc);
2084 ec->crtc_allocator &= ~(1 << output->crtc_id);
2085 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002086 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002087
David Herrmann0f0d54e2011-12-08 17:05:45 +01002088 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002089}
2090
Jesse Barnes58ef3792012-02-23 09:45:49 -05002091static void
2092create_sprites(struct drm_compositor *ec)
2093{
2094 struct drm_sprite *sprite;
2095 drmModePlaneRes *plane_res;
2096 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002097 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002098
2099 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2100 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002101 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002102 strerror(errno));
2103 return;
2104 }
2105
2106 for (i = 0; i < plane_res->count_planes; i++) {
2107 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2108 if (!plane)
2109 continue;
2110
Peter Huttererf3d62272013-08-08 11:57:05 +10002111 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002112 plane->count_formats));
2113 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002114 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002115 __func__);
Chris Michael8b376872014-01-02 11:39:40 +00002116 drmModeFreePlane(plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002117 continue;
2118 }
2119
Jesse Barnes58ef3792012-02-23 09:45:49 -05002120 sprite->possible_crtcs = plane->possible_crtcs;
2121 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002122 sprite->current = NULL;
2123 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002124 sprite->compositor = ec;
2125 sprite->count_formats = plane->count_formats;
2126 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002127 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002128 drmModeFreePlane(plane);
Xiong Zhang97116532013-10-23 13:58:31 +08002129 weston_plane_init(&sprite->plane, &ec->base, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002130 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2131 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002132
2133 wl_list_insert(&ec->sprite_list, &sprite->link);
2134 }
2135
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002136 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002137}
2138
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002139static void
2140destroy_sprites(struct drm_compositor *compositor)
2141{
2142 struct drm_sprite *sprite, *next;
2143 struct drm_output *output;
2144
2145 output = container_of(compositor->base.output_list.next,
2146 struct drm_output, base.link);
2147
2148 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2149 drmModeSetPlane(compositor->drm.fd,
2150 sprite->plane_id,
2151 output->crtc_id, 0, 0,
2152 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002153 drm_output_release_fb(output, sprite->current);
2154 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002155 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002156 free(sprite);
2157 }
2158}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002159
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002160static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002161create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002162 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002163{
2164 drmModeConnector *connector;
2165 drmModeRes *resources;
2166 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002167 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002168
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002169 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002170 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002171 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002172 return -1;
2173 }
2174
Jesse Barnes58ef3792012-02-23 09:45:49 -05002175 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002176 if (!ec->crtcs) {
2177 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002178 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002179 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002180
Rob Clark4339add2012-08-09 14:18:28 -05002181 ec->min_width = resources->min_width;
2182 ec->max_width = resources->max_width;
2183 ec->min_height = resources->min_height;
2184 ec->max_height = resources->max_height;
2185
Jesse Barnes58ef3792012-02-23 09:45:49 -05002186 ec->num_crtcs = resources->count_crtcs;
2187 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2188
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002189 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002190 connector = drmModeGetConnector(ec->drm.fd,
2191 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002192 if (connector == NULL)
2193 continue;
2194
2195 if (connector->connection == DRM_MODE_CONNECTED &&
2196 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002197 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002198 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002199 connector, x, y,
2200 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002201 drmModeFreeConnector(connector);
2202 continue;
2203 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002204
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002205 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002206 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002207 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002208 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002209
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002210 drmModeFreeConnector(connector);
2211 }
2212
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002213 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002214 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002215 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002216 return -1;
2217 }
2218
2219 drmModeFreeResources(resources);
2220
2221 return 0;
2222}
2223
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002224static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002225update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002226{
2227 drmModeConnector *connector;
2228 drmModeRes *resources;
2229 struct drm_output *output, *next;
2230 int x = 0, y = 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002231 uint32_t connected = 0, disconnects = 0;
2232 int i;
2233
2234 resources = drmModeGetResources(ec->drm.fd);
2235 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002236 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002237 return;
2238 }
2239
2240 /* collect new connects */
2241 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002242 int connector_id = resources->connectors[i];
2243
2244 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002245 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002246 continue;
2247
David Herrmann7551cff2011-12-08 17:05:43 +01002248 if (connector->connection != DRM_MODE_CONNECTED) {
2249 drmModeFreeConnector(connector);
2250 continue;
2251 }
2252
Benjamin Franzke117483d2011-08-30 11:38:26 +02002253 connected |= (1 << connector_id);
2254
2255 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002256 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002257 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002258 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002259
2260 /* XXX: not yet needed, we die with 0 outputs */
2261 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002262 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002263 else
2264 x = 0;
2265 y = 0;
2266 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002267 connector, x, y,
2268 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002269 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002270
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002271 }
2272 drmModeFreeConnector(connector);
2273 }
2274 drmModeFreeResources(resources);
2275
2276 disconnects = ec->connector_allocator & ~connected;
2277 if (disconnects) {
2278 wl_list_for_each_safe(output, next, &ec->base.output_list,
2279 base.link) {
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002280 if (disconnects & (1 << output->connector_id)) {
2281 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002282 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002283 output->connector_id);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002284 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002285 }
2286 }
2287 }
2288
2289 /* FIXME: handle zero outputs, without terminating */
2290 if (ec->connector_allocator == 0)
2291 wl_display_terminate(ec->base.wl_display);
2292}
2293
2294static int
David Herrmannd7488c22012-03-11 20:05:21 +01002295udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002296{
David Herrmannd7488c22012-03-11 20:05:21 +01002297 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002298 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002299
2300 sysnum = udev_device_get_sysnum(device);
2301 if (!sysnum || atoi(sysnum) != ec->drm.id)
2302 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002303
David Herrmann6ac52db2012-03-11 20:05:22 +01002304 val = udev_device_get_property_value(device, "HOTPLUG");
2305 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002306 return 0;
2307
David Herrmann6ac52db2012-03-11 20:05:22 +01002308 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002309}
2310
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002311static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002312udev_drm_event(int fd, uint32_t mask, void *data)
2313{
2314 struct drm_compositor *ec = data;
2315 struct udev_device *event;
2316
2317 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002318
David Herrmannd7488c22012-03-11 20:05:21 +01002319 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002320 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002321
2322 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002323
2324 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002325}
2326
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002327static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002328drm_restore(struct weston_compositor *ec)
2329{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002330 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002331}
2332
2333static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002334drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002335{
2336 struct drm_compositor *d = (struct drm_compositor *) ec;
2337
Rob Bradfordd355b802013-05-31 18:09:55 +01002338 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002339
2340 wl_event_source_remove(d->udev_drm_source);
2341 wl_event_source_remove(d->drm_source);
2342
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002343 destroy_sprites(d);
2344
Ander Conselvan de Oliveira6b162142013-10-25 16:26:32 +03002345 weston_compositor_shutdown(ec);
2346
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002347 if (d->gbm)
2348 gbm_device_destroy(d->gbm);
2349
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002350 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002351
Rob Bradford45c15b82013-07-26 16:29:35 +01002352 close(d->drm.fd);
2353
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002354 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002355}
2356
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002357static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002358drm_compositor_set_modes(struct drm_compositor *compositor)
2359{
2360 struct drm_output *output;
2361 struct drm_mode *drm_mode;
2362 int ret;
2363
2364 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002365 if (!output->current) {
2366 /* If something that would cause the output to
2367 * switch mode happened while in another vt, we
2368 * might not have a current drm_fb. In that case,
2369 * schedule a repaint and let drm_output_repaint
2370 * handle setting the mode. */
2371 weston_output_schedule_repaint(&output->base);
2372 continue;
2373 }
2374
Hardeningff39efa2013-09-18 23:56:35 +02002375 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002376 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002377 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002378 &output->connector_id, 1,
2379 &drm_mode->mode_info);
2380 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002381 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002382 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002383 drm_mode->base.width, drm_mode->base.height,
2384 output->base.x, output->base.y);
2385 }
2386 }
2387}
2388
2389static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002390session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002391{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002392 struct weston_compositor *compositor = data;
2393 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002394 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002395 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002396
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002397 if (ec->base.session_active) {
2398 weston_log("activating session\n");
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002399 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002400 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002401 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002402 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002403 } else {
2404 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002405 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002406
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002407 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002408 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002409
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002410 /* If we have a repaint scheduled (either from a
2411 * pending pageflip or the idle handler), make sure we
2412 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002413 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002414 * further attemps at repainting. When we switch
2415 * back, we schedule a repaint, which will process
2416 * pending frame callbacks. */
2417
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002418 wl_list_for_each(output, &ec->base.output_list, base.link) {
2419 output->base.repaint_needed = 0;
2420 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002421 }
2422
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002423 output = container_of(ec->base.output_list.next,
2424 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002425
2426 wl_list_for_each(sprite, &ec->sprite_list, link)
2427 drmModeSetPlane(ec->drm.fd,
2428 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002429 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002430 0, 0, 0, 0, 0, 0, 0, 0);
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002431 };
2432}
2433
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002434static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002435switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002436{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002437 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002438
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002439 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002440}
2441
David Herrmann0af066f2012-10-29 19:21:16 +01002442/*
2443 * Find primary GPU
2444 * Some systems may have multiple DRM devices attached to a single seat. This
2445 * function loops over all devices and tries to find a PCI device with the
2446 * boot_vga sysfs attribute set to 1.
2447 * If no such device is found, the first DRM device reported by udev is used.
2448 */
2449static struct udev_device*
2450find_primary_gpu(struct drm_compositor *ec, const char *seat)
2451{
2452 struct udev_enumerate *e;
2453 struct udev_list_entry *entry;
2454 const char *path, *device_seat, *id;
2455 struct udev_device *device, *drm_device, *pci;
2456
2457 e = udev_enumerate_new(ec->udev);
2458 udev_enumerate_add_match_subsystem(e, "drm");
2459 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2460
2461 udev_enumerate_scan_devices(e);
2462 drm_device = NULL;
2463 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2464 path = udev_list_entry_get_name(entry);
2465 device = udev_device_new_from_syspath(ec->udev, path);
2466 if (!device)
2467 continue;
2468 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2469 if (!device_seat)
2470 device_seat = default_seat;
2471 if (strcmp(device_seat, seat)) {
2472 udev_device_unref(device);
2473 continue;
2474 }
2475
2476 pci = udev_device_get_parent_with_subsystem_devtype(device,
2477 "pci", NULL);
2478 if (pci) {
2479 id = udev_device_get_sysattr_value(pci, "boot_vga");
2480 if (id && !strcmp(id, "1")) {
2481 if (drm_device)
2482 udev_device_unref(drm_device);
2483 drm_device = device;
2484 break;
2485 }
2486 }
2487
2488 if (!drm_device)
2489 drm_device = device;
2490 else
2491 udev_device_unref(device);
2492 }
2493
2494 udev_enumerate_unref(e);
2495 return drm_device;
2496}
2497
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002498static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002499planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002500{
2501 struct drm_compositor *c = data;
2502
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002503 switch (key) {
2504 case KEY_C:
2505 c->cursors_are_broken ^= 1;
2506 break;
2507 case KEY_V:
2508 c->sprites_are_broken ^= 1;
2509 break;
2510 case KEY_O:
2511 c->sprites_hidden ^= 1;
2512 break;
2513 default:
2514 break;
2515 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002516}
2517
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002518#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002519static void
2520recorder_frame_notify(struct wl_listener *listener, void *data)
2521{
2522 struct drm_output *output;
2523 struct drm_compositor *c;
2524 int fd, ret;
2525
2526 output = container_of(listener, struct drm_output,
2527 recorder_frame_listener);
2528 c = (struct drm_compositor *) output->base.compositor;
2529
2530 if (!output->recorder)
2531 return;
2532
2533 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2534 DRM_CLOEXEC, &fd);
2535 if (ret) {
2536 weston_log("[libva recorder] "
2537 "failed to create prime fd for front buffer\n");
2538 return;
2539 }
2540
2541 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002542}
2543
2544static void *
2545create_recorder(struct drm_compositor *c, int width, int height,
2546 const char *filename)
2547{
2548 int fd;
2549 drm_magic_t magic;
2550
2551 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2552 if (fd < 0)
2553 return NULL;
2554
2555 drmGetMagic(fd, &magic);
2556 drmAuthMagic(c->drm.fd, magic);
2557
2558 return vaapi_recorder_create(fd, width, height, filename);
2559}
2560
2561static void
2562recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2563 void *data)
2564{
2565 struct drm_compositor *c = data;
2566 struct drm_output *output;
2567 int width, height;
2568
2569 output = container_of(c->base.output_list.next,
2570 struct drm_output, base.link);
2571
2572 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002573 width = output->base.current_mode->width;
2574 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002575
2576 output->recorder =
2577 create_recorder(c, width, height, "capture.h264");
2578 if (!output->recorder) {
2579 weston_log("failed to create vaapi recorder\n");
2580 return;
2581 }
2582
2583 output->base.disable_planes++;
2584
2585 output->recorder_frame_listener.notify = recorder_frame_notify;
2586 wl_signal_add(&output->base.frame_signal,
2587 &output->recorder_frame_listener);
2588
2589 weston_output_schedule_repaint(&output->base);
2590
2591 weston_log("[libva recorder] initialized\n");
2592 } else {
2593 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002594 output->recorder = NULL;
2595
2596 output->base.disable_planes--;
2597
2598 wl_list_remove(&output->recorder_frame_listener.link);
2599 weston_log("[libva recorder] done\n");
2600 }
2601}
2602#else
2603static void
2604recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2605 void *data)
2606{
2607 weston_log("Compiled without libva support\n");
2608}
2609#endif
2610
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002611static void
2612switch_to_gl_renderer(struct drm_compositor *c)
2613{
2614 struct drm_output *output;
2615
2616 if (!c->use_pixman)
2617 return;
2618
2619 weston_log("Switching to GL renderer\n");
2620
2621 c->gbm = create_gbm_device(c->drm.fd);
2622 if (!c->gbm) {
2623 weston_log("Failed to create gbm device. "
2624 "Aborting renderer switch\n");
2625 return;
2626 }
2627
2628 wl_list_for_each(output, &c->base.output_list, base.link)
2629 pixman_renderer_output_destroy(&output->base);
2630
2631 c->base.renderer->destroy(&c->base);
2632
2633 if (drm_compositor_create_gl_renderer(c) < 0) {
2634 gbm_device_destroy(c->gbm);
2635 weston_log("Failed to create GL renderer. Quitting.\n");
2636 /* FIXME: we need a function to shutdown cleanly */
2637 assert(0);
2638 }
2639
2640 wl_list_for_each(output, &c->base.output_list, base.link)
2641 drm_output_init_egl(output, c);
2642
2643 c->use_pixman = 0;
2644}
2645
2646static void
2647renderer_switch_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2648 void *data)
2649{
2650 struct drm_compositor *c = (struct drm_compositor *) seat->compositor;
2651
2652 switch_to_gl_renderer(c);
2653}
2654
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002655static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002656drm_compositor_create(struct wl_display *display,
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002657 struct drm_parameters *param,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002658 int *argc, char *argv[],
2659 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002660{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002661 struct drm_compositor *ec;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002662 struct weston_config_section *section;
David Herrmann0af066f2012-10-29 19:21:16 +01002663 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002664 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002665 const char *path;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002666 char *s;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002667 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002668
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002669 weston_log("initializing drm backend\n");
2670
Peter Huttererf3d62272013-08-08 11:57:05 +10002671 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002672 if (ec == NULL)
2673 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002674
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002675 /* KMS support for sprites is not complete yet, so disable the
2676 * functionality for now. */
2677 ec->sprites_are_broken = 1;
Kristian Høgsberg8e6f3762013-10-16 16:31:42 -07002678
2679 section = weston_config_get_section(config, "core", NULL, NULL);
2680 weston_config_section_get_string(section,
2681 "gbm-format", &s, "xrgb8888");
2682 if (strcmp(s, "xrgb8888") == 0)
2683 ec->format = GBM_FORMAT_XRGB8888;
2684 else if (strcmp(s, "rgb565") == 0)
2685 ec->format = GBM_FORMAT_RGB565;
2686 else if (strcmp(s, "xrgb2101010") == 0)
2687 ec->format = GBM_FORMAT_XRGB2101010;
2688 else {
2689 weston_log("fatal: unrecognized pixel format: %s\n", s);
2690 free(s);
2691 goto err_base;
2692 }
2693 free(s);
2694
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002695 ec->use_pixman = param->use_pixman;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002696
Daniel Stone725c2c32012-06-22 14:04:36 +01002697 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002698 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002699 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002700 goto err_base;
2701 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002702
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002703 /* Check if we run drm-backend using weston-launch */
David Herrmanncc5b2ed2013-10-22 00:28:09 +02002704 ec->base.launcher = weston_launcher_connect(&ec->base, param->tty,
2705 param->seat_id);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002706 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002707 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002708 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002709 goto err_compositor;
2710 }
2711
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002712 ec->udev = udev_new();
2713 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002714 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002715 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002716 }
2717
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002718 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002719 ec->session_listener.notify = session_notify;
2720 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002721
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002722 drm_device = find_primary_gpu(ec, param->seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002723 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002724 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002725 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002726 }
David Herrmann0af066f2012-10-29 19:21:16 +01002727 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002728
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002729 if (init_drm(ec, drm_device) < 0) {
2730 weston_log("failed to initialize kms\n");
2731 goto err_udev_dev;
2732 }
2733
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002734 if (ec->use_pixman) {
2735 if (init_pixman(ec) < 0) {
2736 weston_log("failed to initialize pixman renderer\n");
2737 goto err_udev_dev;
2738 }
2739 } else {
2740 if (init_egl(ec) < 0) {
2741 weston_log("failed to initialize egl\n");
2742 goto err_udev_dev;
2743 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002744 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002745
2746 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002747 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002748
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002749 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002750
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002751 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002752 weston_compositor_add_key_binding(&ec->base, key,
2753 MODIFIER_CTRL | MODIFIER_ALT,
2754 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002755
Jesse Barnes58ef3792012-02-23 09:45:49 -05002756 wl_list_init(&ec->sprite_list);
2757 create_sprites(ec);
2758
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002759 if (create_outputs(ec, param->connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002760 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002761 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002762 }
2763
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002764 path = NULL;
2765
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002766 if (udev_input_init(&ec->input,
2767 &ec->base, ec->udev, param->seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002768 weston_log("failed to create input devices\n");
2769 goto err_sprite;
2770 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002771
2772 loop = wl_display_get_event_loop(ec->base.wl_display);
2773 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002774 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002775 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002776
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002777 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2778 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002779 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002780 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002781 }
2782 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2783 "drm", NULL);
2784 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002785 wl_event_loop_add_fd(loop,
2786 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002787 WL_EVENT_READABLE, udev_drm_event, ec);
2788
2789 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002790 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002791 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002792 }
2793
Daniel Stonea96b93c2012-06-22 14:04:37 +01002794 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002795
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002796 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002797 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002798 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002799 planes_binding, ec);
2800 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2801 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002802 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2803 recorder_binding, ec);
Ander Conselvan de Oliveira65796812013-11-19 15:22:04 +02002804 weston_compositor_add_debug_binding(&ec->base, KEY_W,
2805 renderer_switch_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002806
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002807 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002808
2809err_udev_monitor:
2810 wl_event_source_remove(ec->udev_drm_source);
2811 udev_monitor_unref(ec->udev_monitor);
2812err_drm_source:
2813 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002814 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002815err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002816 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002817 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002818 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002819err_udev_dev:
2820 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002821err_launcher:
2822 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002823err_udev:
2824 udev_unref(ec->udev);
2825err_compositor:
2826 weston_compositor_shutdown(&ec->base);
2827err_base:
2828 free(ec);
2829 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002830}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002831
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002832WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002833backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002834 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002835{
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002836 struct drm_parameters param = { 0, };
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002837
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002838 const struct weston_option drm_options[] = {
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002839 { WESTON_OPTION_INTEGER, "connector", 0, &param.connector },
2840 { WESTON_OPTION_STRING, "seat", 0, &param.seat_id },
2841 { WESTON_OPTION_INTEGER, "tty", 0, &param.tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002842 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002843 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &param.use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002844 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002845
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002846 param.seat_id = default_seat;
2847
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002848 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002849
Kristian Høgsbergd8e98332013-10-16 16:15:11 -07002850 return drm_compositor_create(display, &param, argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002851}