blob: 0ac5efac2b300740e511c6131c2a68978b321a32 [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;
152
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400153 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400154 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400155 struct weston_plane cursor_plane;
156 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400157 struct weston_surface *cursor_surface;
158 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300159 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200160 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200161
162 struct drm_fb *dumb[2];
163 pixman_image_t *image[2];
164 int current_image;
165 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300166
167 struct vaapi_recorder *recorder;
168 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400169};
170
Jesse Barnes58ef3792012-02-23 09:45:49 -0500171/*
172 * An output has a primary display plane plus zero or more sprites for
173 * blending display contents.
174 */
175struct drm_sprite {
176 struct wl_list link;
177
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400178 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500179
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200180 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300181 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500182 struct drm_compositor *compositor;
183
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184 uint32_t possible_crtcs;
185 uint32_t plane_id;
186 uint32_t count_formats;
187
188 int32_t src_x, src_y;
189 uint32_t src_w, src_h;
190 uint32_t dest_x, dest_y;
191 uint32_t dest_w, dest_h;
192
193 uint32_t formats[];
194};
195
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500196static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400197
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400198static void
199drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400200
Jesse Barnes58ef3792012-02-23 09:45:49 -0500201static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500202drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
203{
204 struct weston_compositor *ec = output_base->compositor;
205 struct drm_compositor *c =(struct drm_compositor *) ec;
206 struct drm_output *output = (struct drm_output *) output_base;
207 int crtc;
208
209 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
210 if (c->crtcs[crtc] != output->crtc_id)
211 continue;
212
213 if (supported & (1 << crtc))
214 return -1;
215 }
216
217 return 0;
218}
219
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300220static void
221drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
222{
223 struct drm_fb *fb = data;
224 struct gbm_device *gbm = gbm_bo_get_device(bo);
225
226 if (fb->fb_id)
227 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
228
Pekka Paalanende685b82012-12-04 15:58:12 +0200229 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300230
231 free(data);
232}
233
234static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200235drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
236{
237 struct drm_fb *fb;
238 int ret;
239
240 struct drm_mode_create_dumb create_arg;
241 struct drm_mode_destroy_dumb destroy_arg;
242 struct drm_mode_map_dumb map_arg;
243
Peter Huttererf3d62272013-08-08 11:57:05 +1000244 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200245 if (!fb)
246 return NULL;
247
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700248 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200249 create_arg.bpp = 32;
250 create_arg.width = width;
251 create_arg.height = height;
252
253 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
254 if (ret)
255 goto err_fb;
256
257 fb->handle = create_arg.handle;
258 fb->stride = create_arg.pitch;
259 fb->size = create_arg.size;
260 fb->fd = ec->drm.fd;
261
262 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
263 fb->stride, fb->handle, &fb->fb_id);
264 if (ret)
265 goto err_bo;
266
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700267 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200268 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400269 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200270 if (ret)
271 goto err_add_fb;
272
273 fb->map = mmap(0, fb->size, PROT_WRITE,
274 MAP_SHARED, ec->drm.fd, map_arg.offset);
275 if (fb->map == MAP_FAILED)
276 goto err_add_fb;
277
278 return fb;
279
280err_add_fb:
281 drmModeRmFB(ec->drm.fd, fb->fb_id);
282err_bo:
283 memset(&destroy_arg, 0, sizeof(destroy_arg));
284 destroy_arg.handle = create_arg.handle;
285 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
286err_fb:
287 free(fb);
288 return NULL;
289}
290
291static void
292drm_fb_destroy_dumb(struct drm_fb *fb)
293{
294 struct drm_mode_destroy_dumb destroy_arg;
295
296 if (!fb->map)
297 return;
298
299 if (fb->fb_id)
300 drmModeRmFB(fb->fd, fb->fb_id);
301
302 weston_buffer_reference(&fb->buffer_ref, NULL);
303
304 munmap(fb->map, fb->size);
305
306 memset(&destroy_arg, 0, sizeof(destroy_arg));
307 destroy_arg.handle = fb->handle;
308 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
309
310 free(fb);
311}
312
313static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500314drm_fb_get_from_bo(struct gbm_bo *bo,
315 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300316{
317 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200318 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200319 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300320 int ret;
321
322 if (fb)
323 return fb;
324
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200325 fb = calloc(1, sizeof *fb);
326 if (!fb)
327 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300328
329 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300330
331 width = gbm_bo_get_width(bo);
332 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200333 fb->stride = gbm_bo_get_stride(bo);
334 fb->handle = gbm_bo_get_handle(bo).u32;
335 fb->size = fb->stride * height;
336 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300337
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200338 if (compositor->min_width > width || width > compositor->max_width ||
339 compositor->min_height > height ||
340 height > compositor->max_height) {
341 weston_log("bo geometry out of bounds\n");
342 goto err_free;
343 }
344
345 ret = -1;
346
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200347 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200348 handles[0] = fb->handle;
349 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200350 offsets[0] = 0;
351
352 ret = drmModeAddFB2(compositor->drm.fd, width, height,
353 format, handles, pitches, offsets,
354 &fb->fb_id, 0);
355 if (ret) {
356 weston_log("addfb2 failed: %m\n");
357 compositor->no_addfb2 = 1;
358 compositor->sprites_are_broken = 1;
359 }
360 }
361
362 if (ret)
363 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200364 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200365
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300366 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200367 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200368 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300369 }
370
371 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
372
373 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200374
375err_free:
376 free(fb);
377 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300378}
379
380static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500381drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200382{
Pekka Paalanende685b82012-12-04 15:58:12 +0200383 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200384
385 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200386
Pekka Paalanende685b82012-12-04 15:58:12 +0200387 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200388}
389
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200390static void
391drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
392{
393 if (!fb)
394 return;
395
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200396 if (fb->map &&
397 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200398 drm_fb_destroy_dumb(fb);
399 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200400 if (fb->is_client_buffer)
401 gbm_bo_destroy(fb->bo);
402 else
403 gbm_surface_release_buffer(output->surface,
404 output->current->bo);
405 }
406}
407
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500408static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200409drm_output_check_scanout_format(struct drm_output *output,
410 struct weston_surface *es, struct gbm_bo *bo)
411{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200412 uint32_t format;
413 pixman_region32_t r;
414
415 format = gbm_bo_get_format(bo);
416
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500417 switch (format) {
418 case GBM_FORMAT_XRGB8888:
419 return format;
420 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200421 /* We can only scanout an ARGB buffer if the surface's
422 * opaque region covers the whole output */
423 pixman_region32_init(&r);
424 pixman_region32_subtract(&r, &output->base.region,
425 &es->opaque);
426
427 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500428 format = GBM_FORMAT_XRGB8888;
429 else
430 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200431
432 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200433
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500434 return format;
435 default:
436 return 0;
437 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200438}
439
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400440static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400441drm_output_prepare_scanout_surface(struct weston_output *_output,
442 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500443{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400444 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500445 struct drm_compositor *c =
446 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500447 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300448 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500449 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500450
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500451 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200452 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200453 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200454 buffer->width != output->base.current_mode->width ||
455 buffer->height != output->base.current_mode->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200456 output->base.transform != es->buffer_transform ||
457 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400458 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500459
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400460 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700461 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500462
Rob Bradford9b101872012-09-14 23:25:41 +0100463 /* Unable to use the buffer for scanout */
464 if (!bo)
465 return NULL;
466
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500467 format = drm_output_check_scanout_format(output, es, bo);
468 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300469 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400470 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300471 }
472
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500473 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300474 if (!output->next) {
475 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400476 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300477 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500478
Pekka Paalanende685b82012-12-04 15:58:12 +0200479 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500480
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400481 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500482}
483
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500484static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200485drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400486{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200487 struct drm_compositor *c =
488 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300489 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400490
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200491 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400492
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300493 bo = gbm_surface_lock_front_buffer(output->surface);
494 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200495 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400496 return;
497 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300498
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700499 output->next = drm_fb_get_from_bo(bo, c, c->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300500 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200501 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300502 gbm_surface_release_buffer(output->surface, bo);
503 return;
504 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400505}
506
507static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200508drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
509{
510 struct weston_compositor *ec = output->base.compositor;
511 pixman_region32_t total_damage, previous_damage;
512
513 pixman_region32_init(&total_damage);
514 pixman_region32_init(&previous_damage);
515
516 pixman_region32_copy(&previous_damage, damage);
517
518 pixman_region32_union(&total_damage, damage, &output->previous_damage);
519 pixman_region32_copy(&output->previous_damage, &previous_damage);
520
521 output->current_image ^= 1;
522
523 output->next = output->dumb[output->current_image];
524 pixman_renderer_output_set_buffer(&output->base,
525 output->image[output->current_image]);
526
527 ec->renderer->repaint_output(&output->base, &total_damage);
528
529 pixman_region32_fini(&total_damage);
530 pixman_region32_fini(&previous_damage);
531}
532
533static void
534drm_output_render(struct drm_output *output, pixman_region32_t *damage)
535{
536 struct drm_compositor *c =
537 (struct drm_compositor *) output->base.compositor;
538
539 if (c->use_pixman)
540 drm_output_render_pixman(output, damage);
541 else
542 drm_output_render_gl(output, damage);
543
544 pixman_region32_subtract(&c->base.primary_plane.damage,
545 &c->base.primary_plane.damage, damage);
546}
547
548static void
Richard Hughese7299962013-05-01 21:52:12 +0100549drm_output_set_gamma(struct weston_output *output_base,
550 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
551{
552 int rc;
553 struct drm_output *output = (struct drm_output *) output_base;
554 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
555
556 /* check */
557 if (output_base->gamma_size != size)
558 return;
559 if (!output->original_crtc)
560 return;
561
562 rc = drmModeCrtcSetGamma(compositor->drm.fd,
563 output->crtc_id,
564 size, r, g, b);
565 if (rc)
566 weston_log("set gamma failed: %m\n");
567}
568
569static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500570drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400571 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100572{
573 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500574 struct drm_compositor *compositor =
575 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500576 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400577 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500578 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100579
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300580 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400581 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300582 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400583 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100584
Hardeningff39efa2013-09-18 23:56:35 +0200585 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300586 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400587 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300588 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400589 &output->connector_id, 1,
590 &mode->mode_info);
591 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200592 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400593 return;
594 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300595 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200596 }
597
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500598 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300599 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500600 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200601 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500602 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500603 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100604
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300605 output->page_flip_pending = 1;
606
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400607 drm_output_set_cursor(output);
608
Jesse Barnes58ef3792012-02-23 09:45:49 -0500609 /*
610 * Now, update all the sprite surfaces
611 */
612 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200613 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500614 drmVBlank vbl = {
615 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
616 .request.sequence = 1,
617 };
618
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200619 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200620 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 continue;
622
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200623 if (s->next && !compositor->sprites_hidden)
624 fb_id = s->next->fb_id;
625
Jesse Barnes58ef3792012-02-23 09:45:49 -0500626 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200627 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628 s->dest_x, s->dest_y,
629 s->dest_w, s->dest_h,
630 s->src_x, s->src_y,
631 s->src_w, s->src_h);
632 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200633 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 ret, strerror(errno));
635
Rob Clark5ca1a472012-08-08 20:27:37 -0500636 if (output->pipe > 0)
637 vbl.request.type |= DRM_VBLANK_SECONDARY;
638
Jesse Barnes58ef3792012-02-23 09:45:49 -0500639 /*
640 * Queue a vblank signal so we know when the surface
641 * becomes active on the display or has been replaced.
642 */
643 vbl.request.signal = (unsigned long)s;
644 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
645 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200646 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500647 ret, strerror(errno));
648 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300649
650 s->output = output;
651 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500652 }
653
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500654 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400655}
656
657static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200658drm_output_start_repaint_loop(struct weston_output *output_base)
659{
660 struct drm_output *output = (struct drm_output *) output_base;
661 struct drm_compositor *compositor = (struct drm_compositor *)
662 output_base->compositor;
663 uint32_t fb_id;
664
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300665 struct timespec ts;
666
667 if (!output->current) {
668 /* We can't page flip if there's no mode set */
669 uint32_t msec;
670
671 clock_gettime(compositor->clock, &ts);
672 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
673 weston_output_finish_frame(output_base, msec);
674 return;
675 }
676
677 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200678
679 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
680 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
681 weston_log("queueing pageflip failed: %m\n");
682 return;
683 }
684}
685
686static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500687vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
688 void *data)
689{
690 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300691 struct drm_output *output = s->output;
692 uint32_t msecs;
693
694 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500695
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200696 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200697 s->current = s->next;
698 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300699
700 if (!output->page_flip_pending) {
701 msecs = sec * 1000 + usec / 1000;
702 weston_output_finish_frame(&output->base, msecs);
703 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500704}
705
706static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400707page_flip_handler(int fd, unsigned int frame,
708 unsigned int sec, unsigned int usec, void *data)
709{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200710 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400711 uint32_t msecs;
712
Jonas Ådahle5a12252013-04-05 23:07:11 +0200713 /* We don't set page_flip_pending on start_repaint_loop, in that case
714 * we just want to page flip to the current buffer to get an accurate
715 * timestamp */
716 if (output->page_flip_pending) {
717 drm_output_release_fb(output, output->current);
718 output->current = output->next;
719 output->next = NULL;
720 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300721
Jonas Ådahle5a12252013-04-05 23:07:11 +0200722 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400723
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300724 if (!output->vblank_pending) {
725 msecs = sec * 1000 + usec / 1000;
726 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300727
728 /* We can't call this from frame_notify, because the output's
729 * repaint needed flag is cleared just after that */
730 if (output->recorder)
731 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300732 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200733}
734
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500735static uint32_t
736drm_output_check_sprite_format(struct drm_sprite *s,
737 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500738{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500739 uint32_t i, format;
740
741 format = gbm_bo_get_format(bo);
742
743 if (format == GBM_FORMAT_ARGB8888) {
744 pixman_region32_t r;
745
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500746 pixman_region32_init_rect(&r, 0, 0,
747 es->geometry.width,
748 es->geometry.height);
749 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500750
751 if (!pixman_region32_not_empty(&r))
752 format = GBM_FORMAT_XRGB8888;
753
754 pixman_region32_fini(&r);
755 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500756
757 for (i = 0; i < s->count_formats; i++)
758 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500759 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500760
761 return 0;
762}
763
764static int
765drm_surface_transform_supported(struct weston_surface *es)
766{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500767 return !es->transform.enabled ||
768 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500769}
770
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400771static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500772drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400773 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500774{
775 struct weston_compositor *ec = output_base->compositor;
776 struct drm_compositor *c =(struct drm_compositor *) ec;
777 struct drm_sprite *s;
778 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500779 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500780 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200781 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500782 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400783 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500784
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200785 if (c->gbm == NULL)
786 return NULL;
787
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200788 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200789 return NULL;
790
Hardeningff39efa2013-09-18 23:56:35 +0200791 if (es->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200792 return NULL;
793
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500794 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400795 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500796
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300797 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400798 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300799
Pekka Paalanende685b82012-12-04 15:58:12 +0200800 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400801 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500802
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200803 if (es->alpha != 1.0f)
804 return NULL;
805
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500806 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500807 return NULL;
808
Jesse Barnes58ef3792012-02-23 09:45:49 -0500809 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500811
Jesse Barnes58ef3792012-02-23 09:45:49 -0500812 wl_list_for_each(s, &c->sprite_list, link) {
813 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
814 continue;
815
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200816 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817 found = 1;
818 break;
819 }
820 }
821
822 /* No sprites available */
823 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400824 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500825
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400826 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700827 es->buffer_ref.buffer->resource,
828 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400829 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400830 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400831
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500832 format = drm_output_check_sprite_format(s, es, bo);
833 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200834 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400835 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500836 }
837
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200838 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200839 if (!s->next) {
840 gbm_bo_destroy(bo);
841 return NULL;
842 }
843
Pekka Paalanende685b82012-12-04 15:58:12 +0200844 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500845
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400846 box = pixman_region32_extents(&es->transform.boundingbox);
847 s->plane.x = box->x1;
848 s->plane.y = box->y1;
849
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 /*
851 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200852 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500853 * for us already).
854 */
855 pixman_region32_init(&dest_rect);
856 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
857 &output_base->region);
858 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
859 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200860 tbox = weston_transformed_rect(output_base->width,
861 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200862 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200863 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200864 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200865 s->dest_x = tbox.x1;
866 s->dest_y = tbox.y1;
867 s->dest_w = tbox.x2 - tbox.x1;
868 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500869 pixman_region32_fini(&dest_rect);
870
871 pixman_region32_init(&src_rect);
872 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
873 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500874 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400875
876 weston_surface_from_global_fixed(es,
877 wl_fixed_from_int(box->x1),
878 wl_fixed_from_int(box->y1),
879 &sx1, &sy1);
880 weston_surface_from_global_fixed(es,
881 wl_fixed_from_int(box->x2),
882 wl_fixed_from_int(box->y2),
883 &sx2, &sy2);
884
885 if (sx1 < 0)
886 sx1 = 0;
887 if (sy1 < 0)
888 sy1 = 0;
889 if (sx2 > wl_fixed_from_int(es->geometry.width))
890 sx2 = wl_fixed_from_int(es->geometry.width);
891 if (sy2 > wl_fixed_from_int(es->geometry.height))
892 sy2 = wl_fixed_from_int(es->geometry.height);
893
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200894 tbox.x1 = sx1;
895 tbox.y1 = sy1;
896 tbox.x2 = sx2;
897 tbox.y2 = sy2;
898
899 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
900 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200901 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200902
903 s->src_x = tbox.x1 << 8;
904 s->src_y = tbox.y1 << 8;
905 s->src_w = (tbox.x2 - tbox.x1) << 8;
906 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500907 pixman_region32_fini(&src_rect);
908
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400909 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500910}
911
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400912static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400913drm_output_prepare_cursor_surface(struct weston_output *output_base,
914 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500915{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400916 struct drm_compositor *c =
917 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400918 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400919
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200920 if (c->gbm == NULL)
921 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200922 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
923 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400924 if (output->cursor_surface)
925 return NULL;
926 if (es->output_mask != (1u << output_base->id))
927 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500928 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400929 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200930 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500931 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400932 es->geometry.width > 64 || es->geometry.height > 64)
933 return NULL;
934
935 output->cursor_surface = es;
936
937 return &output->cursor_plane;
938}
939
940static void
941drm_output_set_cursor(struct drm_output *output)
942{
943 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400944 struct drm_compositor *c =
945 (struct drm_compositor *) output->base.compositor;
946 EGLint handle, stride;
947 struct gbm_bo *bo;
948 uint32_t buf[64 * 64];
949 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400950 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500951
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400952 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400953 if (es == NULL) {
954 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
955 return;
956 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500957
Pekka Paalanende685b82012-12-04 15:58:12 +0200958 if (es->buffer_ref.buffer &&
959 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400960 pixman_region32_fini(&output->cursor_plane.damage);
961 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400962 output->current_cursor ^= 1;
963 bo = output->cursor_bo[output->current_cursor];
964 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500965 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
966 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400967 for (i = 0; i < es->geometry.height; i++)
968 memcpy(buf + i * 64, s + i * stride,
969 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500970
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400971 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300972 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400973
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400974 handle = gbm_bo_get_handle(bo).s32;
975 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500976 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300977 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500978 c->cursors_are_broken = 1;
979 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400980 }
981
Hardeningff39efa2013-09-18 23:56:35 +0200982 x = (es->geometry.x - output->base.x) * output->base.current_scale;
983 y = (es->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400984 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500985 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400986 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500987 c->cursors_are_broken = 1;
988 }
989
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400990 output->cursor_plane.x = x;
991 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400992 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500993}
994
Jesse Barnes58ef3792012-02-23 09:45:49 -0500995static void
996drm_assign_planes(struct weston_output *output)
997{
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400998 struct drm_compositor *c =
999 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001000 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001001 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001002 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001003
1004 /*
1005 * Find a surface for each sprite in the output using some heuristics:
1006 * 1) size
1007 * 2) frequency of update
1008 * 3) opacity (though some hw might support alpha blending)
1009 * 4) clipping (this can be fixed with color keys)
1010 *
1011 * The idea is to save on blitting since this should save power.
1012 * If we can get a large video surface on the sprite for example,
1013 * the main display surface may not need to update at all, and
1014 * the client buffer can be used directly for the sprite surface
1015 * as we do for flipping full screen surfaces.
1016 */
1017 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001018 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001019 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001020 /* test whether this buffer can ever go into a plane:
1021 * non-shm, or small enough to be a cursor
1022 */
1023 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001024 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001025 (es->geometry.width <= 64 && es->geometry.height <= 64))
1026 es->keep_buffer = 1;
1027 else
1028 es->keep_buffer = 0;
1029
Jesse Barnes58ef3792012-02-23 09:45:49 -05001030 pixman_region32_init(&surface_overlap);
1031 pixman_region32_intersect(&surface_overlap, &overlap,
1032 &es->transform.boundingbox);
1033
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001034 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001035 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001036 next_plane = primary;
1037 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001038 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001039 if (next_plane == NULL)
1040 next_plane = drm_output_prepare_scanout_surface(output, es);
1041 if (next_plane == NULL)
1042 next_plane = drm_output_prepare_overlay_surface(output, es);
1043 if (next_plane == NULL)
1044 next_plane = primary;
1045 weston_surface_move_to_plane(es, next_plane);
1046 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001047 pixman_region32_union(&overlap, &overlap,
1048 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001049
Jesse Barnes58ef3792012-02-23 09:45:49 -05001050 pixman_region32_fini(&surface_overlap);
1051 }
1052 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001053}
1054
Matt Roper361d2ad2011-08-29 13:52:23 -07001055static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001056drm_output_fini_pixman(struct drm_output *output);
1057
1058static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001059drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001060{
1061 struct drm_output *output = (struct drm_output *) output_base;
1062 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001063 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001064 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001065
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001066 if (output->backlight)
1067 backlight_destroy(output->backlight);
1068
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001069 drmModeFreeProperty(output->dpms_prop);
1070
Matt Roper361d2ad2011-08-29 13:52:23 -07001071 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001072 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001073
1074 /* Restore original CRTC state */
1075 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001076 origcrtc->x, origcrtc->y,
1077 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001078 drmModeFreeCrtc(origcrtc);
1079
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001080 c->crtc_allocator &= ~(1 << output->crtc_id);
1081 c->connector_allocator &= ~(1 << output->connector_id);
1082
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001083 if (c->use_pixman) {
1084 drm_output_fini_pixman(output);
1085 } else {
1086 gl_renderer_output_destroy(output_base);
1087 gbm_surface_destroy(output->surface);
1088 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001089
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001090 weston_plane_release(&output->fb_plane);
1091 weston_plane_release(&output->cursor_plane);
1092
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001093 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001094 wl_list_remove(&output->base.link);
1095
Matt Roper361d2ad2011-08-29 13:52:23 -07001096 free(output);
1097}
1098
Alex Wub7b8bda2012-04-17 17:20:48 +08001099static struct drm_mode *
1100choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1101{
1102 struct drm_mode *tmp_mode = NULL, *mode;
1103
Hardeningff39efa2013-09-18 23:56:35 +02001104 if (output->base.current_mode->width == target_mode->width &&
1105 output->base.current_mode->height == target_mode->height &&
1106 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001107 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001108 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001109
1110 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1111 if (mode->mode_info.hdisplay == target_mode->width &&
1112 mode->mode_info.vdisplay == target_mode->height) {
1113 if (mode->mode_info.vrefresh == target_mode->refresh ||
1114 target_mode->refresh == 0) {
1115 return mode;
1116 } else if (!tmp_mode)
1117 tmp_mode = mode;
1118 }
1119 }
1120
1121 return tmp_mode;
1122}
1123
1124static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001125drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001126static int
1127drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001128
1129static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001130drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1131{
1132 struct drm_output *output;
1133 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001134 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001135
1136 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001137 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001138 return -1;
1139 }
1140
1141 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001142 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001143 return -1;
1144 }
1145
1146 ec = (struct drm_compositor *)output_base->compositor;
1147 output = (struct drm_output *)output_base;
1148 drm_mode = choose_mode (output, mode);
1149
1150 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001151 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001152 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001153 }
1154
Hardeningff39efa2013-09-18 23:56:35 +02001155 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001156 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001157
Hardeningff39efa2013-09-18 23:56:35 +02001158 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001159
Hardeningff39efa2013-09-18 23:56:35 +02001160 output->base.current_mode = &drm_mode->base;
1161 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001162 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1163
Alex Wub7b8bda2012-04-17 17:20:48 +08001164 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001165 drm_output_release_fb(output, output->current);
1166 drm_output_release_fb(output, output->next);
1167 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001168
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001169 if (ec->use_pixman) {
1170 drm_output_fini_pixman(output);
1171 if (drm_output_init_pixman(output, ec) < 0) {
1172 weston_log("failed to init output pixman state with "
1173 "new mode\n");
1174 return -1;
1175 }
1176 } else {
1177 gl_renderer_output_destroy(&output->base);
1178 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001179
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001180 if (drm_output_init_egl(output, ec) < 0) {
1181 weston_log("failed to init output egl state with "
1182 "new mode");
1183 return -1;
1184 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001185 }
1186
Alex Wub7b8bda2012-04-17 17:20:48 +08001187 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001188}
1189
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001190static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001191on_drm_input(int fd, uint32_t mask, void *data)
1192{
1193 drmEventContext evctx;
1194
1195 memset(&evctx, 0, sizeof evctx);
1196 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1197 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001198 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001199 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001200
1201 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001202}
1203
1204static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001205init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001206{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001207 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001208 uint64_t cap;
1209 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001210
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001211 sysnum = udev_device_get_sysnum(device);
1212 if (sysnum)
1213 ec->drm.id = atoi(sysnum);
1214 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001215 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001216 return -1;
1217 }
1218
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001219 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001220 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001221 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001222 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001223 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001224 udev_device_get_devnode(device));
1225 return -1;
1226 }
1227
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001228 weston_log("using %s\n", filename);
1229
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001230 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001231 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001232
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001233 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1234 if (ret == 0 && cap == 1)
1235 ec->clock = CLOCK_MONOTONIC;
1236 else
1237 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001238
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001239 return 0;
1240}
1241
1242static int
1243init_egl(struct drm_compositor *ec)
1244{
Benjamin Franzke060cf802011-04-30 09:32:11 +02001245 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001246
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001247 if (!ec->gbm)
1248 return -1;
1249
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001250 if (gl_renderer_create(&ec->base, ec->gbm,
1251 gl_renderer_opaque_attribs,
1252 &ec->format) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001253 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001254 return -1;
1255 }
1256
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001257 return 0;
1258}
1259
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001260static int
1261init_pixman(struct drm_compositor *ec)
1262{
1263 return pixman_renderer_init(&ec->base);
1264}
1265
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001266static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001267drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001268{
1269 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001270 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001271
1272 mode = malloc(sizeof *mode);
1273 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001274 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001275
1276 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001277 mode->base.width = info->hdisplay;
1278 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001279
1280 /* Calculate higher precision (mHz) refresh rate */
1281 refresh = (info->clock * 1000000LL / info->htotal +
1282 info->vtotal / 2) / info->vtotal;
1283
1284 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1285 refresh *= 2;
1286 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1287 refresh /= 2;
1288 if (info->vscan > 1)
1289 refresh /= info->vscan;
1290
1291 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001292 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001293
1294 if (info->type & DRM_MODE_TYPE_PREFERRED)
1295 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1296
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001297 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1298
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001299 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001300}
1301
1302static int
1303drm_subpixel_to_wayland(int drm_value)
1304{
1305 switch (drm_value) {
1306 default:
1307 case DRM_MODE_SUBPIXEL_UNKNOWN:
1308 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1309 case DRM_MODE_SUBPIXEL_NONE:
1310 return WL_OUTPUT_SUBPIXEL_NONE;
1311 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1312 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1313 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1314 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1315 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1316 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1317 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1318 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1319 }
1320}
1321
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001322/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001323static uint32_t
1324drm_get_backlight(struct drm_output *output)
1325{
1326 long brightness, max_brightness, norm;
1327
1328 brightness = backlight_get_brightness(output->backlight);
1329 max_brightness = backlight_get_max_brightness(output->backlight);
1330
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001331 /* convert it on a scale of 0 to 255 */
1332 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001333
1334 return (uint32_t) norm;
1335}
1336
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001337/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001338static void
1339drm_set_backlight(struct weston_output *output_base, uint32_t value)
1340{
1341 struct drm_output *output = (struct drm_output *) output_base;
1342 long max_brightness, new_brightness;
1343
1344 if (!output->backlight)
1345 return;
1346
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001347 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001348 return;
1349
1350 max_brightness = backlight_get_max_brightness(output->backlight);
1351
1352 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001353 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001354
1355 backlight_set_brightness(output->backlight, new_brightness);
1356}
1357
1358static drmModePropertyPtr
1359drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1360{
1361 drmModePropertyPtr props;
1362 int i;
1363
1364 for (i = 0; i < connector->count_props; i++) {
1365 props = drmModeGetProperty(fd, connector->props[i]);
1366 if (!props)
1367 continue;
1368
1369 if (!strcmp(props->name, name))
1370 return props;
1371
1372 drmModeFreeProperty(props);
1373 }
1374
1375 return NULL;
1376}
1377
1378static void
1379drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1380{
1381 struct drm_output *output = (struct drm_output *) output_base;
1382 struct weston_compositor *ec = output_base->compositor;
1383 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001384
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001385 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001386 return;
1387
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001388 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1389 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001390}
1391
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001392static const char *connector_type_names[] = {
1393 "None",
1394 "VGA",
1395 "DVI",
1396 "DVI",
1397 "DVI",
1398 "Composite",
1399 "TV",
1400 "LVDS",
1401 "CTV",
1402 "DIN",
1403 "DP",
1404 "HDMI",
1405 "HDMI",
1406 "TV",
1407 "eDP",
1408};
1409
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001410static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001411find_crtc_for_connector(struct drm_compositor *ec,
1412 drmModeRes *resources, drmModeConnector *connector)
1413{
1414 drmModeEncoder *encoder;
1415 uint32_t possible_crtcs;
1416 int i, j;
1417
1418 for (j = 0; j < connector->count_encoders; j++) {
1419 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1420 if (encoder == NULL) {
1421 weston_log("Failed to get encoder.\n");
1422 return -1;
1423 }
1424 possible_crtcs = encoder->possible_crtcs;
1425 drmModeFreeEncoder(encoder);
1426
1427 for (i = 0; i < resources->count_crtcs; i++) {
1428 if (possible_crtcs & (1 << i) &&
1429 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1430 return i;
1431 }
1432 }
1433
1434 return -1;
1435}
1436
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001437/* Init output state that depends on gl or gbm */
1438static int
1439drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1440{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001441 int i, flags;
1442
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001443 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001444 output->base.current_mode->width,
1445 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001446 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001447 GBM_BO_USE_SCANOUT |
1448 GBM_BO_USE_RENDERING);
1449 if (!output->surface) {
1450 weston_log("failed to create gbm surface\n");
1451 return -1;
1452 }
1453
1454 if (gl_renderer_output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001455 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001456 gbm_surface_destroy(output->surface);
1457 return -1;
1458 }
1459
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001460 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1461
1462 for (i = 0; i < 2; i++) {
1463 if (output->cursor_bo[i])
1464 continue;
1465
1466 output->cursor_bo[i] =
1467 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1468 flags);
1469 }
1470
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001471 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1472 weston_log("cursor buffers unavailable, using gl cursors\n");
1473 ec->cursors_are_broken = 1;
1474 }
1475
1476 return 0;
1477}
1478
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001479static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001480drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1481{
Hardeningff39efa2013-09-18 23:56:35 +02001482 int w = output->base.current_mode->width;
1483 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001484 unsigned int i;
1485
1486 /* FIXME error checking */
1487
1488 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001489 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001490 if (!output->dumb[i])
1491 goto err;
1492
1493 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001494 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001495 output->dumb[i]->map,
1496 output->dumb[i]->stride);
1497 if (!output->image[i])
1498 goto err;
1499 }
1500
1501 if (pixman_renderer_output_create(&output->base) < 0)
1502 goto err;
1503
1504 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001505 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001506
1507 return 0;
1508
1509err:
1510 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1511 if (output->dumb[i])
1512 drm_fb_destroy_dumb(output->dumb[i]);
1513 if (output->image[i])
1514 pixman_image_unref(output->image[i]);
1515
1516 output->dumb[i] = NULL;
1517 output->image[i] = NULL;
1518 }
1519
1520 return -1;
1521}
1522
1523static void
1524drm_output_fini_pixman(struct drm_output *output)
1525{
1526 unsigned int i;
1527
1528 pixman_renderer_output_destroy(&output->base);
1529 pixman_region32_fini(&output->previous_damage);
1530
1531 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1532 drm_fb_destroy_dumb(output->dumb[i]);
1533 pixman_image_unref(output->image[i]);
1534 output->dumb[i] = NULL;
1535 output->image[i] = NULL;
1536 }
1537}
1538
Richard Hughes2b2092a2013-04-24 14:58:02 +01001539static void
1540edid_parse_string(const uint8_t *data, char text[])
1541{
1542 int i;
1543 int replaced = 0;
1544
1545 /* this is always 12 bytes, but we can't guarantee it's null
1546 * terminated or not junk. */
1547 strncpy(text, (const char *) data, 12);
1548
1549 /* remove insane chars */
1550 for (i = 0; text[i] != '\0'; i++) {
1551 if (text[i] == '\n' ||
1552 text[i] == '\r') {
1553 text[i] = '\0';
1554 break;
1555 }
1556 }
1557
1558 /* ensure string is printable */
1559 for (i = 0; text[i] != '\0'; i++) {
1560 if (!isprint(text[i])) {
1561 text[i] = '-';
1562 replaced++;
1563 }
1564 }
1565
1566 /* if the string is random junk, ignore the string */
1567 if (replaced > 4)
1568 text[0] = '\0';
1569}
1570
1571#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1572#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1573#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1574#define EDID_OFFSET_DATA_BLOCKS 0x36
1575#define EDID_OFFSET_LAST_BLOCK 0x6c
1576#define EDID_OFFSET_PNPID 0x08
1577#define EDID_OFFSET_SERIAL 0x0c
1578
1579static int
1580edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1581{
1582 int i;
1583 uint32_t serial_number;
1584
1585 /* check header */
1586 if (length < 128)
1587 return -1;
1588 if (data[0] != 0x00 || data[1] != 0xff)
1589 return -1;
1590
1591 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1592 * /--08--\/--09--\
1593 * 7654321076543210
1594 * |\---/\---/\---/
1595 * R C1 C2 C3 */
1596 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1597 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1598 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1599 edid->pnp_id[3] = '\0';
1600
1601 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1602 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1603 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1604 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1605 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1606 if (serial_number > 0)
1607 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1608
1609 /* parse EDID data */
1610 for (i = EDID_OFFSET_DATA_BLOCKS;
1611 i <= EDID_OFFSET_LAST_BLOCK;
1612 i += 18) {
1613 /* ignore pixel clock data */
1614 if (data[i] != 0)
1615 continue;
1616 if (data[i+2] != 0)
1617 continue;
1618
1619 /* any useful blocks? */
1620 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1621 edid_parse_string(&data[i+5],
1622 edid->monitor_name);
1623 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1624 edid_parse_string(&data[i+5],
1625 edid->serial_number);
1626 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1627 edid_parse_string(&data[i+5],
1628 edid->eisa_id);
1629 }
1630 }
1631 return 0;
1632}
1633
1634static void
1635find_and_parse_output_edid(struct drm_compositor *ec,
1636 struct drm_output *output,
1637 drmModeConnector *connector)
1638{
1639 drmModePropertyBlobPtr edid_blob = NULL;
1640 drmModePropertyPtr property;
1641 int i;
1642 int rc;
1643
1644 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1645 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1646 if (!property)
1647 continue;
1648 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1649 !strcmp(property->name, "EDID")) {
1650 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1651 connector->prop_values[i]);
1652 }
1653 drmModeFreeProperty(property);
1654 }
1655 if (!edid_blob)
1656 return;
1657
1658 rc = edid_parse(&output->edid,
1659 edid_blob->data,
1660 edid_blob->length);
1661 if (!rc) {
1662 weston_log("EDID data '%s', '%s', '%s'\n",
1663 output->edid.pnp_id,
1664 output->edid.monitor_name,
1665 output->edid.serial_number);
1666 if (output->edid.pnp_id[0] != '\0')
1667 output->base.make = output->edid.pnp_id;
1668 if (output->edid.monitor_name[0] != '\0')
1669 output->base.model = output->edid.monitor_name;
1670 if (output->edid.serial_number[0] != '\0')
1671 output->base.serial_number = output->edid.serial_number;
1672 }
1673 drmModeFreePropertyBlob(edid_blob);
1674}
1675
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001676
1677
1678static int
1679parse_modeline(const char *s, drmModeModeInfo *mode)
1680{
1681 char hsync[16];
1682 char vsync[16];
1683 float fclock;
1684
1685 mode->type = DRM_MODE_TYPE_USERDEF;
1686 mode->hskew = 0;
1687 mode->vscan = 0;
1688 mode->vrefresh = 0;
1689 mode->flags = 0;
1690
Rob Bradford307e09e2013-07-26 16:29:40 +01001691 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001692 &fclock,
1693 &mode->hdisplay,
1694 &mode->hsync_start,
1695 &mode->hsync_end,
1696 &mode->htotal,
1697 &mode->vdisplay,
1698 &mode->vsync_start,
1699 &mode->vsync_end,
1700 &mode->vtotal, hsync, vsync) != 11)
1701 return -1;
1702
1703 mode->clock = fclock * 1000;
1704 if (strcmp(hsync, "+hsync") == 0)
1705 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1706 else if (strcmp(hsync, "-hsync") == 0)
1707 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1708 else
1709 return -1;
1710
1711 if (strcmp(vsync, "+vsync") == 0)
1712 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1713 else if (strcmp(vsync, "-vsync") == 0)
1714 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1715 else
1716 return -1;
1717
1718 return 0;
1719}
1720
1721static uint32_t
1722parse_transform(const char *transform, const char *output_name)
1723{
1724 static const struct { const char *name; uint32_t token; } names[] = {
1725 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1726 { "90", WL_OUTPUT_TRANSFORM_90 },
1727 { "180", WL_OUTPUT_TRANSFORM_180 },
1728 { "270", WL_OUTPUT_TRANSFORM_270 },
1729 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1730 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1731 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1732 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1733 };
1734 unsigned int i;
1735
1736 for (i = 0; i < ARRAY_LENGTH(names); i++)
1737 if (strcmp(names[i].name, transform) == 0)
1738 return names[i].token;
1739
1740 weston_log("Invalid transform \"%s\" for output %s\n",
1741 transform, output_name);
1742
1743 return WL_OUTPUT_TRANSFORM_NORMAL;
1744}
1745
Rob Bradford66bd9f52013-06-25 18:56:42 +01001746static void
1747setup_output_seat_constraint(struct drm_compositor *ec,
1748 struct weston_output *output,
1749 const char *s)
1750{
1751 if (strcmp(s, "") != 0) {
1752 struct udev_seat *seat;
1753
1754 seat = udev_seat_get_named(&ec->base, s);
1755 if (seat)
1756 seat->base.output = output;
1757
1758 if (seat && seat->base.pointer)
1759 weston_pointer_clamp(seat->base.pointer,
1760 &seat->base.pointer->x,
1761 &seat->base.pointer->y);
1762 }
1763}
1764
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001765static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001766create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001767 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001768 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001769 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001770{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001771 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001772 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1773 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001774 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001775 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001776 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001777 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001778 int i, width, height, scale;
1779 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001780 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001781 enum output_config config;
1782 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001783
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001784 i = find_crtc_for_connector(ec, resources, connector);
1785 if (i < 0) {
1786 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001787 return -1;
1788 }
1789
Peter Huttererf3d62272013-08-08 11:57:05 +10001790 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001791 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001792 return -1;
1793
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001794 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1795 output->base.make = "unknown";
1796 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001797 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001798 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001799
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001800 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1801 type_name = connector_type_names[connector->connector_type];
1802 else
1803 type_name = "UNKNOWN";
1804 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001805 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001806
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001807 section = weston_config_get_section(ec->base.config, "output", "name",
1808 output->base.name);
1809 weston_config_section_get_string(section, "mode", &s, "preferred");
1810 if (strcmp(s, "off") == 0)
1811 config = OUTPUT_CONFIG_OFF;
1812 else if (strcmp(s, "preferred") == 0)
1813 config = OUTPUT_CONFIG_PREFERRED;
1814 else if (strcmp(s, "current") == 0)
1815 config = OUTPUT_CONFIG_CURRENT;
1816 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1817 config = OUTPUT_CONFIG_MODE;
1818 else if (parse_modeline(s, &modeline) == 0)
1819 config = OUTPUT_CONFIG_MODELINE;
1820 else {
1821 weston_log("Invalid mode \"%s\" for output %s\n",
1822 s, output->base.name);
1823 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001824 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001825 free(s);
1826
1827 weston_config_section_get_int(section, "scale", &scale, 1);
1828 weston_config_section_get_string(section, "transform", &s, "normal");
1829 transform = parse_transform(s, output->base.name);
1830 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001831
Rob Bradford66bd9f52013-06-25 18:56:42 +01001832 weston_config_section_get_string(section, "seat", &s, "");
1833 setup_output_seat_constraint(ec, &output->base, s);
1834 free(s);
1835
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001836 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001837 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001838 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001839 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001840 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001841
Matt Roper361d2ad2011-08-29 13:52:23 -07001842 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001843 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001844
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001845 /* Get the current mode on the crtc that's currently driving
1846 * this connector. */
1847 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001848 memset(&crtc_mode, 0, sizeof crtc_mode);
1849 if (encoder != NULL) {
1850 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1851 drmModeFreeEncoder(encoder);
1852 if (crtc == NULL)
1853 goto err_free;
1854 if (crtc->mode_valid)
1855 crtc_mode = crtc->mode;
1856 drmModeFreeCrtc(crtc);
1857 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001858
David Herrmann0f0d54e2011-12-08 17:05:45 +01001859 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001860 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001861 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001862 goto err_free;
1863 }
1864
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001865 if (config == OUTPUT_CONFIG_OFF) {
1866 weston_log("Disabling output %s\n", output->base.name);
1867 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1868 0, 0, 0, 0, 0, NULL);
1869 goto err_free;
1870 }
1871
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001872 preferred = NULL;
1873 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001874 configured = NULL;
1875
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001876 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001877 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001878 width == drm_mode->base.width &&
1879 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001880 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001881 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001882 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001883 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001884 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001885 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001886
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001887 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001888 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001889 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001890 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001891 }
1892
Wang Quanxianacb805a2012-07-30 18:09:46 -04001893 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001894 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001895 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001896 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001897 }
1898
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001899 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001900 configured = current;
1901
Wang Quanxianacb805a2012-07-30 18:09:46 -04001902 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001903 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001904 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001905 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001906 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001907 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001908 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001909 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001910
Hardeningff39efa2013-09-18 23:56:35 +02001911 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001912 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001913 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001914 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001915
Hardeningff39efa2013-09-18 23:56:35 +02001916 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001917
John Kåre Alsaker94659272012-11-13 19:10:18 +01001918 weston_output_init(&output->base, &ec->base, x, y,
1919 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001920 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001921
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001922 if (ec->use_pixman) {
1923 if (drm_output_init_pixman(output, ec) < 0) {
1924 weston_log("Failed to init output pixman state\n");
1925 goto err_output;
1926 }
1927 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001928 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001929 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001930 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001931
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001932 output->backlight = backlight_init(drm_device,
1933 connector->connector_type);
1934 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001935 weston_log("Initialized backlight, device %s\n",
1936 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001937 output->base.set_backlight = drm_set_backlight;
1938 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001939 } else {
1940 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001941 }
1942
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001943 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1944
Richard Hughes2b2092a2013-04-24 14:58:02 +01001945 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001946 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1947 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001948
Jonas Ådahle5a12252013-04-05 23:07:11 +02001949 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001950 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001951 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001952 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001953 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001954 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001955
Richard Hughese7299962013-05-01 21:52:12 +01001956 output->base.gamma_size = output->original_crtc->gamma_size;
1957 output->base.set_gamma = drm_output_set_gamma;
1958
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001959 weston_plane_init(&output->cursor_plane, 0, 0);
1960 weston_plane_init(&output->fb_plane, 0, 0);
1961
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001962 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1963 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1964 &ec->base.primary_plane);
1965
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001966 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01001967 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001968 wl_list_for_each(m, &output->base.mode_list, link)
1969 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
1970 m->width, m->height, m->refresh / 1000.0,
1971 m->flags & WL_OUTPUT_MODE_PREFERRED ?
1972 ", preferred" : "",
1973 m->flags & WL_OUTPUT_MODE_CURRENT ?
1974 ", current" : "",
1975 connector->count_modes == 0 ?
1976 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001977
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001978 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001979
John Kåre Alsaker94659272012-11-13 19:10:18 +01001980err_output:
1981 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001982err_free:
1983 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
1984 base.link) {
1985 wl_list_remove(&drm_mode->base.link);
1986 free(drm_mode);
1987 }
1988
1989 drmModeFreeCrtc(output->original_crtc);
1990 ec->crtc_allocator &= ~(1 << output->crtc_id);
1991 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01001992 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001993
David Herrmann0f0d54e2011-12-08 17:05:45 +01001994 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001995}
1996
Jesse Barnes58ef3792012-02-23 09:45:49 -05001997static void
1998create_sprites(struct drm_compositor *ec)
1999{
2000 struct drm_sprite *sprite;
2001 drmModePlaneRes *plane_res;
2002 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002003 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002004
2005 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2006 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002007 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002008 strerror(errno));
2009 return;
2010 }
2011
2012 for (i = 0; i < plane_res->count_planes; i++) {
2013 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2014 if (!plane)
2015 continue;
2016
Peter Huttererf3d62272013-08-08 11:57:05 +10002017 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002018 plane->count_formats));
2019 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002020 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002021 __func__);
2022 free(plane);
2023 continue;
2024 }
2025
Jesse Barnes58ef3792012-02-23 09:45:49 -05002026 sprite->possible_crtcs = plane->possible_crtcs;
2027 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002028 sprite->current = NULL;
2029 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002030 sprite->compositor = ec;
2031 sprite->count_formats = plane->count_formats;
2032 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002033 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002034 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002035 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002036 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2037 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002038
2039 wl_list_insert(&ec->sprite_list, &sprite->link);
2040 }
2041
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002042 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002043}
2044
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002045static void
2046destroy_sprites(struct drm_compositor *compositor)
2047{
2048 struct drm_sprite *sprite, *next;
2049 struct drm_output *output;
2050
2051 output = container_of(compositor->base.output_list.next,
2052 struct drm_output, base.link);
2053
2054 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2055 drmModeSetPlane(compositor->drm.fd,
2056 sprite->plane_id,
2057 output->crtc_id, 0, 0,
2058 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002059 drm_output_release_fb(output, sprite->current);
2060 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002061 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002062 free(sprite);
2063 }
2064}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002065
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002066static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002067create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002068 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002069{
2070 drmModeConnector *connector;
2071 drmModeRes *resources;
2072 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002073 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002074
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002075 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002076 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002077 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002078 return -1;
2079 }
2080
Jesse Barnes58ef3792012-02-23 09:45:49 -05002081 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002082 if (!ec->crtcs) {
2083 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002084 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002085 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002086
Rob Clark4339add2012-08-09 14:18:28 -05002087 ec->min_width = resources->min_width;
2088 ec->max_width = resources->max_width;
2089 ec->min_height = resources->min_height;
2090 ec->max_height = resources->max_height;
2091
Jesse Barnes58ef3792012-02-23 09:45:49 -05002092 ec->num_crtcs = resources->count_crtcs;
2093 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2094
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002095 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002096 connector = drmModeGetConnector(ec->drm.fd,
2097 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002098 if (connector == NULL)
2099 continue;
2100
2101 if (connector->connection == DRM_MODE_CONNECTED &&
2102 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002103 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002104 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002105 connector, x, y,
2106 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002107 drmModeFreeConnector(connector);
2108 continue;
2109 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002110
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002111 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002112 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002113 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002114 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002115
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002116 drmModeFreeConnector(connector);
2117 }
2118
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002119 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002120 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002121 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002122 return -1;
2123 }
2124
2125 drmModeFreeResources(resources);
2126
2127 return 0;
2128}
2129
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002130static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002131update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002132{
2133 drmModeConnector *connector;
2134 drmModeRes *resources;
2135 struct drm_output *output, *next;
2136 int x = 0, y = 0;
2137 int x_offset = 0, y_offset = 0;
2138 uint32_t connected = 0, disconnects = 0;
2139 int i;
2140
2141 resources = drmModeGetResources(ec->drm.fd);
2142 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002143 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002144 return;
2145 }
2146
2147 /* collect new connects */
2148 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002149 int connector_id = resources->connectors[i];
2150
2151 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002152 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002153 continue;
2154
David Herrmann7551cff2011-12-08 17:05:43 +01002155 if (connector->connection != DRM_MODE_CONNECTED) {
2156 drmModeFreeConnector(connector);
2157 continue;
2158 }
2159
Benjamin Franzke117483d2011-08-30 11:38:26 +02002160 connected |= (1 << connector_id);
2161
2162 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002163 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002164 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002165 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002166
2167 /* XXX: not yet needed, we die with 0 outputs */
2168 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002169 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002170 else
2171 x = 0;
2172 y = 0;
2173 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002174 connector, x, y,
2175 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002176 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002177
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002178 }
2179 drmModeFreeConnector(connector);
2180 }
2181 drmModeFreeResources(resources);
2182
2183 disconnects = ec->connector_allocator & ~connected;
2184 if (disconnects) {
2185 wl_list_for_each_safe(output, next, &ec->base.output_list,
2186 base.link) {
2187 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002188 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002189 output->base.x - x_offset,
2190 output->base.y - y_offset);
2191 }
2192
2193 if (disconnects & (1 << output->connector_id)) {
2194 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002195 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002196 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002197 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002198 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002199 }
2200 }
2201 }
2202
2203 /* FIXME: handle zero outputs, without terminating */
2204 if (ec->connector_allocator == 0)
2205 wl_display_terminate(ec->base.wl_display);
2206}
2207
2208static int
David Herrmannd7488c22012-03-11 20:05:21 +01002209udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002210{
David Herrmannd7488c22012-03-11 20:05:21 +01002211 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002212 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002213
2214 sysnum = udev_device_get_sysnum(device);
2215 if (!sysnum || atoi(sysnum) != ec->drm.id)
2216 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002217
David Herrmann6ac52db2012-03-11 20:05:22 +01002218 val = udev_device_get_property_value(device, "HOTPLUG");
2219 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002220 return 0;
2221
David Herrmann6ac52db2012-03-11 20:05:22 +01002222 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002223}
2224
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002225static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002226udev_drm_event(int fd, uint32_t mask, void *data)
2227{
2228 struct drm_compositor *ec = data;
2229 struct udev_device *event;
2230
2231 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002232
David Herrmannd7488c22012-03-11 20:05:21 +01002233 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002234 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002235
2236 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002237
2238 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002239}
2240
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002241static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002242drm_restore(struct weston_compositor *ec)
2243{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002244 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002245}
2246
2247static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002248drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002249{
2250 struct drm_compositor *d = (struct drm_compositor *) ec;
2251
Rob Bradfordd355b802013-05-31 18:09:55 +01002252 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002253
2254 wl_event_source_remove(d->udev_drm_source);
2255 wl_event_source_remove(d->drm_source);
2256
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002257 destroy_sprites(d);
2258
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002259 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002260
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002261 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002262
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002263 if (d->gbm)
2264 gbm_device_destroy(d->gbm);
2265
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002266 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002267
Rob Bradford45c15b82013-07-26 16:29:35 +01002268 close(d->drm.fd);
2269
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002270 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002271}
2272
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002273static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002274drm_compositor_set_modes(struct drm_compositor *compositor)
2275{
2276 struct drm_output *output;
2277 struct drm_mode *drm_mode;
2278 int ret;
2279
2280 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002281 if (!output->current) {
2282 /* If something that would cause the output to
2283 * switch mode happened while in another vt, we
2284 * might not have a current drm_fb. In that case,
2285 * schedule a repaint and let drm_output_repaint
2286 * handle setting the mode. */
2287 weston_output_schedule_repaint(&output->base);
2288 continue;
2289 }
2290
Hardeningff39efa2013-09-18 23:56:35 +02002291 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002292 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002293 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002294 &output->connector_id, 1,
2295 &drm_mode->mode_info);
2296 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002297 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002298 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002299 drm_mode->base.width, drm_mode->base.height,
2300 output->base.x, output->base.y);
2301 }
2302 }
2303}
2304
2305static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002306session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002307{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002308 struct weston_compositor *compositor = data;
2309 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002310 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002311 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002312
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002313 if (ec->base.session_active) {
2314 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002315 compositor->focus = 1;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002316 if (ec->base.launcher == NULL && drmSetMaster(ec->drm.fd)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002317 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002318 wl_display_terminate(compositor->wl_display);
2319 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002320 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002321 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002322 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002323 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002324 } else {
2325 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002326 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002327
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002328 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002329 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002330 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002331
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002332 /* If we have a repaint scheduled (either from a
2333 * pending pageflip or the idle handler), make sure we
2334 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002335 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002336 * further attemps at repainting. When we switch
2337 * back, we schedule a repaint, which will process
2338 * pending frame callbacks. */
2339
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002340 wl_list_for_each(output, &ec->base.output_list, base.link) {
2341 output->base.repaint_needed = 0;
2342 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002343 }
2344
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002345 output = container_of(ec->base.output_list.next,
2346 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002347
2348 wl_list_for_each(sprite, &ec->sprite_list, link)
2349 drmModeSetPlane(ec->drm.fd,
2350 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002351 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002352 0, 0, 0, 0, 0, 0, 0, 0);
2353
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002354 if (ec->base.launcher == NULL && drmDropMaster(ec->drm.fd) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002355 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002356 };
2357}
2358
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002359static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002360switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002361{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002362 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002363
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002364 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002365}
2366
David Herrmann0af066f2012-10-29 19:21:16 +01002367/*
2368 * Find primary GPU
2369 * Some systems may have multiple DRM devices attached to a single seat. This
2370 * function loops over all devices and tries to find a PCI device with the
2371 * boot_vga sysfs attribute set to 1.
2372 * If no such device is found, the first DRM device reported by udev is used.
2373 */
2374static struct udev_device*
2375find_primary_gpu(struct drm_compositor *ec, const char *seat)
2376{
2377 struct udev_enumerate *e;
2378 struct udev_list_entry *entry;
2379 const char *path, *device_seat, *id;
2380 struct udev_device *device, *drm_device, *pci;
2381
2382 e = udev_enumerate_new(ec->udev);
2383 udev_enumerate_add_match_subsystem(e, "drm");
2384 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2385
2386 udev_enumerate_scan_devices(e);
2387 drm_device = NULL;
2388 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2389 path = udev_list_entry_get_name(entry);
2390 device = udev_device_new_from_syspath(ec->udev, path);
2391 if (!device)
2392 continue;
2393 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2394 if (!device_seat)
2395 device_seat = default_seat;
2396 if (strcmp(device_seat, seat)) {
2397 udev_device_unref(device);
2398 continue;
2399 }
2400
2401 pci = udev_device_get_parent_with_subsystem_devtype(device,
2402 "pci", NULL);
2403 if (pci) {
2404 id = udev_device_get_sysattr_value(pci, "boot_vga");
2405 if (id && !strcmp(id, "1")) {
2406 if (drm_device)
2407 udev_device_unref(drm_device);
2408 drm_device = device;
2409 break;
2410 }
2411 }
2412
2413 if (!drm_device)
2414 drm_device = device;
2415 else
2416 udev_device_unref(device);
2417 }
2418
2419 udev_enumerate_unref(e);
2420 return drm_device;
2421}
2422
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002423static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002424planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002425{
2426 struct drm_compositor *c = data;
2427
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002428 switch (key) {
2429 case KEY_C:
2430 c->cursors_are_broken ^= 1;
2431 break;
2432 case KEY_V:
2433 c->sprites_are_broken ^= 1;
2434 break;
2435 case KEY_O:
2436 c->sprites_hidden ^= 1;
2437 break;
2438 default:
2439 break;
2440 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002441}
2442
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002443#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002444static void
2445recorder_frame_notify(struct wl_listener *listener, void *data)
2446{
2447 struct drm_output *output;
2448 struct drm_compositor *c;
2449 int fd, ret;
2450
2451 output = container_of(listener, struct drm_output,
2452 recorder_frame_listener);
2453 c = (struct drm_compositor *) output->base.compositor;
2454
2455 if (!output->recorder)
2456 return;
2457
2458 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2459 DRM_CLOEXEC, &fd);
2460 if (ret) {
2461 weston_log("[libva recorder] "
2462 "failed to create prime fd for front buffer\n");
2463 return;
2464 }
2465
2466 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002467}
2468
2469static void *
2470create_recorder(struct drm_compositor *c, int width, int height,
2471 const char *filename)
2472{
2473 int fd;
2474 drm_magic_t magic;
2475
2476 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2477 if (fd < 0)
2478 return NULL;
2479
2480 drmGetMagic(fd, &magic);
2481 drmAuthMagic(c->drm.fd, magic);
2482
2483 return vaapi_recorder_create(fd, width, height, filename);
2484}
2485
2486static void
2487recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2488 void *data)
2489{
2490 struct drm_compositor *c = data;
2491 struct drm_output *output;
2492 int width, height;
2493
2494 output = container_of(c->base.output_list.next,
2495 struct drm_output, base.link);
2496
2497 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002498 width = output->base.current_mode->width;
2499 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002500
2501 output->recorder =
2502 create_recorder(c, width, height, "capture.h264");
2503 if (!output->recorder) {
2504 weston_log("failed to create vaapi recorder\n");
2505 return;
2506 }
2507
2508 output->base.disable_planes++;
2509
2510 output->recorder_frame_listener.notify = recorder_frame_notify;
2511 wl_signal_add(&output->base.frame_signal,
2512 &output->recorder_frame_listener);
2513
2514 weston_output_schedule_repaint(&output->base);
2515
2516 weston_log("[libva recorder] initialized\n");
2517 } else {
2518 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002519 output->recorder = NULL;
2520
2521 output->base.disable_planes--;
2522
2523 wl_list_remove(&output->recorder_frame_listener.link);
2524 weston_log("[libva recorder] done\n");
2525 }
2526}
2527#else
2528static void
2529recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2530 void *data)
2531{
2532 weston_log("Compiled without libva support\n");
2533}
2534#endif
2535
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002536static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002537drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002538 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002539 int *argc, char *argv[],
2540 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002541{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002542 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002543 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002544 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002545 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002546 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002547
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002548 weston_log("initializing drm backend\n");
2549
Peter Huttererf3d62272013-08-08 11:57:05 +10002550 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002551 if (ec == NULL)
2552 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002553
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002554 /* KMS support for sprites is not complete yet, so disable the
2555 * functionality for now. */
2556 ec->sprites_are_broken = 1;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07002557 ec->format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002558 ec->use_pixman = pixman;
2559
Daniel Stone725c2c32012-06-22 14:04:36 +01002560 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002561 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002562 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002563 goto err_base;
2564 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002565
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002566 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg6ff3ff52013-10-02 10:53:33 -07002567 ec->base.launcher = weston_launcher_connect(&ec->base, tty);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002568 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002569 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002570 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002571 goto err_compositor;
2572 }
2573
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002574 ec->udev = udev_new();
2575 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002576 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002577 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002578 }
2579
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002580 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002581 ec->session_listener.notify = session_notify;
2582 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002583
Rob Bradford643641d2013-05-31 18:09:53 +01002584 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002585 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002586 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002587 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002588 }
David Herrmann0af066f2012-10-29 19:21:16 +01002589 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002590
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002591 if (init_drm(ec, drm_device) < 0) {
2592 weston_log("failed to initialize kms\n");
2593 goto err_udev_dev;
2594 }
2595
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002596 if (ec->use_pixman) {
2597 if (init_pixman(ec) < 0) {
2598 weston_log("failed to initialize pixman renderer\n");
2599 goto err_udev_dev;
2600 }
2601 } else {
2602 if (init_egl(ec) < 0) {
2603 weston_log("failed to initialize egl\n");
2604 goto err_udev_dev;
2605 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002606 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002607
2608 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002609 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002610
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002611 ec->base.focus = 1;
2612
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002613 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002614
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002615 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002616 weston_compositor_add_key_binding(&ec->base, key,
2617 MODIFIER_CTRL | MODIFIER_ALT,
2618 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002619
Jesse Barnes58ef3792012-02-23 09:45:49 -05002620 wl_list_init(&ec->sprite_list);
2621 create_sprites(ec);
2622
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002623 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002624 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002625 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002626 }
2627
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002628 path = NULL;
2629
Rob Bradfordd355b802013-05-31 18:09:55 +01002630 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002631 weston_log("failed to create input devices\n");
2632 goto err_sprite;
2633 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002634
2635 loop = wl_display_get_event_loop(ec->base.wl_display);
2636 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002637 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002638 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002639
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002640 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2641 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002642 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002643 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002644 }
2645 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2646 "drm", NULL);
2647 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002648 wl_event_loop_add_fd(loop,
2649 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002650 WL_EVENT_READABLE, udev_drm_event, ec);
2651
2652 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002653 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002654 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002655 }
2656
Daniel Stonea96b93c2012-06-22 14:04:37 +01002657 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002658
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002659 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002660 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002661 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002662 planes_binding, ec);
2663 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2664 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002665 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2666 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002667
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002668 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002669
2670err_udev_monitor:
2671 wl_event_source_remove(ec->udev_drm_source);
2672 udev_monitor_unref(ec->udev_monitor);
2673err_drm_source:
2674 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002675 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002676err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002677 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002678 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002679 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002680err_udev_dev:
2681 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002682err_launcher:
2683 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002684err_udev:
2685 udev_unref(ec->udev);
2686err_compositor:
2687 weston_compositor_shutdown(&ec->base);
2688err_base:
2689 free(ec);
2690 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002691}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002692
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002693WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002694backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002695 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002696{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002697 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002698 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002699
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002700 const struct weston_option drm_options[] = {
2701 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002702 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002703 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002704 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002705 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002706 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002707
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002708 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002709
Rob Bradford643641d2013-05-31 18:09:53 +01002710 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002711 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002712}