blob: ad5a2c308828706f72cf9a438d0c2d9aef65de34 [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 Oliveira95eb3a22013-05-07 14:16:59 +030036#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040037
Benjamin Franzkec649a922011-03-02 11:56:04 +010038#include <xf86drm.h>
39#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050040#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010041
Benjamin Franzke060cf802011-04-30 09:32:11 +020042#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020043#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040044#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020045
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040046#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010047#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020048#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050049#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010050#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030051#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040052
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030053#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
54#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
55#endif
56
Kristian Høgsberg061c4252012-06-28 11:28:15 -040057static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060058
59enum output_config {
60 OUTPUT_CONFIG_INVALID = 0,
61 OUTPUT_CONFIG_OFF,
62 OUTPUT_CONFIG_PREFERRED,
63 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060064 OUTPUT_CONFIG_MODE,
65 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060066};
67
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040068struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050069 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040070
71 struct udev *udev;
72 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040073
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010074 struct udev_monitor *udev_monitor;
75 struct wl_event_source *udev_drm_source;
76
Benjamin Franzke2af7f102011-03-02 11:14:59 +010077 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010078 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010079 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030080 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010081 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020082 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050083 uint32_t *crtcs;
84 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050085 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010086 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070087 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -070088 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020089
Rob Clark4339add2012-08-09 14:18:28 -050090 /* we need these parameters in order to not fail drmModeAddFB2()
91 * due to out of bounds dimensions, and then mistakenly set
92 * sprites_are_broken:
93 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020094 uint32_t min_width, max_width;
95 uint32_t min_height, max_height;
96 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050097
Jesse Barnes58ef3792012-02-23 09:45:49 -050098 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -050099 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200100 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500101
Rob Clarkab5b1e32012-08-09 13:24:45 -0500102 int cursors_are_broken;
103
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200104 int use_pixman;
105
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200106 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300107
108 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100109 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400110};
111
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400112struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500113 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400114 drmModeModeInfo mode_info;
115};
116
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300117struct drm_output;
118
119struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300120 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200121 uint32_t fb_id, stride, handle, size;
122 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300123 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200124 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200125
126 /* Used by gbm fbs */
127 struct gbm_bo *bo;
128
129 /* Used by dumb fbs */
130 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300131};
132
Richard Hughes2b2092a2013-04-24 14:58:02 +0100133struct drm_edid {
134 char eisa_id[13];
135 char monitor_name[13];
136 char pnp_id[5];
137 char serial_number[13];
138};
139
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400140struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500141 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400142
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500144 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400145 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700146 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100147 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300148 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200149
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300150 int vblank_pending;
151 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800152 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300153
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400154 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400155 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400156 struct weston_plane cursor_plane;
157 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400158 struct weston_surface *cursor_surface;
159 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300160 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200161 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200162
163 struct drm_fb *dumb[2];
164 pixman_image_t *image[2];
165 int current_image;
166 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300167
168 struct vaapi_recorder *recorder;
169 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400170};
171
Jesse Barnes58ef3792012-02-23 09:45:49 -0500172/*
173 * An output has a primary display plane plus zero or more sprites for
174 * blending display contents.
175 */
176struct drm_sprite {
177 struct wl_list link;
178
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400179 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500180
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200181 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300182 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500183 struct drm_compositor *compositor;
184
Jesse Barnes58ef3792012-02-23 09:45:49 -0500185 uint32_t possible_crtcs;
186 uint32_t plane_id;
187 uint32_t count_formats;
188
189 int32_t src_x, src_y;
190 uint32_t src_w, src_h;
191 uint32_t dest_x, dest_y;
192 uint32_t dest_w, dest_h;
193
194 uint32_t formats[];
195};
196
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500197static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400198
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400199static void
200drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400201
Jesse Barnes58ef3792012-02-23 09:45:49 -0500202static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500203drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
204{
205 struct weston_compositor *ec = output_base->compositor;
206 struct drm_compositor *c =(struct drm_compositor *) ec;
207 struct drm_output *output = (struct drm_output *) output_base;
208 int crtc;
209
210 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
211 if (c->crtcs[crtc] != output->crtc_id)
212 continue;
213
214 if (supported & (1 << crtc))
215 return -1;
216 }
217
218 return 0;
219}
220
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300221static void
222drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
223{
224 struct drm_fb *fb = data;
225 struct gbm_device *gbm = gbm_bo_get_device(bo);
226
227 if (fb->fb_id)
228 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
229
Pekka Paalanende685b82012-12-04 15:58:12 +0200230 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300231
232 free(data);
233}
234
235static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200236drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
237{
238 struct drm_fb *fb;
239 int ret;
240
241 struct drm_mode_create_dumb create_arg;
242 struct drm_mode_destroy_dumb destroy_arg;
243 struct drm_mode_map_dumb map_arg;
244
Peter Huttererf3d62272013-08-08 11:57:05 +1000245 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200246 if (!fb)
247 return NULL;
248
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700249 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200250 create_arg.bpp = 32;
251 create_arg.width = width;
252 create_arg.height = height;
253
254 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
255 if (ret)
256 goto err_fb;
257
258 fb->handle = create_arg.handle;
259 fb->stride = create_arg.pitch;
260 fb->size = create_arg.size;
261 fb->fd = ec->drm.fd;
262
263 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
264 fb->stride, fb->handle, &fb->fb_id);
265 if (ret)
266 goto err_bo;
267
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700268 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200269 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400270 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200271 if (ret)
272 goto err_add_fb;
273
274 fb->map = mmap(0, fb->size, PROT_WRITE,
275 MAP_SHARED, ec->drm.fd, map_arg.offset);
276 if (fb->map == MAP_FAILED)
277 goto err_add_fb;
278
279 return fb;
280
281err_add_fb:
282 drmModeRmFB(ec->drm.fd, fb->fb_id);
283err_bo:
284 memset(&destroy_arg, 0, sizeof(destroy_arg));
285 destroy_arg.handle = create_arg.handle;
286 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
287err_fb:
288 free(fb);
289 return NULL;
290}
291
292static void
293drm_fb_destroy_dumb(struct drm_fb *fb)
294{
295 struct drm_mode_destroy_dumb destroy_arg;
296
297 if (!fb->map)
298 return;
299
300 if (fb->fb_id)
301 drmModeRmFB(fb->fd, fb->fb_id);
302
303 weston_buffer_reference(&fb->buffer_ref, NULL);
304
305 munmap(fb->map, fb->size);
306
307 memset(&destroy_arg, 0, sizeof(destroy_arg));
308 destroy_arg.handle = fb->handle;
309 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
310
311 free(fb);
312}
313
314static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500315drm_fb_get_from_bo(struct gbm_bo *bo,
316 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300317{
318 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200319 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200320 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300321 int ret;
322
323 if (fb)
324 return fb;
325
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200326 fb = calloc(1, sizeof *fb);
327 if (!fb)
328 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300329
330 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300331
332 width = gbm_bo_get_width(bo);
333 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200334 fb->stride = gbm_bo_get_stride(bo);
335 fb->handle = gbm_bo_get_handle(bo).u32;
336 fb->size = fb->stride * height;
337 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300338
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200339 if (compositor->min_width > width || width > compositor->max_width ||
340 compositor->min_height > height ||
341 height > compositor->max_height) {
342 weston_log("bo geometry out of bounds\n");
343 goto err_free;
344 }
345
346 ret = -1;
347
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200348 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200349 handles[0] = fb->handle;
350 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200351 offsets[0] = 0;
352
353 ret = drmModeAddFB2(compositor->drm.fd, width, height,
354 format, handles, pitches, offsets,
355 &fb->fb_id, 0);
356 if (ret) {
357 weston_log("addfb2 failed: %m\n");
358 compositor->no_addfb2 = 1;
359 compositor->sprites_are_broken = 1;
360 }
361 }
362
363 if (ret)
364 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200365 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200366
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300367 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200368 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200369 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300370 }
371
372 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
373
374 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200375
376err_free:
377 free(fb);
378 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300379}
380
381static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500382drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200383{
Pekka Paalanende685b82012-12-04 15:58:12 +0200384 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200385
386 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200387
Pekka Paalanende685b82012-12-04 15:58:12 +0200388 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200389}
390
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200391static void
392drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
393{
394 if (!fb)
395 return;
396
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200397 if (fb->map &&
398 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200399 drm_fb_destroy_dumb(fb);
400 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200401 if (fb->is_client_buffer)
402 gbm_bo_destroy(fb->bo);
403 else
404 gbm_surface_release_buffer(output->surface,
405 output->current->bo);
406 }
407}
408
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500409static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200410drm_output_check_scanout_format(struct drm_output *output,
411 struct weston_surface *es, struct gbm_bo *bo)
412{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200413 uint32_t format;
414 pixman_region32_t r;
415
416 format = gbm_bo_get_format(bo);
417
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500418 switch (format) {
419 case GBM_FORMAT_XRGB8888:
420 return format;
421 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200422 /* We can only scanout an ARGB buffer if the surface's
423 * opaque region covers the whole output */
424 pixman_region32_init(&r);
425 pixman_region32_subtract(&r, &output->base.region,
426 &es->opaque);
427
428 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500429 format = GBM_FORMAT_XRGB8888;
430 else
431 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200432
433 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200434
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500435 return format;
436 default:
437 return 0;
438 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200439}
440
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400441static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400442drm_output_prepare_scanout_surface(struct weston_output *_output,
443 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500444{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400445 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500446 struct drm_compositor *c =
447 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500448 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300449 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500450 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500451
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500452 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200453 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200454 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200455 buffer->width != output->base.current_mode->width ||
456 buffer->height != output->base.current_mode->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200457 output->base.transform != es->buffer_transform ||
458 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400459 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500460
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400461 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700462 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500463
Rob Bradford9b101872012-09-14 23:25:41 +0100464 /* Unable to use the buffer for scanout */
465 if (!bo)
466 return NULL;
467
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500468 format = drm_output_check_scanout_format(output, es, bo);
469 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300470 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400471 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300472 }
473
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500474 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300475 if (!output->next) {
476 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400477 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300478 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500479
Pekka Paalanende685b82012-12-04 15:58:12 +0200480 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500481
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400482 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500483}
484
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500485static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200486drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400487{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200488 struct drm_compositor *c =
489 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300490 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400491
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200492 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400493
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300494 bo = gbm_surface_lock_front_buffer(output->surface);
495 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200496 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400497 return;
498 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300499
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700500 output->next = drm_fb_get_from_bo(bo, c, c->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200502 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 gbm_surface_release_buffer(output->surface, bo);
504 return;
505 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400506}
507
508static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200509drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
510{
511 struct weston_compositor *ec = output->base.compositor;
512 pixman_region32_t total_damage, previous_damage;
513
514 pixman_region32_init(&total_damage);
515 pixman_region32_init(&previous_damage);
516
517 pixman_region32_copy(&previous_damage, damage);
518
519 pixman_region32_union(&total_damage, damage, &output->previous_damage);
520 pixman_region32_copy(&output->previous_damage, &previous_damage);
521
522 output->current_image ^= 1;
523
524 output->next = output->dumb[output->current_image];
525 pixman_renderer_output_set_buffer(&output->base,
526 output->image[output->current_image]);
527
528 ec->renderer->repaint_output(&output->base, &total_damage);
529
530 pixman_region32_fini(&total_damage);
531 pixman_region32_fini(&previous_damage);
532}
533
534static void
535drm_output_render(struct drm_output *output, pixman_region32_t *damage)
536{
537 struct drm_compositor *c =
538 (struct drm_compositor *) output->base.compositor;
539
540 if (c->use_pixman)
541 drm_output_render_pixman(output, damage);
542 else
543 drm_output_render_gl(output, damage);
544
545 pixman_region32_subtract(&c->base.primary_plane.damage,
546 &c->base.primary_plane.damage, damage);
547}
548
549static void
Richard Hughese7299962013-05-01 21:52:12 +0100550drm_output_set_gamma(struct weston_output *output_base,
551 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
552{
553 int rc;
554 struct drm_output *output = (struct drm_output *) output_base;
555 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
556
557 /* check */
558 if (output_base->gamma_size != size)
559 return;
560 if (!output->original_crtc)
561 return;
562
563 rc = drmModeCrtcSetGamma(compositor->drm.fd,
564 output->crtc_id,
565 size, r, g, b);
566 if (rc)
567 weston_log("set gamma failed: %m\n");
568}
569
570static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500571drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400572 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100573{
574 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500575 struct drm_compositor *compositor =
576 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500577 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400578 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500579 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100580
Xiong Zhangabd5d472013-10-11 14:43:07 +0800581 if (output->destroy_pending)
582 return;
583
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300584 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400585 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300586 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400587 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100588
Hardeningff39efa2013-09-18 23:56:35 +0200589 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300590 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400591 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300592 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400593 &output->connector_id, 1,
594 &mode->mode_info);
595 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200596 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400597 return;
598 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300599 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200600 }
601
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500602 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300603 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500604 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200605 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500606 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500607 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100608
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300609 output->page_flip_pending = 1;
610
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400611 drm_output_set_cursor(output);
612
Jesse Barnes58ef3792012-02-23 09:45:49 -0500613 /*
614 * Now, update all the sprite surfaces
615 */
616 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200617 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500618 drmVBlank vbl = {
619 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
620 .request.sequence = 1,
621 };
622
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200623 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200624 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500625 continue;
626
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200627 if (s->next && !compositor->sprites_hidden)
628 fb_id = s->next->fb_id;
629
Jesse Barnes58ef3792012-02-23 09:45:49 -0500630 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200631 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 s->dest_x, s->dest_y,
633 s->dest_w, s->dest_h,
634 s->src_x, s->src_y,
635 s->src_w, s->src_h);
636 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200637 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500638 ret, strerror(errno));
639
Rob Clark5ca1a472012-08-08 20:27:37 -0500640 if (output->pipe > 0)
641 vbl.request.type |= DRM_VBLANK_SECONDARY;
642
Jesse Barnes58ef3792012-02-23 09:45:49 -0500643 /*
644 * Queue a vblank signal so we know when the surface
645 * becomes active on the display or has been replaced.
646 */
647 vbl.request.signal = (unsigned long)s;
648 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
649 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200650 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500651 ret, strerror(errno));
652 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300653
654 s->output = output;
655 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500656 }
657
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500658 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400659}
660
661static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200662drm_output_start_repaint_loop(struct weston_output *output_base)
663{
664 struct drm_output *output = (struct drm_output *) output_base;
665 struct drm_compositor *compositor = (struct drm_compositor *)
666 output_base->compositor;
667 uint32_t fb_id;
668
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300669 struct timespec ts;
670
Xiong Zhangabd5d472013-10-11 14:43:07 +0800671 if (output->destroy_pending)
672 return;
673
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300674 if (!output->current) {
675 /* We can't page flip if there's no mode set */
676 uint32_t msec;
677
678 clock_gettime(compositor->clock, &ts);
679 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
680 weston_output_finish_frame(output_base, msec);
681 return;
682 }
683
684 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200685
686 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
687 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
688 weston_log("queueing pageflip failed: %m\n");
689 return;
690 }
691}
692
693static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500694vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
695 void *data)
696{
697 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300698 struct drm_output *output = s->output;
699 uint32_t msecs;
700
701 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500702
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200703 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200704 s->current = s->next;
705 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300706
707 if (!output->page_flip_pending) {
708 msecs = sec * 1000 + usec / 1000;
709 weston_output_finish_frame(&output->base, msecs);
710 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500711}
712
713static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800714drm_output_destroy(struct weston_output *output_base);
715
716static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400717page_flip_handler(int fd, unsigned int frame,
718 unsigned int sec, unsigned int usec, void *data)
719{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200720 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400721 uint32_t msecs;
722
Jonas Ådahle5a12252013-04-05 23:07:11 +0200723 /* We don't set page_flip_pending on start_repaint_loop, in that case
724 * we just want to page flip to the current buffer to get an accurate
725 * timestamp */
726 if (output->page_flip_pending) {
727 drm_output_release_fb(output, output->current);
728 output->current = output->next;
729 output->next = NULL;
730 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300731
Jonas Ådahle5a12252013-04-05 23:07:11 +0200732 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400733
Xiong Zhangabd5d472013-10-11 14:43:07 +0800734 if (output->destroy_pending)
735 drm_output_destroy(&output->base);
736 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300737 msecs = sec * 1000 + usec / 1000;
738 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300739
740 /* We can't call this from frame_notify, because the output's
741 * repaint needed flag is cleared just after that */
742 if (output->recorder)
743 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300744 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200745}
746
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500747static uint32_t
748drm_output_check_sprite_format(struct drm_sprite *s,
749 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500750{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500751 uint32_t i, format;
752
753 format = gbm_bo_get_format(bo);
754
755 if (format == GBM_FORMAT_ARGB8888) {
756 pixman_region32_t r;
757
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500758 pixman_region32_init_rect(&r, 0, 0,
759 es->geometry.width,
760 es->geometry.height);
761 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500762
763 if (!pixman_region32_not_empty(&r))
764 format = GBM_FORMAT_XRGB8888;
765
766 pixman_region32_fini(&r);
767 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500768
769 for (i = 0; i < s->count_formats; i++)
770 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500771 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772
773 return 0;
774}
775
776static int
777drm_surface_transform_supported(struct weston_surface *es)
778{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500779 return !es->transform.enabled ||
780 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500781}
782
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400783static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500784drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400785 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500786{
787 struct weston_compositor *ec = output_base->compositor;
788 struct drm_compositor *c =(struct drm_compositor *) ec;
789 struct drm_sprite *s;
790 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500791 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500792 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200793 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500794 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400795 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200797 if (c->gbm == NULL)
798 return NULL;
799
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200800 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200801 return NULL;
802
Hardeningff39efa2013-09-18 23:56:35 +0200803 if (es->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200804 return NULL;
805
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500806 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400807 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500808
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300809 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300811
Pekka Paalanende685b82012-12-04 15:58:12 +0200812 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400813 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500814
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200815 if (es->alpha != 1.0f)
816 return NULL;
817
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500818 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500819 return NULL;
820
Jesse Barnes58ef3792012-02-23 09:45:49 -0500821 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400822 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824 wl_list_for_each(s, &c->sprite_list, link) {
825 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
826 continue;
827
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200828 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500829 found = 1;
830 break;
831 }
832 }
833
834 /* No sprites available */
835 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400836 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500837
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400838 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700839 es->buffer_ref.buffer->resource,
840 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400841 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400842 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400843
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500844 format = drm_output_check_sprite_format(s, es, bo);
845 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200846 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400847 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500848 }
849
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200850 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200851 if (!s->next) {
852 gbm_bo_destroy(bo);
853 return NULL;
854 }
855
Pekka Paalanende685b82012-12-04 15:58:12 +0200856 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500857
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400858 box = pixman_region32_extents(&es->transform.boundingbox);
859 s->plane.x = box->x1;
860 s->plane.y = box->y1;
861
Jesse Barnes58ef3792012-02-23 09:45:49 -0500862 /*
863 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200864 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500865 * for us already).
866 */
867 pixman_region32_init(&dest_rect);
868 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
869 &output_base->region);
870 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
871 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200872 tbox = weston_transformed_rect(output_base->width,
873 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200874 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200875 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200876 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200877 s->dest_x = tbox.x1;
878 s->dest_y = tbox.y1;
879 s->dest_w = tbox.x2 - tbox.x1;
880 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500881 pixman_region32_fini(&dest_rect);
882
883 pixman_region32_init(&src_rect);
884 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
885 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500886 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400887
888 weston_surface_from_global_fixed(es,
889 wl_fixed_from_int(box->x1),
890 wl_fixed_from_int(box->y1),
891 &sx1, &sy1);
892 weston_surface_from_global_fixed(es,
893 wl_fixed_from_int(box->x2),
894 wl_fixed_from_int(box->y2),
895 &sx2, &sy2);
896
897 if (sx1 < 0)
898 sx1 = 0;
899 if (sy1 < 0)
900 sy1 = 0;
901 if (sx2 > wl_fixed_from_int(es->geometry.width))
902 sx2 = wl_fixed_from_int(es->geometry.width);
903 if (sy2 > wl_fixed_from_int(es->geometry.height))
904 sy2 = wl_fixed_from_int(es->geometry.height);
905
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200906 tbox.x1 = sx1;
907 tbox.y1 = sy1;
908 tbox.x2 = sx2;
909 tbox.y2 = sy2;
910
911 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
912 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200913 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200914
915 s->src_x = tbox.x1 << 8;
916 s->src_y = tbox.y1 << 8;
917 s->src_w = (tbox.x2 - tbox.x1) << 8;
918 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500919 pixman_region32_fini(&src_rect);
920
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400921 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500922}
923
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400924static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400925drm_output_prepare_cursor_surface(struct weston_output *output_base,
926 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500927{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400928 struct drm_compositor *c =
929 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400930 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400931
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200932 if (c->gbm == NULL)
933 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200934 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
935 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400936 if (output->cursor_surface)
937 return NULL;
938 if (es->output_mask != (1u << output_base->id))
939 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500940 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400941 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200942 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500943 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400944 es->geometry.width > 64 || es->geometry.height > 64)
945 return NULL;
946
947 output->cursor_surface = es;
948
949 return &output->cursor_plane;
950}
951
952static void
953drm_output_set_cursor(struct drm_output *output)
954{
955 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400956 struct drm_compositor *c =
957 (struct drm_compositor *) output->base.compositor;
958 EGLint handle, stride;
959 struct gbm_bo *bo;
960 uint32_t buf[64 * 64];
961 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400962 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500963
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400964 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400965 if (es == NULL) {
966 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
967 return;
968 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500969
Pekka Paalanende685b82012-12-04 15:58:12 +0200970 if (es->buffer_ref.buffer &&
971 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400972 pixman_region32_fini(&output->cursor_plane.damage);
973 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400974 output->current_cursor ^= 1;
975 bo = output->cursor_bo[output->current_cursor];
976 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500977 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
978 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400979 for (i = 0; i < es->geometry.height; i++)
980 memcpy(buf + i * 64, s + i * stride,
981 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500982
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400983 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300984 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400985
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400986 handle = gbm_bo_get_handle(bo).s32;
987 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500988 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300989 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500990 c->cursors_are_broken = 1;
991 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400992 }
993
Hardeningff39efa2013-09-18 23:56:35 +0200994 x = (es->geometry.x - output->base.x) * output->base.current_scale;
995 y = (es->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400996 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500997 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400998 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500999 c->cursors_are_broken = 1;
1000 }
1001
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001002 output->cursor_plane.x = x;
1003 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001004 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001005}
1006
Jesse Barnes58ef3792012-02-23 09:45:49 -05001007static void
1008drm_assign_planes(struct weston_output *output)
1009{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001010 struct drm_compositor *c =
1011 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001012 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001013 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001014 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001015
1016 /*
1017 * Find a surface for each sprite in the output using some heuristics:
1018 * 1) size
1019 * 2) frequency of update
1020 * 3) opacity (though some hw might support alpha blending)
1021 * 4) clipping (this can be fixed with color keys)
1022 *
1023 * The idea is to save on blitting since this should save power.
1024 * If we can get a large video surface on the sprite for example,
1025 * the main display surface may not need to update at all, and
1026 * the client buffer can be used directly for the sprite surface
1027 * as we do for flipping full screen surfaces.
1028 */
1029 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001030 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001031 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001032 /* test whether this buffer can ever go into a plane:
1033 * non-shm, or small enough to be a cursor
1034 */
1035 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001036 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001037 (es->geometry.width <= 64 && es->geometry.height <= 64))
1038 es->keep_buffer = 1;
1039 else
1040 es->keep_buffer = 0;
1041
Jesse Barnes58ef3792012-02-23 09:45:49 -05001042 pixman_region32_init(&surface_overlap);
1043 pixman_region32_intersect(&surface_overlap, &overlap,
1044 &es->transform.boundingbox);
1045
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001046 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001047 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001048 next_plane = primary;
1049 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001050 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001051 if (next_plane == NULL)
1052 next_plane = drm_output_prepare_scanout_surface(output, es);
1053 if (next_plane == NULL)
1054 next_plane = drm_output_prepare_overlay_surface(output, es);
1055 if (next_plane == NULL)
1056 next_plane = primary;
1057 weston_surface_move_to_plane(es, next_plane);
1058 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001059 pixman_region32_union(&overlap, &overlap,
1060 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001061
Jesse Barnes58ef3792012-02-23 09:45:49 -05001062 pixman_region32_fini(&surface_overlap);
1063 }
1064 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001065}
1066
Matt Roper361d2ad2011-08-29 13:52:23 -07001067static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001068drm_output_fini_pixman(struct drm_output *output);
1069
1070static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001071drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001072{
1073 struct drm_output *output = (struct drm_output *) output_base;
1074 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001075 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001076 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001077
Xiong Zhangabd5d472013-10-11 14:43:07 +08001078 if (output->page_flip_pending) {
1079 output->destroy_pending = 1;
1080 weston_log("destroy output while page flip pending\n");
1081 return;
1082 }
1083
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001084 if (output->backlight)
1085 backlight_destroy(output->backlight);
1086
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001087 drmModeFreeProperty(output->dpms_prop);
1088
Matt Roper361d2ad2011-08-29 13:52:23 -07001089 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001090 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001091
1092 /* Restore original CRTC state */
1093 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001094 origcrtc->x, origcrtc->y,
1095 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001096 drmModeFreeCrtc(origcrtc);
1097
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001098 c->crtc_allocator &= ~(1 << output->crtc_id);
1099 c->connector_allocator &= ~(1 << output->connector_id);
1100
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001101 if (c->use_pixman) {
1102 drm_output_fini_pixman(output);
1103 } else {
1104 gl_renderer_output_destroy(output_base);
1105 gbm_surface_destroy(output->surface);
1106 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001107
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001108 weston_plane_release(&output->fb_plane);
1109 weston_plane_release(&output->cursor_plane);
1110
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001111 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001112 wl_list_remove(&output->base.link);
1113
Matt Roper361d2ad2011-08-29 13:52:23 -07001114 free(output);
1115}
1116
Alex Wub7b8bda2012-04-17 17:20:48 +08001117static struct drm_mode *
1118choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1119{
1120 struct drm_mode *tmp_mode = NULL, *mode;
1121
Hardeningff39efa2013-09-18 23:56:35 +02001122 if (output->base.current_mode->width == target_mode->width &&
1123 output->base.current_mode->height == target_mode->height &&
1124 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001125 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001126 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001127
1128 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1129 if (mode->mode_info.hdisplay == target_mode->width &&
1130 mode->mode_info.vdisplay == target_mode->height) {
1131 if (mode->mode_info.vrefresh == target_mode->refresh ||
1132 target_mode->refresh == 0) {
1133 return mode;
1134 } else if (!tmp_mode)
1135 tmp_mode = mode;
1136 }
1137 }
1138
1139 return tmp_mode;
1140}
1141
1142static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001143drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001144static int
1145drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001146
1147static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001148drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1149{
1150 struct drm_output *output;
1151 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001152 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001153
1154 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001155 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001156 return -1;
1157 }
1158
1159 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001160 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001161 return -1;
1162 }
1163
1164 ec = (struct drm_compositor *)output_base->compositor;
1165 output = (struct drm_output *)output_base;
1166 drm_mode = choose_mode (output, mode);
1167
1168 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001169 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001170 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001171 }
1172
Hardeningff39efa2013-09-18 23:56:35 +02001173 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001174 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001175
Hardeningff39efa2013-09-18 23:56:35 +02001176 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001177
Hardeningff39efa2013-09-18 23:56:35 +02001178 output->base.current_mode = &drm_mode->base;
1179 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001180 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1181
Alex Wub7b8bda2012-04-17 17:20:48 +08001182 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001183 drm_output_release_fb(output, output->current);
1184 drm_output_release_fb(output, output->next);
1185 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001186
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001187 if (ec->use_pixman) {
1188 drm_output_fini_pixman(output);
1189 if (drm_output_init_pixman(output, ec) < 0) {
1190 weston_log("failed to init output pixman state with "
1191 "new mode\n");
1192 return -1;
1193 }
1194 } else {
1195 gl_renderer_output_destroy(&output->base);
1196 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001197
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001198 if (drm_output_init_egl(output, ec) < 0) {
1199 weston_log("failed to init output egl state with "
1200 "new mode");
1201 return -1;
1202 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001203 }
1204
Alex Wub7b8bda2012-04-17 17:20:48 +08001205 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001206}
1207
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001208static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001209on_drm_input(int fd, uint32_t mask, void *data)
1210{
1211 drmEventContext evctx;
1212
1213 memset(&evctx, 0, sizeof evctx);
1214 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1215 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001216 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001217 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001218
1219 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001220}
1221
1222static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001223init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001224{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001225 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001226 uint64_t cap;
1227 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001228
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001229 sysnum = udev_device_get_sysnum(device);
1230 if (sysnum)
1231 ec->drm.id = atoi(sysnum);
1232 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001233 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001234 return -1;
1235 }
1236
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001237 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001238 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001239 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001240 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001241 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001242 udev_device_get_devnode(device));
1243 return -1;
1244 }
1245
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001246 weston_log("using %s\n", filename);
1247
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001248 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001249 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001250
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001251 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1252 if (ret == 0 && cap == 1)
1253 ec->clock = CLOCK_MONOTONIC;
1254 else
1255 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001256
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001257 return 0;
1258}
1259
1260static int
1261init_egl(struct drm_compositor *ec)
1262{
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001263 EGLint format;
1264
Benjamin Franzke060cf802011-04-30 09:32:11 +02001265 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001266
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001267 if (!ec->gbm)
1268 return -1;
1269
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001270 format = ec->format;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001271 if (gl_renderer_create(&ec->base, ec->gbm,
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001272 gl_renderer_opaque_attribs, &format) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001273 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001274 return -1;
1275 }
1276
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001277 return 0;
1278}
1279
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001280static int
1281init_pixman(struct drm_compositor *ec)
1282{
1283 return pixman_renderer_init(&ec->base);
1284}
1285
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001286static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001287drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001288{
1289 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001290 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001291
1292 mode = malloc(sizeof *mode);
1293 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001294 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001295
1296 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001297 mode->base.width = info->hdisplay;
1298 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001299
1300 /* Calculate higher precision (mHz) refresh rate */
1301 refresh = (info->clock * 1000000LL / info->htotal +
1302 info->vtotal / 2) / info->vtotal;
1303
1304 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1305 refresh *= 2;
1306 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1307 refresh /= 2;
1308 if (info->vscan > 1)
1309 refresh /= info->vscan;
1310
1311 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001312 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001313
1314 if (info->type & DRM_MODE_TYPE_PREFERRED)
1315 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1316
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001317 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1318
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001319 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001320}
1321
1322static int
1323drm_subpixel_to_wayland(int drm_value)
1324{
1325 switch (drm_value) {
1326 default:
1327 case DRM_MODE_SUBPIXEL_UNKNOWN:
1328 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1329 case DRM_MODE_SUBPIXEL_NONE:
1330 return WL_OUTPUT_SUBPIXEL_NONE;
1331 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1332 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1333 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1334 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1335 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1336 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1337 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1338 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1339 }
1340}
1341
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001342/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001343static uint32_t
1344drm_get_backlight(struct drm_output *output)
1345{
1346 long brightness, max_brightness, norm;
1347
1348 brightness = backlight_get_brightness(output->backlight);
1349 max_brightness = backlight_get_max_brightness(output->backlight);
1350
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001351 /* convert it on a scale of 0 to 255 */
1352 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001353
1354 return (uint32_t) norm;
1355}
1356
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001357/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001358static void
1359drm_set_backlight(struct weston_output *output_base, uint32_t value)
1360{
1361 struct drm_output *output = (struct drm_output *) output_base;
1362 long max_brightness, new_brightness;
1363
1364 if (!output->backlight)
1365 return;
1366
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001367 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001368 return;
1369
1370 max_brightness = backlight_get_max_brightness(output->backlight);
1371
1372 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001373 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001374
1375 backlight_set_brightness(output->backlight, new_brightness);
1376}
1377
1378static drmModePropertyPtr
1379drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1380{
1381 drmModePropertyPtr props;
1382 int i;
1383
1384 for (i = 0; i < connector->count_props; i++) {
1385 props = drmModeGetProperty(fd, connector->props[i]);
1386 if (!props)
1387 continue;
1388
1389 if (!strcmp(props->name, name))
1390 return props;
1391
1392 drmModeFreeProperty(props);
1393 }
1394
1395 return NULL;
1396}
1397
1398static void
1399drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1400{
1401 struct drm_output *output = (struct drm_output *) output_base;
1402 struct weston_compositor *ec = output_base->compositor;
1403 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001404
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001405 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001406 return;
1407
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001408 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1409 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001410}
1411
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001412static const char *connector_type_names[] = {
1413 "None",
1414 "VGA",
1415 "DVI",
1416 "DVI",
1417 "DVI",
1418 "Composite",
1419 "TV",
1420 "LVDS",
1421 "CTV",
1422 "DIN",
1423 "DP",
1424 "HDMI",
1425 "HDMI",
1426 "TV",
1427 "eDP",
1428};
1429
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001430static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001431find_crtc_for_connector(struct drm_compositor *ec,
1432 drmModeRes *resources, drmModeConnector *connector)
1433{
1434 drmModeEncoder *encoder;
1435 uint32_t possible_crtcs;
1436 int i, j;
1437
1438 for (j = 0; j < connector->count_encoders; j++) {
1439 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1440 if (encoder == NULL) {
1441 weston_log("Failed to get encoder.\n");
1442 return -1;
1443 }
1444 possible_crtcs = encoder->possible_crtcs;
1445 drmModeFreeEncoder(encoder);
1446
1447 for (i = 0; i < resources->count_crtcs; i++) {
1448 if (possible_crtcs & (1 << i) &&
1449 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1450 return i;
1451 }
1452 }
1453
1454 return -1;
1455}
1456
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001457/* Init output state that depends on gl or gbm */
1458static int
1459drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1460{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001461 int i, flags;
1462
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001463 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001464 output->base.current_mode->width,
1465 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001466 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001467 GBM_BO_USE_SCANOUT |
1468 GBM_BO_USE_RENDERING);
1469 if (!output->surface) {
1470 weston_log("failed to create gbm surface\n");
1471 return -1;
1472 }
1473
1474 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001475 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001476 gbm_surface_destroy(output->surface);
1477 return -1;
1478 }
1479
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001480 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1481
1482 for (i = 0; i < 2; i++) {
1483 if (output->cursor_bo[i])
1484 continue;
1485
1486 output->cursor_bo[i] =
1487 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1488 flags);
1489 }
1490
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001491 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1492 weston_log("cursor buffers unavailable, using gl cursors\n");
1493 ec->cursors_are_broken = 1;
1494 }
1495
1496 return 0;
1497}
1498
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001499static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001500drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1501{
Hardeningff39efa2013-09-18 23:56:35 +02001502 int w = output->base.current_mode->width;
1503 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001504 unsigned int i;
1505
1506 /* FIXME error checking */
1507
1508 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001509 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001510 if (!output->dumb[i])
1511 goto err;
1512
1513 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001514 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001515 output->dumb[i]->map,
1516 output->dumb[i]->stride);
1517 if (!output->image[i])
1518 goto err;
1519 }
1520
1521 if (pixman_renderer_output_create(&output->base) < 0)
1522 goto err;
1523
1524 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001525 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001526
1527 return 0;
1528
1529err:
1530 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1531 if (output->dumb[i])
1532 drm_fb_destroy_dumb(output->dumb[i]);
1533 if (output->image[i])
1534 pixman_image_unref(output->image[i]);
1535
1536 output->dumb[i] = NULL;
1537 output->image[i] = NULL;
1538 }
1539
1540 return -1;
1541}
1542
1543static void
1544drm_output_fini_pixman(struct drm_output *output)
1545{
1546 unsigned int i;
1547
1548 pixman_renderer_output_destroy(&output->base);
1549 pixman_region32_fini(&output->previous_damage);
1550
1551 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1552 drm_fb_destroy_dumb(output->dumb[i]);
1553 pixman_image_unref(output->image[i]);
1554 output->dumb[i] = NULL;
1555 output->image[i] = NULL;
1556 }
1557}
1558
Richard Hughes2b2092a2013-04-24 14:58:02 +01001559static void
1560edid_parse_string(const uint8_t *data, char text[])
1561{
1562 int i;
1563 int replaced = 0;
1564
1565 /* this is always 12 bytes, but we can't guarantee it's null
1566 * terminated or not junk. */
1567 strncpy(text, (const char *) data, 12);
1568
1569 /* remove insane chars */
1570 for (i = 0; text[i] != '\0'; i++) {
1571 if (text[i] == '\n' ||
1572 text[i] == '\r') {
1573 text[i] = '\0';
1574 break;
1575 }
1576 }
1577
1578 /* ensure string is printable */
1579 for (i = 0; text[i] != '\0'; i++) {
1580 if (!isprint(text[i])) {
1581 text[i] = '-';
1582 replaced++;
1583 }
1584 }
1585
1586 /* if the string is random junk, ignore the string */
1587 if (replaced > 4)
1588 text[0] = '\0';
1589}
1590
1591#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1592#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1593#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1594#define EDID_OFFSET_DATA_BLOCKS 0x36
1595#define EDID_OFFSET_LAST_BLOCK 0x6c
1596#define EDID_OFFSET_PNPID 0x08
1597#define EDID_OFFSET_SERIAL 0x0c
1598
1599static int
1600edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1601{
1602 int i;
1603 uint32_t serial_number;
1604
1605 /* check header */
1606 if (length < 128)
1607 return -1;
1608 if (data[0] != 0x00 || data[1] != 0xff)
1609 return -1;
1610
1611 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1612 * /--08--\/--09--\
1613 * 7654321076543210
1614 * |\---/\---/\---/
1615 * R C1 C2 C3 */
1616 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1617 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1618 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1619 edid->pnp_id[3] = '\0';
1620
1621 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1622 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1623 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1624 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1625 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1626 if (serial_number > 0)
1627 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1628
1629 /* parse EDID data */
1630 for (i = EDID_OFFSET_DATA_BLOCKS;
1631 i <= EDID_OFFSET_LAST_BLOCK;
1632 i += 18) {
1633 /* ignore pixel clock data */
1634 if (data[i] != 0)
1635 continue;
1636 if (data[i+2] != 0)
1637 continue;
1638
1639 /* any useful blocks? */
1640 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1641 edid_parse_string(&data[i+5],
1642 edid->monitor_name);
1643 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1644 edid_parse_string(&data[i+5],
1645 edid->serial_number);
1646 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1647 edid_parse_string(&data[i+5],
1648 edid->eisa_id);
1649 }
1650 }
1651 return 0;
1652}
1653
1654static void
1655find_and_parse_output_edid(struct drm_compositor *ec,
1656 struct drm_output *output,
1657 drmModeConnector *connector)
1658{
1659 drmModePropertyBlobPtr edid_blob = NULL;
1660 drmModePropertyPtr property;
1661 int i;
1662 int rc;
1663
1664 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1665 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1666 if (!property)
1667 continue;
1668 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1669 !strcmp(property->name, "EDID")) {
1670 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1671 connector->prop_values[i]);
1672 }
1673 drmModeFreeProperty(property);
1674 }
1675 if (!edid_blob)
1676 return;
1677
1678 rc = edid_parse(&output->edid,
1679 edid_blob->data,
1680 edid_blob->length);
1681 if (!rc) {
1682 weston_log("EDID data '%s', '%s', '%s'\n",
1683 output->edid.pnp_id,
1684 output->edid.monitor_name,
1685 output->edid.serial_number);
1686 if (output->edid.pnp_id[0] != '\0')
1687 output->base.make = output->edid.pnp_id;
1688 if (output->edid.monitor_name[0] != '\0')
1689 output->base.model = output->edid.monitor_name;
1690 if (output->edid.serial_number[0] != '\0')
1691 output->base.serial_number = output->edid.serial_number;
1692 }
1693 drmModeFreePropertyBlob(edid_blob);
1694}
1695
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001696
1697
1698static int
1699parse_modeline(const char *s, drmModeModeInfo *mode)
1700{
1701 char hsync[16];
1702 char vsync[16];
1703 float fclock;
1704
1705 mode->type = DRM_MODE_TYPE_USERDEF;
1706 mode->hskew = 0;
1707 mode->vscan = 0;
1708 mode->vrefresh = 0;
1709 mode->flags = 0;
1710
Rob Bradford307e09e2013-07-26 16:29:40 +01001711 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001712 &fclock,
1713 &mode->hdisplay,
1714 &mode->hsync_start,
1715 &mode->hsync_end,
1716 &mode->htotal,
1717 &mode->vdisplay,
1718 &mode->vsync_start,
1719 &mode->vsync_end,
1720 &mode->vtotal, hsync, vsync) != 11)
1721 return -1;
1722
1723 mode->clock = fclock * 1000;
1724 if (strcmp(hsync, "+hsync") == 0)
1725 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1726 else if (strcmp(hsync, "-hsync") == 0)
1727 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1728 else
1729 return -1;
1730
1731 if (strcmp(vsync, "+vsync") == 0)
1732 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1733 else if (strcmp(vsync, "-vsync") == 0)
1734 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1735 else
1736 return -1;
1737
1738 return 0;
1739}
1740
1741static uint32_t
1742parse_transform(const char *transform, const char *output_name)
1743{
1744 static const struct { const char *name; uint32_t token; } names[] = {
1745 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1746 { "90", WL_OUTPUT_TRANSFORM_90 },
1747 { "180", WL_OUTPUT_TRANSFORM_180 },
1748 { "270", WL_OUTPUT_TRANSFORM_270 },
1749 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1750 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1751 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1752 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1753 };
1754 unsigned int i;
1755
1756 for (i = 0; i < ARRAY_LENGTH(names); i++)
1757 if (strcmp(names[i].name, transform) == 0)
1758 return names[i].token;
1759
1760 weston_log("Invalid transform \"%s\" for output %s\n",
1761 transform, output_name);
1762
1763 return WL_OUTPUT_TRANSFORM_NORMAL;
1764}
1765
Rob Bradford66bd9f52013-06-25 18:56:42 +01001766static void
1767setup_output_seat_constraint(struct drm_compositor *ec,
1768 struct weston_output *output,
1769 const char *s)
1770{
1771 if (strcmp(s, "") != 0) {
1772 struct udev_seat *seat;
1773
1774 seat = udev_seat_get_named(&ec->base, s);
1775 if (seat)
1776 seat->base.output = output;
1777
1778 if (seat && seat->base.pointer)
1779 weston_pointer_clamp(seat->base.pointer,
1780 &seat->base.pointer->x,
1781 &seat->base.pointer->y);
1782 }
1783}
1784
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001785static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001786create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001787 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001788 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001789 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001790{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001791 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001792 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1793 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001794 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001795 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001796 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001797 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001798 int i, width, height, scale;
1799 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001800 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001801 enum output_config config;
1802 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001803
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001804 i = find_crtc_for_connector(ec, resources, connector);
1805 if (i < 0) {
1806 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001807 return -1;
1808 }
1809
Peter Huttererf3d62272013-08-08 11:57:05 +10001810 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001811 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001812 return -1;
1813
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001814 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1815 output->base.make = "unknown";
1816 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001817 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001818 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001819
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001820 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1821 type_name = connector_type_names[connector->connector_type];
1822 else
1823 type_name = "UNKNOWN";
1824 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001825 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001826
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001827 section = weston_config_get_section(ec->base.config, "output", "name",
1828 output->base.name);
1829 weston_config_section_get_string(section, "mode", &s, "preferred");
1830 if (strcmp(s, "off") == 0)
1831 config = OUTPUT_CONFIG_OFF;
1832 else if (strcmp(s, "preferred") == 0)
1833 config = OUTPUT_CONFIG_PREFERRED;
1834 else if (strcmp(s, "current") == 0)
1835 config = OUTPUT_CONFIG_CURRENT;
1836 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1837 config = OUTPUT_CONFIG_MODE;
1838 else if (parse_modeline(s, &modeline) == 0)
1839 config = OUTPUT_CONFIG_MODELINE;
1840 else {
1841 weston_log("Invalid mode \"%s\" for output %s\n",
1842 s, output->base.name);
1843 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001844 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001845 free(s);
1846
1847 weston_config_section_get_int(section, "scale", &scale, 1);
1848 weston_config_section_get_string(section, "transform", &s, "normal");
1849 transform = parse_transform(s, output->base.name);
1850 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001851
Rob Bradford66bd9f52013-06-25 18:56:42 +01001852 weston_config_section_get_string(section, "seat", &s, "");
1853 setup_output_seat_constraint(ec, &output->base, s);
1854 free(s);
1855
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001856 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001857 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001858 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001859 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001860 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001861
Matt Roper361d2ad2011-08-29 13:52:23 -07001862 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001863 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001864
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001865 /* Get the current mode on the crtc that's currently driving
1866 * this connector. */
1867 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001868 memset(&crtc_mode, 0, sizeof crtc_mode);
1869 if (encoder != NULL) {
1870 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1871 drmModeFreeEncoder(encoder);
1872 if (crtc == NULL)
1873 goto err_free;
1874 if (crtc->mode_valid)
1875 crtc_mode = crtc->mode;
1876 drmModeFreeCrtc(crtc);
1877 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001878
David Herrmann0f0d54e2011-12-08 17:05:45 +01001879 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001880 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001881 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001882 goto err_free;
1883 }
1884
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001885 if (config == OUTPUT_CONFIG_OFF) {
1886 weston_log("Disabling output %s\n", output->base.name);
1887 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1888 0, 0, 0, 0, 0, NULL);
1889 goto err_free;
1890 }
1891
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001892 preferred = NULL;
1893 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001894 configured = NULL;
1895
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001896 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001897 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001898 width == drm_mode->base.width &&
1899 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001900 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001901 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001902 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001903 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001904 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001905 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001906
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001907 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001908 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001909 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001910 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001911 }
1912
Wang Quanxianacb805a2012-07-30 18:09:46 -04001913 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001914 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001915 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001916 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001917 }
1918
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001919 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001920 configured = current;
1921
Wang Quanxianacb805a2012-07-30 18:09:46 -04001922 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001923 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001924 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001925 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001926 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001927 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001928 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001929 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001930
Hardeningff39efa2013-09-18 23:56:35 +02001931 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001932 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001933 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001934 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001935
Hardeningff39efa2013-09-18 23:56:35 +02001936 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001937
John Kåre Alsaker94659272012-11-13 19:10:18 +01001938 weston_output_init(&output->base, &ec->base, x, y,
1939 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001940 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001941
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001942 if (ec->use_pixman) {
1943 if (drm_output_init_pixman(output, ec) < 0) {
1944 weston_log("Failed to init output pixman state\n");
1945 goto err_output;
1946 }
1947 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001948 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001949 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001950 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001951
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001952 output->backlight = backlight_init(drm_device,
1953 connector->connector_type);
1954 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001955 weston_log("Initialized backlight, device %s\n",
1956 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001957 output->base.set_backlight = drm_set_backlight;
1958 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001959 } else {
1960 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001961 }
1962
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001963 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1964
Richard Hughes2b2092a2013-04-24 14:58:02 +01001965 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001966 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1967 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001968
Jonas Ådahle5a12252013-04-05 23:07:11 +02001969 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001970 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001971 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001972 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001973 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001974 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001975
Richard Hughese7299962013-05-01 21:52:12 +01001976 output->base.gamma_size = output->original_crtc->gamma_size;
1977 output->base.set_gamma = drm_output_set_gamma;
1978
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001979 weston_plane_init(&output->cursor_plane, 0, 0);
1980 weston_plane_init(&output->fb_plane, 0, 0);
1981
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001982 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1983 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1984 &ec->base.primary_plane);
1985
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001986 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001987 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001988 wl_list_for_each(m, &output->base.mode_list, link)
1989 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1990 m->width, m->height, m->refresh / 1000.0,
1991 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1992 ", preferred" : "",
1993 m->flags & WL_OUTPUT_MODE_CURRENT ?
1994 ", current" : "",
1995 connector->count_modes == 0 ?
1996 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001997
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001998 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001999
John Kåre Alsaker94659272012-11-13 19:10:18 +01002000err_output:
2001 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002002err_free:
2003 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2004 base.link) {
2005 wl_list_remove(&drm_mode->base.link);
2006 free(drm_mode);
2007 }
2008
2009 drmModeFreeCrtc(output->original_crtc);
2010 ec->crtc_allocator &= ~(1 << output->crtc_id);
2011 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002012 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002013
David Herrmann0f0d54e2011-12-08 17:05:45 +01002014 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002015}
2016
Jesse Barnes58ef3792012-02-23 09:45:49 -05002017static void
2018create_sprites(struct drm_compositor *ec)
2019{
2020 struct drm_sprite *sprite;
2021 drmModePlaneRes *plane_res;
2022 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002023 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002024
2025 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2026 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002027 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002028 strerror(errno));
2029 return;
2030 }
2031
2032 for (i = 0; i < plane_res->count_planes; i++) {
2033 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2034 if (!plane)
2035 continue;
2036
Peter Huttererf3d62272013-08-08 11:57:05 +10002037 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002038 plane->count_formats));
2039 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002040 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002041 __func__);
2042 free(plane);
2043 continue;
2044 }
2045
Jesse Barnes58ef3792012-02-23 09:45:49 -05002046 sprite->possible_crtcs = plane->possible_crtcs;
2047 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002048 sprite->current = NULL;
2049 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002050 sprite->compositor = ec;
2051 sprite->count_formats = plane->count_formats;
2052 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002053 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002054 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002055 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002056 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2057 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002058
2059 wl_list_insert(&ec->sprite_list, &sprite->link);
2060 }
2061
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002062 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002063}
2064
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002065static void
2066destroy_sprites(struct drm_compositor *compositor)
2067{
2068 struct drm_sprite *sprite, *next;
2069 struct drm_output *output;
2070
2071 output = container_of(compositor->base.output_list.next,
2072 struct drm_output, base.link);
2073
2074 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2075 drmModeSetPlane(compositor->drm.fd,
2076 sprite->plane_id,
2077 output->crtc_id, 0, 0,
2078 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002079 drm_output_release_fb(output, sprite->current);
2080 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002081 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002082 free(sprite);
2083 }
2084}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002085
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002086static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002087create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002088 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002089{
2090 drmModeConnector *connector;
2091 drmModeRes *resources;
2092 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002093 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002094
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002095 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002096 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002097 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002098 return -1;
2099 }
2100
Jesse Barnes58ef3792012-02-23 09:45:49 -05002101 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002102 if (!ec->crtcs) {
2103 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002104 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002105 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002106
Rob Clark4339add2012-08-09 14:18:28 -05002107 ec->min_width = resources->min_width;
2108 ec->max_width = resources->max_width;
2109 ec->min_height = resources->min_height;
2110 ec->max_height = resources->max_height;
2111
Jesse Barnes58ef3792012-02-23 09:45:49 -05002112 ec->num_crtcs = resources->count_crtcs;
2113 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2114
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002115 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002116 connector = drmModeGetConnector(ec->drm.fd,
2117 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002118 if (connector == NULL)
2119 continue;
2120
2121 if (connector->connection == DRM_MODE_CONNECTED &&
2122 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002123 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002124 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002125 connector, x, y,
2126 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002127 drmModeFreeConnector(connector);
2128 continue;
2129 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002130
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002131 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002132 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002133 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002134 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002135
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002136 drmModeFreeConnector(connector);
2137 }
2138
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002139 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002140 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002141 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002142 return -1;
2143 }
2144
2145 drmModeFreeResources(resources);
2146
2147 return 0;
2148}
2149
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002150static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002151update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002152{
2153 drmModeConnector *connector;
2154 drmModeRes *resources;
2155 struct drm_output *output, *next;
2156 int x = 0, y = 0;
2157 int x_offset = 0, y_offset = 0;
2158 uint32_t connected = 0, disconnects = 0;
2159 int i;
2160
2161 resources = drmModeGetResources(ec->drm.fd);
2162 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002163 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002164 return;
2165 }
2166
2167 /* collect new connects */
2168 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002169 int connector_id = resources->connectors[i];
2170
2171 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002172 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002173 continue;
2174
David Herrmann7551cff2011-12-08 17:05:43 +01002175 if (connector->connection != DRM_MODE_CONNECTED) {
2176 drmModeFreeConnector(connector);
2177 continue;
2178 }
2179
Benjamin Franzke117483d2011-08-30 11:38:26 +02002180 connected |= (1 << connector_id);
2181
2182 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002183 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002184 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002185 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002186
2187 /* XXX: not yet needed, we die with 0 outputs */
2188 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002189 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002190 else
2191 x = 0;
2192 y = 0;
2193 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002194 connector, x, y,
2195 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002196 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002197
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002198 }
2199 drmModeFreeConnector(connector);
2200 }
2201 drmModeFreeResources(resources);
2202
2203 disconnects = ec->connector_allocator & ~connected;
2204 if (disconnects) {
2205 wl_list_for_each_safe(output, next, &ec->base.output_list,
2206 base.link) {
2207 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002208 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002209 output->base.x - x_offset,
2210 output->base.y - y_offset);
2211 }
2212
2213 if (disconnects & (1 << output->connector_id)) {
2214 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002215 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002216 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002217 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002218 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002219 }
2220 }
2221 }
2222
2223 /* FIXME: handle zero outputs, without terminating */
2224 if (ec->connector_allocator == 0)
2225 wl_display_terminate(ec->base.wl_display);
2226}
2227
2228static int
David Herrmannd7488c22012-03-11 20:05:21 +01002229udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002230{
David Herrmannd7488c22012-03-11 20:05:21 +01002231 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002232 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002233
2234 sysnum = udev_device_get_sysnum(device);
2235 if (!sysnum || atoi(sysnum) != ec->drm.id)
2236 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002237
David Herrmann6ac52db2012-03-11 20:05:22 +01002238 val = udev_device_get_property_value(device, "HOTPLUG");
2239 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002240 return 0;
2241
David Herrmann6ac52db2012-03-11 20:05:22 +01002242 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002243}
2244
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002245static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002246udev_drm_event(int fd, uint32_t mask, void *data)
2247{
2248 struct drm_compositor *ec = data;
2249 struct udev_device *event;
2250
2251 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002252
David Herrmannd7488c22012-03-11 20:05:21 +01002253 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002254 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002255
2256 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002257
2258 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002259}
2260
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002261static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002262drm_restore(struct weston_compositor *ec)
2263{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002264 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002265}
2266
2267static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002268drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002269{
2270 struct drm_compositor *d = (struct drm_compositor *) ec;
2271
Rob Bradfordd355b802013-05-31 18:09:55 +01002272 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002273
2274 wl_event_source_remove(d->udev_drm_source);
2275 wl_event_source_remove(d->drm_source);
2276
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002277 destroy_sprites(d);
2278
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002279 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002280
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002281 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002282
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002283 if (d->gbm)
2284 gbm_device_destroy(d->gbm);
2285
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002286 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002287
Rob Bradford45c15b82013-07-26 16:29:35 +01002288 close(d->drm.fd);
2289
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002290 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002291}
2292
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002293static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002294drm_compositor_set_modes(struct drm_compositor *compositor)
2295{
2296 struct drm_output *output;
2297 struct drm_mode *drm_mode;
2298 int ret;
2299
2300 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002301 if (!output->current) {
2302 /* If something that would cause the output to
2303 * switch mode happened while in another vt, we
2304 * might not have a current drm_fb. In that case,
2305 * schedule a repaint and let drm_output_repaint
2306 * handle setting the mode. */
2307 weston_output_schedule_repaint(&output->base);
2308 continue;
2309 }
2310
Hardeningff39efa2013-09-18 23:56:35 +02002311 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002312 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002313 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002314 &output->connector_id, 1,
2315 &drm_mode->mode_info);
2316 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002317 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002318 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002319 drm_mode->base.width, drm_mode->base.height,
2320 output->base.x, output->base.y);
2321 }
2322 }
2323}
2324
2325static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002326session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002327{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002328 struct weston_compositor *compositor = data;
2329 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002330 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002331 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002332
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002333 if (ec->base.session_active) {
2334 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002335 compositor->focus = 1;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002336 if (ec->base.launcher == NULL && drmSetMaster(ec->drm.fd)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002337 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002338 wl_display_terminate(compositor->wl_display);
2339 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002340 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002341 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002342 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002343 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002344 } else {
2345 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002346 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002347
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002348 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002349 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002350 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002351
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002352 /* If we have a repaint scheduled (either from a
2353 * pending pageflip or the idle handler), make sure we
2354 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002355 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002356 * further attemps at repainting. When we switch
2357 * back, we schedule a repaint, which will process
2358 * pending frame callbacks. */
2359
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002360 wl_list_for_each(output, &ec->base.output_list, base.link) {
2361 output->base.repaint_needed = 0;
2362 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002363 }
2364
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002365 output = container_of(ec->base.output_list.next,
2366 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002367
2368 wl_list_for_each(sprite, &ec->sprite_list, link)
2369 drmModeSetPlane(ec->drm.fd,
2370 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002371 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002372 0, 0, 0, 0, 0, 0, 0, 0);
2373
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002374 if (ec->base.launcher == NULL && drmDropMaster(ec->drm.fd) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002375 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002376 };
2377}
2378
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002379static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002380switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002381{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002382 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002383
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002384 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002385}
2386
David Herrmann0af066f2012-10-29 19:21:16 +01002387/*
2388 * Find primary GPU
2389 * Some systems may have multiple DRM devices attached to a single seat. This
2390 * function loops over all devices and tries to find a PCI device with the
2391 * boot_vga sysfs attribute set to 1.
2392 * If no such device is found, the first DRM device reported by udev is used.
2393 */
2394static struct udev_device*
2395find_primary_gpu(struct drm_compositor *ec, const char *seat)
2396{
2397 struct udev_enumerate *e;
2398 struct udev_list_entry *entry;
2399 const char *path, *device_seat, *id;
2400 struct udev_device *device, *drm_device, *pci;
2401
2402 e = udev_enumerate_new(ec->udev);
2403 udev_enumerate_add_match_subsystem(e, "drm");
2404 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2405
2406 udev_enumerate_scan_devices(e);
2407 drm_device = NULL;
2408 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2409 path = udev_list_entry_get_name(entry);
2410 device = udev_device_new_from_syspath(ec->udev, path);
2411 if (!device)
2412 continue;
2413 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2414 if (!device_seat)
2415 device_seat = default_seat;
2416 if (strcmp(device_seat, seat)) {
2417 udev_device_unref(device);
2418 continue;
2419 }
2420
2421 pci = udev_device_get_parent_with_subsystem_devtype(device,
2422 "pci", NULL);
2423 if (pci) {
2424 id = udev_device_get_sysattr_value(pci, "boot_vga");
2425 if (id && !strcmp(id, "1")) {
2426 if (drm_device)
2427 udev_device_unref(drm_device);
2428 drm_device = device;
2429 break;
2430 }
2431 }
2432
2433 if (!drm_device)
2434 drm_device = device;
2435 else
2436 udev_device_unref(device);
2437 }
2438
2439 udev_enumerate_unref(e);
2440 return drm_device;
2441}
2442
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002443static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002444planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002445{
2446 struct drm_compositor *c = data;
2447
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002448 switch (key) {
2449 case KEY_C:
2450 c->cursors_are_broken ^= 1;
2451 break;
2452 case KEY_V:
2453 c->sprites_are_broken ^= 1;
2454 break;
2455 case KEY_O:
2456 c->sprites_hidden ^= 1;
2457 break;
2458 default:
2459 break;
2460 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002461}
2462
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002463#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002464static void
2465recorder_frame_notify(struct wl_listener *listener, void *data)
2466{
2467 struct drm_output *output;
2468 struct drm_compositor *c;
2469 int fd, ret;
2470
2471 output = container_of(listener, struct drm_output,
2472 recorder_frame_listener);
2473 c = (struct drm_compositor *) output->base.compositor;
2474
2475 if (!output->recorder)
2476 return;
2477
2478 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2479 DRM_CLOEXEC, &fd);
2480 if (ret) {
2481 weston_log("[libva recorder] "
2482 "failed to create prime fd for front buffer\n");
2483 return;
2484 }
2485
2486 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002487}
2488
2489static void *
2490create_recorder(struct drm_compositor *c, int width, int height,
2491 const char *filename)
2492{
2493 int fd;
2494 drm_magic_t magic;
2495
2496 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2497 if (fd < 0)
2498 return NULL;
2499
2500 drmGetMagic(fd, &magic);
2501 drmAuthMagic(c->drm.fd, magic);
2502
2503 return vaapi_recorder_create(fd, width, height, filename);
2504}
2505
2506static void
2507recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2508 void *data)
2509{
2510 struct drm_compositor *c = data;
2511 struct drm_output *output;
2512 int width, height;
2513
2514 output = container_of(c->base.output_list.next,
2515 struct drm_output, base.link);
2516
2517 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002518 width = output->base.current_mode->width;
2519 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002520
2521 output->recorder =
2522 create_recorder(c, width, height, "capture.h264");
2523 if (!output->recorder) {
2524 weston_log("failed to create vaapi recorder\n");
2525 return;
2526 }
2527
2528 output->base.disable_planes++;
2529
2530 output->recorder_frame_listener.notify = recorder_frame_notify;
2531 wl_signal_add(&output->base.frame_signal,
2532 &output->recorder_frame_listener);
2533
2534 weston_output_schedule_repaint(&output->base);
2535
2536 weston_log("[libva recorder] initialized\n");
2537 } else {
2538 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002539 output->recorder = NULL;
2540
2541 output->base.disable_planes--;
2542
2543 wl_list_remove(&output->recorder_frame_listener.link);
2544 weston_log("[libva recorder] done\n");
2545 }
2546}
2547#else
2548static void
2549recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2550 void *data)
2551{
2552 weston_log("Compiled without libva support\n");
2553}
2554#endif
2555
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002556static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002557drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002558 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002559 int *argc, char *argv[],
2560 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002561{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002562 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002563 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002564 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002565 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002566 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002567
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002568 weston_log("initializing drm backend\n");
2569
Peter Huttererf3d62272013-08-08 11:57:05 +10002570 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002571 if (ec == NULL)
2572 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002573
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002574 /* KMS support for sprites is not complete yet, so disable the
2575 * functionality for now. */
2576 ec->sprites_are_broken = 1;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07002577 ec->format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002578 ec->use_pixman = pixman;
2579
Daniel Stone725c2c32012-06-22 14:04:36 +01002580 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002581 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002582 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002583 goto err_base;
2584 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002585
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002586 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg6ff3ff52013-10-02 10:53:33 -07002587 ec->base.launcher = weston_launcher_connect(&ec->base, tty);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002588 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002589 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002590 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002591 goto err_compositor;
2592 }
2593
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002594 ec->udev = udev_new();
2595 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002596 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002597 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002598 }
2599
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002600 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002601 ec->session_listener.notify = session_notify;
2602 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002603
Rob Bradford643641d2013-05-31 18:09:53 +01002604 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002605 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002606 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002607 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002608 }
David Herrmann0af066f2012-10-29 19:21:16 +01002609 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002610
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002611 if (init_drm(ec, drm_device) < 0) {
2612 weston_log("failed to initialize kms\n");
2613 goto err_udev_dev;
2614 }
2615
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002616 if (ec->use_pixman) {
2617 if (init_pixman(ec) < 0) {
2618 weston_log("failed to initialize pixman renderer\n");
2619 goto err_udev_dev;
2620 }
2621 } else {
2622 if (init_egl(ec) < 0) {
2623 weston_log("failed to initialize egl\n");
2624 goto err_udev_dev;
2625 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002626 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002627
2628 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002629 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002630
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002631 ec->base.focus = 1;
2632
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002633 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002634
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002635 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002636 weston_compositor_add_key_binding(&ec->base, key,
2637 MODIFIER_CTRL | MODIFIER_ALT,
2638 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002639
Jesse Barnes58ef3792012-02-23 09:45:49 -05002640 wl_list_init(&ec->sprite_list);
2641 create_sprites(ec);
2642
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002643 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002644 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002645 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002646 }
2647
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002648 path = NULL;
2649
Rob Bradfordd355b802013-05-31 18:09:55 +01002650 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002651 weston_log("failed to create input devices\n");
2652 goto err_sprite;
2653 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002654
2655 loop = wl_display_get_event_loop(ec->base.wl_display);
2656 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002657 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002658 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002659
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002660 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2661 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002662 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002663 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002664 }
2665 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2666 "drm", NULL);
2667 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002668 wl_event_loop_add_fd(loop,
2669 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002670 WL_EVENT_READABLE, udev_drm_event, ec);
2671
2672 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002673 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002674 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002675 }
2676
Daniel Stonea96b93c2012-06-22 14:04:37 +01002677 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002678
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002679 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002680 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002681 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002682 planes_binding, ec);
2683 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2684 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002685 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2686 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002687
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002688 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002689
2690err_udev_monitor:
2691 wl_event_source_remove(ec->udev_drm_source);
2692 udev_monitor_unref(ec->udev_monitor);
2693err_drm_source:
2694 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002695 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002696err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002697 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002698 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002699 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002700err_udev_dev:
2701 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002702err_launcher:
2703 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002704err_udev:
2705 udev_unref(ec->udev);
2706err_compositor:
2707 weston_compositor_shutdown(&ec->base);
2708err_base:
2709 free(ec);
2710 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002711}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002712
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002713WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002714backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002715 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002716{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002717 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002718 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002719
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002720 const struct weston_option drm_options[] = {
2721 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002722 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002723 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002724 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002725 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002726 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002727
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002728 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002729
Rob Bradford643641d2013-05-31 18:09:53 +01002730 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002731 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002732}