blob: 25c34f8cd4149e6ba450f5b54dee78260059c427 [file] [log] [blame]
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001/*
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04002 * Copyright © 2008-2011 Kristian Høgsberg
3 * Copyright © 2011 Intel Corporation
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04004 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -04005 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040014 *
Kristian Høgsberg96aa7da2011-09-15 15:43:14 -040015 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040022 */
23
Daniel Stonec228e232013-05-22 18:03:19 +030024#include "config.h"
Kristian Høgsberg0b9334a2011-04-12 11:34:32 -040025
Jesse Barnes58ef3792012-02-23 09:45:49 -050026#include <errno.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040027#include <stdlib.h>
Richard Hughes2b2092a2013-04-24 14:58:02 +010028#include <ctype.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040029#include <string.h>
30#include <fcntl.h>
31#include <unistd.h>
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -040032#include <linux/input.h>
Kristian Høgsberg3f495872013-09-18 23:00:17 -070033#include <linux/vt.h>
Ander Conselvan de Oliveirafd1f4c62012-06-26 17:09:14 +030034#include <assert.h>
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +020035#include <sys/mman.h>
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +030036#include <dlfcn.h>
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030037#include <time.h>
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040038
Benjamin Franzkec649a922011-03-02 11:56:04 +010039#include <xf86drm.h>
40#include <xf86drmMode.h>
Jesse Barnes58ef3792012-02-23 09:45:49 -050041#include <drm_fourcc.h>
Benjamin Franzkec649a922011-03-02 11:56:04 +010042
Benjamin Franzke060cf802011-04-30 09:32:11 +020043#include <gbm.h>
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +020044#include <libbacklight.h>
Pekka Paalanen33156972012-08-03 13:30:30 -040045#include <libudev.h>
Benjamin Franzke060cf802011-04-30 09:32:11 +020046
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040047#include "compositor.h"
John Kåre Alsaker30d2b1f2012-11-13 19:10:28 +010048#include "gl-renderer.h"
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +020049#include "pixman-renderer.h"
Kristian Høgsberg98cfea62013-02-18 16:15:53 -050050#include "udev-seat.h"
Benjamin Franzkebfeda132012-01-30 14:04:04 +010051#include "launcher-util.h"
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030052#include "vaapi-recorder.h"
Kristian Høgsbergfc783d42010-06-11 12:56:24 -040053
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +030054#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
55#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
56#endif
57
Kristian Høgsberg061c4252012-06-28 11:28:15 -040058static int option_current_mode = 0;
Scott Moreau8ab5d452012-07-30 19:51:08 -060059
60enum output_config {
61 OUTPUT_CONFIG_INVALID = 0,
62 OUTPUT_CONFIG_OFF,
63 OUTPUT_CONFIG_PREFERRED,
64 OUTPUT_CONFIG_CURRENT,
Scott Moreau8f37e0b2012-07-31 15:30:41 -060065 OUTPUT_CONFIG_MODE,
66 OUTPUT_CONFIG_MODELINE
Scott Moreau8ab5d452012-07-30 19:51:08 -060067};
68
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040069struct drm_compositor {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -050070 struct weston_compositor base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040071
72 struct udev *udev;
73 struct wl_event_source *drm_source;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -040074
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010075 struct udev_monitor *udev_monitor;
76 struct wl_event_source *udev_drm_source;
77
Benjamin Franzke2af7f102011-03-02 11:14:59 +010078 struct {
David Herrmannd7488c22012-03-11 20:05:21 +010079 int id;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010080 int fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +030081 char *filename;
Benjamin Franzke2af7f102011-03-02 11:14:59 +010082 } drm;
Benjamin Franzke060cf802011-04-30 09:32:11 +020083 struct gbm_device *gbm;
Jesse Barnes58ef3792012-02-23 09:45:49 -050084 uint32_t *crtcs;
85 int num_crtcs;
Marty Jack13d9db22011-02-09 19:01:42 -050086 uint32_t crtc_allocator;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +010087 uint32_t connector_allocator;
Kristian Høgsberg61741a22013-09-17 16:02:57 -070088 struct wl_listener session_listener;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -070089 uint32_t format;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +020090
Rob Clark4339add2012-08-09 14:18:28 -050091 /* we need these parameters in order to not fail drmModeAddFB2()
92 * due to out of bounds dimensions, and then mistakenly set
93 * sprites_are_broken:
94 */
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +020095 uint32_t min_width, max_width;
96 uint32_t min_height, max_height;
97 int no_addfb2;
Rob Clark4339add2012-08-09 14:18:28 -050098
Jesse Barnes58ef3792012-02-23 09:45:49 -050099 struct wl_list sprite_list;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500100 int sprites_are_broken;
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +0200101 int sprites_hidden;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500102
Rob Clarkab5b1e32012-08-09 13:24:45 -0500103 int cursors_are_broken;
104
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200105 int use_pixman;
106
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +0200107 uint32_t prev_state;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300108
109 clockid_t clock;
Rob Bradfordd355b802013-05-31 18:09:55 +0100110 struct udev_input input;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400111};
112
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400113struct drm_mode {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500114 struct weston_mode base;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400115 drmModeModeInfo mode_info;
116};
117
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300118struct drm_output;
119
120struct drm_fb {
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300121 struct drm_output *output;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200122 uint32_t fb_id, stride, handle, size;
123 int fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300124 int is_client_buffer;
Pekka Paalanende685b82012-12-04 15:58:12 +0200125 struct weston_buffer_reference buffer_ref;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200126
127 /* Used by gbm fbs */
128 struct gbm_bo *bo;
129
130 /* Used by dumb fbs */
131 void *map;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300132};
133
Richard Hughes2b2092a2013-04-24 14:58:02 +0100134struct drm_edid {
135 char eisa_id[13];
136 char monitor_name[13];
137 char pnp_id[5];
138 char serial_number[13];
139};
140
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400141struct drm_output {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -0500142 struct weston_output base;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400143
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400144 uint32_t crtc_id;
Rob Clark5ca1a472012-08-08 20:27:37 -0500145 int pipe;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400146 uint32_t connector_id;
Matt Roper361d2ad2011-08-29 13:52:23 -0700147 drmModeCrtcPtr original_crtc;
Richard Hughes2b2092a2013-04-24 14:58:02 +0100148 struct drm_edid edid;
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +0300149 drmModePropertyPtr dpms_prop;
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200150
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300151 int vblank_pending;
152 int page_flip_pending;
Xiong Zhangabd5d472013-10-11 14:43:07 +0800153 int destroy_pending;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300154
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400155 struct gbm_surface *surface;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -0400156 struct gbm_bo *cursor_bo[2];
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400157 struct weston_plane cursor_plane;
158 struct weston_plane fb_plane;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400159 struct weston_surface *cursor_surface;
160 int current_cursor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300161 struct drm_fb *current, *next;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +0200162 struct backlight *backlight;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200163
164 struct drm_fb *dumb[2];
165 pixman_image_t *image[2];
166 int current_image;
167 pixman_region32_t previous_damage;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300168
169 struct vaapi_recorder *recorder;
170 struct wl_listener recorder_frame_listener;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400171};
172
Jesse Barnes58ef3792012-02-23 09:45:49 -0500173/*
174 * An output has a primary display plane plus zero or more sprites for
175 * blending display contents.
176 */
177struct drm_sprite {
178 struct wl_list link;
179
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400180 struct weston_plane plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500181
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200182 struct drm_fb *current, *next;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300183 struct drm_output *output;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500184 struct drm_compositor *compositor;
185
Jesse Barnes58ef3792012-02-23 09:45:49 -0500186 uint32_t possible_crtcs;
187 uint32_t plane_id;
188 uint32_t count_formats;
189
190 int32_t src_x, src_y;
191 uint32_t src_w, src_h;
192 uint32_t dest_x, dest_y;
193 uint32_t dest_w, dest_h;
194
195 uint32_t formats[];
196};
197
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +0300198static struct gl_renderer_interface *gl_renderer;
199
Kristian Høgsberg98cfea62013-02-18 16:15:53 -0500200static const char default_seat[] = "seat0";
Pekka Paalanen33156972012-08-03 13:30:30 -0400201
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400202static void
203drm_output_set_cursor(struct drm_output *output);
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400204
Jesse Barnes58ef3792012-02-23 09:45:49 -0500205static int
Jesse Barnes58ef3792012-02-23 09:45:49 -0500206drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
207{
208 struct weston_compositor *ec = output_base->compositor;
209 struct drm_compositor *c =(struct drm_compositor *) ec;
210 struct drm_output *output = (struct drm_output *) output_base;
211 int crtc;
212
213 for (crtc = 0; crtc < c->num_crtcs; crtc++) {
214 if (c->crtcs[crtc] != output->crtc_id)
215 continue;
216
217 if (supported & (1 << crtc))
218 return -1;
219 }
220
221 return 0;
222}
223
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300224static void
225drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
226{
227 struct drm_fb *fb = data;
228 struct gbm_device *gbm = gbm_bo_get_device(bo);
229
230 if (fb->fb_id)
231 drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
232
Pekka Paalanende685b82012-12-04 15:58:12 +0200233 weston_buffer_reference(&fb->buffer_ref, NULL);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300234
235 free(data);
236}
237
238static struct drm_fb *
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200239drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
240{
241 struct drm_fb *fb;
242 int ret;
243
244 struct drm_mode_create_dumb create_arg;
245 struct drm_mode_destroy_dumb destroy_arg;
246 struct drm_mode_map_dumb map_arg;
247
Peter Huttererf3d62272013-08-08 11:57:05 +1000248 fb = zalloc(sizeof *fb);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200249 if (!fb)
250 return NULL;
251
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700252 memset(&create_arg, 0, sizeof create_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200253 create_arg.bpp = 32;
254 create_arg.width = width;
255 create_arg.height = height;
256
257 ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
258 if (ret)
259 goto err_fb;
260
261 fb->handle = create_arg.handle;
262 fb->stride = create_arg.pitch;
263 fb->size = create_arg.size;
264 fb->fd = ec->drm.fd;
265
266 ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
267 fb->stride, fb->handle, &fb->fb_id);
268 if (ret)
269 goto err_bo;
270
Kristian Høgsbergac6104e2013-08-21 22:14:14 -0700271 memset(&map_arg, 0, sizeof map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200272 map_arg.handle = fb->handle;
Chris Michaeleb2074a2013-05-01 21:26:02 -0400273 ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200274 if (ret)
275 goto err_add_fb;
276
277 fb->map = mmap(0, fb->size, PROT_WRITE,
278 MAP_SHARED, ec->drm.fd, map_arg.offset);
279 if (fb->map == MAP_FAILED)
280 goto err_add_fb;
281
282 return fb;
283
284err_add_fb:
285 drmModeRmFB(ec->drm.fd, fb->fb_id);
286err_bo:
287 memset(&destroy_arg, 0, sizeof(destroy_arg));
288 destroy_arg.handle = create_arg.handle;
289 drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
290err_fb:
291 free(fb);
292 return NULL;
293}
294
295static void
296drm_fb_destroy_dumb(struct drm_fb *fb)
297{
298 struct drm_mode_destroy_dumb destroy_arg;
299
300 if (!fb->map)
301 return;
302
303 if (fb->fb_id)
304 drmModeRmFB(fb->fd, fb->fb_id);
305
306 weston_buffer_reference(&fb->buffer_ref, NULL);
307
308 munmap(fb->map, fb->size);
309
310 memset(&destroy_arg, 0, sizeof(destroy_arg));
311 destroy_arg.handle = fb->handle;
312 drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
313
314 free(fb);
315}
316
317static struct drm_fb *
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500318drm_fb_get_from_bo(struct gbm_bo *bo,
319 struct drm_compositor *compositor, uint32_t format)
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300320{
321 struct drm_fb *fb = gbm_bo_get_user_data(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200322 uint32_t width, height;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200323 uint32_t handles[4], pitches[4], offsets[4];
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300324 int ret;
325
326 if (fb)
327 return fb;
328
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200329 fb = calloc(1, sizeof *fb);
330 if (!fb)
331 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300332
333 fb->bo = bo;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300334
335 width = gbm_bo_get_width(bo);
336 height = gbm_bo_get_height(bo);
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200337 fb->stride = gbm_bo_get_stride(bo);
338 fb->handle = gbm_bo_get_handle(bo).u32;
339 fb->size = fb->stride * height;
340 fb->fd = compositor->drm.fd;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300341
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200342 if (compositor->min_width > width || width > compositor->max_width ||
343 compositor->min_height > height ||
344 height > compositor->max_height) {
345 weston_log("bo geometry out of bounds\n");
346 goto err_free;
347 }
348
349 ret = -1;
350
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200351 if (format && !compositor->no_addfb2) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200352 handles[0] = fb->handle;
353 pitches[0] = fb->stride;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200354 offsets[0] = 0;
355
356 ret = drmModeAddFB2(compositor->drm.fd, width, height,
357 format, handles, pitches, offsets,
358 &fb->fb_id, 0);
359 if (ret) {
360 weston_log("addfb2 failed: %m\n");
361 compositor->no_addfb2 = 1;
362 compositor->sprites_are_broken = 1;
363 }
364 }
365
366 if (ret)
367 ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200368 fb->stride, fb->handle, &fb->fb_id);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200369
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300370 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200371 weston_log("failed to create kms fb: %m\n");
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200372 goto err_free;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300373 }
374
375 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
376
377 return fb;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200378
379err_free:
380 free(fb);
381 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300382}
383
384static void
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500385drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200386{
Pekka Paalanende685b82012-12-04 15:58:12 +0200387 assert(fb->buffer_ref.buffer == NULL);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200388
389 fb->is_client_buffer = 1;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200390
Pekka Paalanende685b82012-12-04 15:58:12 +0200391 weston_buffer_reference(&fb->buffer_ref, buffer);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200392}
393
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200394static void
395drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
396{
397 if (!fb)
398 return;
399
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200400 if (fb->map &&
401 (fb != output->dumb[0] && fb != output->dumb[1])) {
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +0200402 drm_fb_destroy_dumb(fb);
403 } else if (fb->bo) {
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200404 if (fb->is_client_buffer)
405 gbm_bo_destroy(fb->bo);
406 else
407 gbm_surface_release_buffer(output->surface,
408 output->current->bo);
409 }
410}
411
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500412static uint32_t
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200413drm_output_check_scanout_format(struct drm_output *output,
414 struct weston_surface *es, struct gbm_bo *bo)
415{
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200416 uint32_t format;
417 pixman_region32_t r;
418
419 format = gbm_bo_get_format(bo);
420
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500421 switch (format) {
422 case GBM_FORMAT_XRGB8888:
423 return format;
424 case GBM_FORMAT_ARGB8888:
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200425 /* We can only scanout an ARGB buffer if the surface's
426 * opaque region covers the whole output */
427 pixman_region32_init(&r);
428 pixman_region32_subtract(&r, &output->base.region,
429 &es->opaque);
430
431 if (!pixman_region32_not_empty(&r))
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500432 format = GBM_FORMAT_XRGB8888;
433 else
434 format = 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200435
436 pixman_region32_fini(&r);
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200437
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500438 return format;
439 default:
440 return 0;
441 }
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200442}
443
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400444static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400445drm_output_prepare_scanout_surface(struct weston_output *_output,
446 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500447{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400448 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500449 struct drm_compositor *c =
450 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500451 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300452 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500453 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500454
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500455 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200456 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200457 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200458 buffer->width != output->base.current_mode->width ||
459 buffer->height != output->base.current_mode->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200460 output->base.transform != es->buffer_transform ||
461 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400462 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500463
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400464 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700465 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500466
Rob Bradford9b101872012-09-14 23:25:41 +0100467 /* Unable to use the buffer for scanout */
468 if (!bo)
469 return NULL;
470
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500471 format = drm_output_check_scanout_format(output, es, bo);
472 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300473 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400474 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300475 }
476
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500477 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300478 if (!output->next) {
479 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400480 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300481 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500482
Pekka Paalanende685b82012-12-04 15:58:12 +0200483 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500484
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400485 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500486}
487
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500488static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200489drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400490{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200491 struct drm_compositor *c =
492 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300493 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400494
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200495 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400496
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300497 bo = gbm_surface_lock_front_buffer(output->surface);
498 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200499 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400500 return;
501 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300502
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700503 output->next = drm_fb_get_from_bo(bo, c, c->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300504 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200505 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300506 gbm_surface_release_buffer(output->surface, bo);
507 return;
508 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400509}
510
511static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200512drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
513{
514 struct weston_compositor *ec = output->base.compositor;
515 pixman_region32_t total_damage, previous_damage;
516
517 pixman_region32_init(&total_damage);
518 pixman_region32_init(&previous_damage);
519
520 pixman_region32_copy(&previous_damage, damage);
521
522 pixman_region32_union(&total_damage, damage, &output->previous_damage);
523 pixman_region32_copy(&output->previous_damage, &previous_damage);
524
525 output->current_image ^= 1;
526
527 output->next = output->dumb[output->current_image];
528 pixman_renderer_output_set_buffer(&output->base,
529 output->image[output->current_image]);
530
531 ec->renderer->repaint_output(&output->base, &total_damage);
532
533 pixman_region32_fini(&total_damage);
534 pixman_region32_fini(&previous_damage);
535}
536
537static void
538drm_output_render(struct drm_output *output, pixman_region32_t *damage)
539{
540 struct drm_compositor *c =
541 (struct drm_compositor *) output->base.compositor;
542
543 if (c->use_pixman)
544 drm_output_render_pixman(output, damage);
545 else
546 drm_output_render_gl(output, damage);
547
548 pixman_region32_subtract(&c->base.primary_plane.damage,
549 &c->base.primary_plane.damage, damage);
550}
551
552static void
Richard Hughese7299962013-05-01 21:52:12 +0100553drm_output_set_gamma(struct weston_output *output_base,
554 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
555{
556 int rc;
557 struct drm_output *output = (struct drm_output *) output_base;
558 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
559
560 /* check */
561 if (output_base->gamma_size != size)
562 return;
563 if (!output->original_crtc)
564 return;
565
566 rc = drmModeCrtcSetGamma(compositor->drm.fd,
567 output->crtc_id,
568 size, r, g, b);
569 if (rc)
570 weston_log("set gamma failed: %m\n");
571}
572
573static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500574drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400575 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100576{
577 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500578 struct drm_compositor *compositor =
579 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500580 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400581 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500582 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100583
Xiong Zhangabd5d472013-10-11 14:43:07 +0800584 if (output->destroy_pending)
585 return;
586
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300587 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400588 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300589 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400590 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100591
Hardeningff39efa2013-09-18 23:56:35 +0200592 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300593 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400594 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300595 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400596 &output->connector_id, 1,
597 &mode->mode_info);
598 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200599 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400600 return;
601 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300602 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200603 }
604
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500605 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300606 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500607 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200608 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500609 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500610 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100611
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300612 output->page_flip_pending = 1;
613
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400614 drm_output_set_cursor(output);
615
Jesse Barnes58ef3792012-02-23 09:45:49 -0500616 /*
617 * Now, update all the sprite surfaces
618 */
619 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200620 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500621 drmVBlank vbl = {
622 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
623 .request.sequence = 1,
624 };
625
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200626 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200627 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500628 continue;
629
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200630 if (s->next && !compositor->sprites_hidden)
631 fb_id = s->next->fb_id;
632
Jesse Barnes58ef3792012-02-23 09:45:49 -0500633 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200634 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500635 s->dest_x, s->dest_y,
636 s->dest_w, s->dest_h,
637 s->src_x, s->src_y,
638 s->src_w, s->src_h);
639 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200640 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500641 ret, strerror(errno));
642
Rob Clark5ca1a472012-08-08 20:27:37 -0500643 if (output->pipe > 0)
644 vbl.request.type |= DRM_VBLANK_SECONDARY;
645
Jesse Barnes58ef3792012-02-23 09:45:49 -0500646 /*
647 * Queue a vblank signal so we know when the surface
648 * becomes active on the display or has been replaced.
649 */
650 vbl.request.signal = (unsigned long)s;
651 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
652 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200653 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500654 ret, strerror(errno));
655 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300656
657 s->output = output;
658 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500659 }
660
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500661 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400662}
663
664static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200665drm_output_start_repaint_loop(struct weston_output *output_base)
666{
667 struct drm_output *output = (struct drm_output *) output_base;
668 struct drm_compositor *compositor = (struct drm_compositor *)
669 output_base->compositor;
670 uint32_t fb_id;
671
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300672 struct timespec ts;
673
Xiong Zhangabd5d472013-10-11 14:43:07 +0800674 if (output->destroy_pending)
675 return;
676
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300677 if (!output->current) {
678 /* We can't page flip if there's no mode set */
679 uint32_t msec;
680
681 clock_gettime(compositor->clock, &ts);
682 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
683 weston_output_finish_frame(output_base, msec);
684 return;
685 }
686
687 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200688
689 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
690 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
691 weston_log("queueing pageflip failed: %m\n");
692 return;
693 }
694}
695
696static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500697vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
698 void *data)
699{
700 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300701 struct drm_output *output = s->output;
702 uint32_t msecs;
703
704 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500705
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200706 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200707 s->current = s->next;
708 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300709
710 if (!output->page_flip_pending) {
711 msecs = sec * 1000 + usec / 1000;
712 weston_output_finish_frame(&output->base, msecs);
713 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500714}
715
716static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800717drm_output_destroy(struct weston_output *output_base);
718
719static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400720page_flip_handler(int fd, unsigned int frame,
721 unsigned int sec, unsigned int usec, void *data)
722{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200723 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400724 uint32_t msecs;
725
Jonas Ådahle5a12252013-04-05 23:07:11 +0200726 /* We don't set page_flip_pending on start_repaint_loop, in that case
727 * we just want to page flip to the current buffer to get an accurate
728 * timestamp */
729 if (output->page_flip_pending) {
730 drm_output_release_fb(output, output->current);
731 output->current = output->next;
732 output->next = NULL;
733 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300734
Jonas Ådahle5a12252013-04-05 23:07:11 +0200735 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400736
Xiong Zhangabd5d472013-10-11 14:43:07 +0800737 if (output->destroy_pending)
738 drm_output_destroy(&output->base);
739 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300740 msecs = sec * 1000 + usec / 1000;
741 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300742
743 /* We can't call this from frame_notify, because the output's
744 * repaint needed flag is cleared just after that */
745 if (output->recorder)
746 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300747 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200748}
749
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500750static uint32_t
751drm_output_check_sprite_format(struct drm_sprite *s,
752 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500753{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500754 uint32_t i, format;
755
756 format = gbm_bo_get_format(bo);
757
758 if (format == GBM_FORMAT_ARGB8888) {
759 pixman_region32_t r;
760
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500761 pixman_region32_init_rect(&r, 0, 0,
762 es->geometry.width,
763 es->geometry.height);
764 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500765
766 if (!pixman_region32_not_empty(&r))
767 format = GBM_FORMAT_XRGB8888;
768
769 pixman_region32_fini(&r);
770 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500771
772 for (i = 0; i < s->count_formats; i++)
773 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500774 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500775
776 return 0;
777}
778
779static int
780drm_surface_transform_supported(struct weston_surface *es)
781{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500782 return !es->transform.enabled ||
783 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500784}
785
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400786static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500787drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400788 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500789{
790 struct weston_compositor *ec = output_base->compositor;
791 struct drm_compositor *c =(struct drm_compositor *) ec;
792 struct drm_sprite *s;
793 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500794 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500795 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200796 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500797 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400798 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500799
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200800 if (c->gbm == NULL)
801 return NULL;
802
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200803 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200804 return NULL;
805
Hardeningff39efa2013-09-18 23:56:35 +0200806 if (es->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200807 return NULL;
808
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500809 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400810 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500811
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300812 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400813 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300814
Pekka Paalanende685b82012-12-04 15:58:12 +0200815 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400816 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500817
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200818 if (es->alpha != 1.0f)
819 return NULL;
820
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500821 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500822 return NULL;
823
Jesse Barnes58ef3792012-02-23 09:45:49 -0500824 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400825 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500826
Jesse Barnes58ef3792012-02-23 09:45:49 -0500827 wl_list_for_each(s, &c->sprite_list, link) {
828 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
829 continue;
830
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200831 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500832 found = 1;
833 break;
834 }
835 }
836
837 /* No sprites available */
838 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400839 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500840
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400841 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700842 es->buffer_ref.buffer->resource,
843 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400844 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400845 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400846
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500847 format = drm_output_check_sprite_format(s, es, bo);
848 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200849 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400850 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500851 }
852
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200853 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200854 if (!s->next) {
855 gbm_bo_destroy(bo);
856 return NULL;
857 }
858
Pekka Paalanende685b82012-12-04 15:58:12 +0200859 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500860
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400861 box = pixman_region32_extents(&es->transform.boundingbox);
862 s->plane.x = box->x1;
863 s->plane.y = box->y1;
864
Jesse Barnes58ef3792012-02-23 09:45:49 -0500865 /*
866 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200867 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500868 * for us already).
869 */
870 pixman_region32_init(&dest_rect);
871 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
872 &output_base->region);
873 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
874 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200875 tbox = weston_transformed_rect(output_base->width,
876 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200877 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200878 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200879 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200880 s->dest_x = tbox.x1;
881 s->dest_y = tbox.y1;
882 s->dest_w = tbox.x2 - tbox.x1;
883 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500884 pixman_region32_fini(&dest_rect);
885
886 pixman_region32_init(&src_rect);
887 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
888 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500889 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400890
891 weston_surface_from_global_fixed(es,
892 wl_fixed_from_int(box->x1),
893 wl_fixed_from_int(box->y1),
894 &sx1, &sy1);
895 weston_surface_from_global_fixed(es,
896 wl_fixed_from_int(box->x2),
897 wl_fixed_from_int(box->y2),
898 &sx2, &sy2);
899
900 if (sx1 < 0)
901 sx1 = 0;
902 if (sy1 < 0)
903 sy1 = 0;
904 if (sx2 > wl_fixed_from_int(es->geometry.width))
905 sx2 = wl_fixed_from_int(es->geometry.width);
906 if (sy2 > wl_fixed_from_int(es->geometry.height))
907 sy2 = wl_fixed_from_int(es->geometry.height);
908
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200909 tbox.x1 = sx1;
910 tbox.y1 = sy1;
911 tbox.x2 = sx2;
912 tbox.y2 = sy2;
913
914 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
915 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200916 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200917
918 s->src_x = tbox.x1 << 8;
919 s->src_y = tbox.y1 << 8;
920 s->src_w = (tbox.x2 - tbox.x1) << 8;
921 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500922 pixman_region32_fini(&src_rect);
923
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400924 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500925}
926
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400927static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400928drm_output_prepare_cursor_surface(struct weston_output *output_base,
929 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500930{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400931 struct drm_compositor *c =
932 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400933 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400934
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200935 if (c->gbm == NULL)
936 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200937 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
938 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400939 if (output->cursor_surface)
940 return NULL;
941 if (es->output_mask != (1u << output_base->id))
942 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500943 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400944 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200945 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500946 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400947 es->geometry.width > 64 || es->geometry.height > 64)
948 return NULL;
949
950 output->cursor_surface = es;
951
952 return &output->cursor_plane;
953}
954
955static void
956drm_output_set_cursor(struct drm_output *output)
957{
958 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400959 struct drm_compositor *c =
960 (struct drm_compositor *) output->base.compositor;
961 EGLint handle, stride;
962 struct gbm_bo *bo;
963 uint32_t buf[64 * 64];
964 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400965 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500966
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400967 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400968 if (es == NULL) {
969 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
970 return;
971 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500972
Pekka Paalanende685b82012-12-04 15:58:12 +0200973 if (es->buffer_ref.buffer &&
974 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400975 pixman_region32_fini(&output->cursor_plane.damage);
976 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400977 output->current_cursor ^= 1;
978 bo = output->cursor_bo[output->current_cursor];
979 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500980 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
981 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400982 for (i = 0; i < es->geometry.height; i++)
983 memcpy(buf + i * 64, s + i * stride,
984 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500985
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400986 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300987 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400988
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400989 handle = gbm_bo_get_handle(bo).s32;
990 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500991 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300992 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500993 c->cursors_are_broken = 1;
994 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400995 }
996
Hardeningff39efa2013-09-18 23:56:35 +0200997 x = (es->geometry.x - output->base.x) * output->base.current_scale;
998 y = (es->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400999 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -05001000 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001001 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001002 c->cursors_are_broken = 1;
1003 }
1004
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001005 output->cursor_plane.x = x;
1006 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001007 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001008}
1009
Jesse Barnes58ef3792012-02-23 09:45:49 -05001010static void
1011drm_assign_planes(struct weston_output *output)
1012{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001013 struct drm_compositor *c =
1014 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001015 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001016 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001017 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001018
1019 /*
1020 * Find a surface for each sprite in the output using some heuristics:
1021 * 1) size
1022 * 2) frequency of update
1023 * 3) opacity (though some hw might support alpha blending)
1024 * 4) clipping (this can be fixed with color keys)
1025 *
1026 * The idea is to save on blitting since this should save power.
1027 * If we can get a large video surface on the sprite for example,
1028 * the main display surface may not need to update at all, and
1029 * the client buffer can be used directly for the sprite surface
1030 * as we do for flipping full screen surfaces.
1031 */
1032 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001033 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001034 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001035 /* test whether this buffer can ever go into a plane:
1036 * non-shm, or small enough to be a cursor
1037 */
1038 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001039 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001040 (es->geometry.width <= 64 && es->geometry.height <= 64))
1041 es->keep_buffer = 1;
1042 else
1043 es->keep_buffer = 0;
1044
Jesse Barnes58ef3792012-02-23 09:45:49 -05001045 pixman_region32_init(&surface_overlap);
1046 pixman_region32_intersect(&surface_overlap, &overlap,
1047 &es->transform.boundingbox);
1048
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001049 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001050 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001051 next_plane = primary;
1052 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001053 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001054 if (next_plane == NULL)
1055 next_plane = drm_output_prepare_scanout_surface(output, es);
1056 if (next_plane == NULL)
1057 next_plane = drm_output_prepare_overlay_surface(output, es);
1058 if (next_plane == NULL)
1059 next_plane = primary;
1060 weston_surface_move_to_plane(es, next_plane);
1061 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001062 pixman_region32_union(&overlap, &overlap,
1063 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001064
Jesse Barnes58ef3792012-02-23 09:45:49 -05001065 pixman_region32_fini(&surface_overlap);
1066 }
1067 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001068}
1069
Matt Roper361d2ad2011-08-29 13:52:23 -07001070static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001071drm_output_fini_pixman(struct drm_output *output);
1072
1073static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001074drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001075{
1076 struct drm_output *output = (struct drm_output *) output_base;
1077 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001078 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001079 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001080
Xiong Zhangabd5d472013-10-11 14:43:07 +08001081 if (output->page_flip_pending) {
1082 output->destroy_pending = 1;
1083 weston_log("destroy output while page flip pending\n");
1084 return;
1085 }
1086
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001087 if (output->backlight)
1088 backlight_destroy(output->backlight);
1089
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001090 drmModeFreeProperty(output->dpms_prop);
1091
Matt Roper361d2ad2011-08-29 13:52:23 -07001092 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001093 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001094
1095 /* Restore original CRTC state */
1096 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001097 origcrtc->x, origcrtc->y,
1098 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001099 drmModeFreeCrtc(origcrtc);
1100
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001101 c->crtc_allocator &= ~(1 << output->crtc_id);
1102 c->connector_allocator &= ~(1 << output->connector_id);
1103
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001104 if (c->use_pixman) {
1105 drm_output_fini_pixman(output);
1106 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001107 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001108 gbm_surface_destroy(output->surface);
1109 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001110
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001111 weston_plane_release(&output->fb_plane);
1112 weston_plane_release(&output->cursor_plane);
1113
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001114 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001115 wl_list_remove(&output->base.link);
1116
Matt Roper361d2ad2011-08-29 13:52:23 -07001117 free(output);
1118}
1119
Alex Wub7b8bda2012-04-17 17:20:48 +08001120static struct drm_mode *
1121choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1122{
1123 struct drm_mode *tmp_mode = NULL, *mode;
1124
Hardeningff39efa2013-09-18 23:56:35 +02001125 if (output->base.current_mode->width == target_mode->width &&
1126 output->base.current_mode->height == target_mode->height &&
1127 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001128 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001129 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001130
1131 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1132 if (mode->mode_info.hdisplay == target_mode->width &&
1133 mode->mode_info.vdisplay == target_mode->height) {
1134 if (mode->mode_info.vrefresh == target_mode->refresh ||
1135 target_mode->refresh == 0) {
1136 return mode;
1137 } else if (!tmp_mode)
1138 tmp_mode = mode;
1139 }
1140 }
1141
1142 return tmp_mode;
1143}
1144
1145static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001146drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001147static int
1148drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001149
1150static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001151drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1152{
1153 struct drm_output *output;
1154 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001155 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001156
1157 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001158 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001159 return -1;
1160 }
1161
1162 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001163 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001164 return -1;
1165 }
1166
1167 ec = (struct drm_compositor *)output_base->compositor;
1168 output = (struct drm_output *)output_base;
1169 drm_mode = choose_mode (output, mode);
1170
1171 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001172 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001173 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001174 }
1175
Hardeningff39efa2013-09-18 23:56:35 +02001176 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001177 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001178
Hardeningff39efa2013-09-18 23:56:35 +02001179 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001180
Hardeningff39efa2013-09-18 23:56:35 +02001181 output->base.current_mode = &drm_mode->base;
1182 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001183 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1184
Alex Wub7b8bda2012-04-17 17:20:48 +08001185 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001186 drm_output_release_fb(output, output->current);
1187 drm_output_release_fb(output, output->next);
1188 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001189
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001190 if (ec->use_pixman) {
1191 drm_output_fini_pixman(output);
1192 if (drm_output_init_pixman(output, ec) < 0) {
1193 weston_log("failed to init output pixman state with "
1194 "new mode\n");
1195 return -1;
1196 }
1197 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001198 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001199 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001200
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001201 if (drm_output_init_egl(output, ec) < 0) {
1202 weston_log("failed to init output egl state with "
1203 "new mode");
1204 return -1;
1205 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001206 }
1207
Alex Wub7b8bda2012-04-17 17:20:48 +08001208 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001209}
1210
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001211static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001212on_drm_input(int fd, uint32_t mask, void *data)
1213{
1214 drmEventContext evctx;
1215
1216 memset(&evctx, 0, sizeof evctx);
1217 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1218 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001219 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001220 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001221
1222 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001223}
1224
1225static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001226init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001227{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001228 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001229 uint64_t cap;
1230 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001231
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001232 sysnum = udev_device_get_sysnum(device);
1233 if (sysnum)
1234 ec->drm.id = atoi(sysnum);
1235 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001236 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001237 return -1;
1238 }
1239
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001240 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001241 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001242 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001243 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001244 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001245 udev_device_get_devnode(device));
1246 return -1;
1247 }
1248
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001249 weston_log("using %s\n", filename);
1250
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001251 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001252 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001253
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001254 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1255 if (ret == 0 && cap == 1)
1256 ec->clock = CLOCK_MONOTONIC;
1257 else
1258 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001259
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001260 return 0;
1261}
1262
1263static int
1264init_egl(struct drm_compositor *ec)
1265{
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001266 EGLint format;
1267
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001268 gl_renderer = weston_load_module("gl-renderer.so",
1269 "gl_renderer_interface");
1270 if (!gl_renderer)
1271 return -1;
1272
1273 /* GBM will load a dri driver, but even though they need symbols from
1274 * libglapi, in some version of Mesa they are not linked to it. Since
1275 * only the gl-renderer module links to it, the call above won't make
1276 * these symbols globally available, and loading the DRI driver fails.
1277 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1278 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1279
Benjamin Franzke060cf802011-04-30 09:32:11 +02001280 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001281
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001282 if (!ec->gbm)
1283 return -1;
1284
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001285 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001286 if (gl_renderer->create(&ec->base, ec->gbm,
1287 gl_renderer->opaque_attribs, &format) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001288 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001289 return -1;
1290 }
1291
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001292 return 0;
1293}
1294
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001295static int
1296init_pixman(struct drm_compositor *ec)
1297{
1298 return pixman_renderer_init(&ec->base);
1299}
1300
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001301static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001302drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001303{
1304 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001305 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001306
1307 mode = malloc(sizeof *mode);
1308 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001309 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001310
1311 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001312 mode->base.width = info->hdisplay;
1313 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001314
1315 /* Calculate higher precision (mHz) refresh rate */
1316 refresh = (info->clock * 1000000LL / info->htotal +
1317 info->vtotal / 2) / info->vtotal;
1318
1319 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1320 refresh *= 2;
1321 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1322 refresh /= 2;
1323 if (info->vscan > 1)
1324 refresh /= info->vscan;
1325
1326 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001327 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001328
1329 if (info->type & DRM_MODE_TYPE_PREFERRED)
1330 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1331
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001332 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1333
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001334 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001335}
1336
1337static int
1338drm_subpixel_to_wayland(int drm_value)
1339{
1340 switch (drm_value) {
1341 default:
1342 case DRM_MODE_SUBPIXEL_UNKNOWN:
1343 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1344 case DRM_MODE_SUBPIXEL_NONE:
1345 return WL_OUTPUT_SUBPIXEL_NONE;
1346 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1347 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1348 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1349 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1350 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1351 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1352 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1353 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1354 }
1355}
1356
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001357/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001358static uint32_t
1359drm_get_backlight(struct drm_output *output)
1360{
1361 long brightness, max_brightness, norm;
1362
1363 brightness = backlight_get_brightness(output->backlight);
1364 max_brightness = backlight_get_max_brightness(output->backlight);
1365
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001366 /* convert it on a scale of 0 to 255 */
1367 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001368
1369 return (uint32_t) norm;
1370}
1371
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001372/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001373static void
1374drm_set_backlight(struct weston_output *output_base, uint32_t value)
1375{
1376 struct drm_output *output = (struct drm_output *) output_base;
1377 long max_brightness, new_brightness;
1378
1379 if (!output->backlight)
1380 return;
1381
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001382 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001383 return;
1384
1385 max_brightness = backlight_get_max_brightness(output->backlight);
1386
1387 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001388 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001389
1390 backlight_set_brightness(output->backlight, new_brightness);
1391}
1392
1393static drmModePropertyPtr
1394drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1395{
1396 drmModePropertyPtr props;
1397 int i;
1398
1399 for (i = 0; i < connector->count_props; i++) {
1400 props = drmModeGetProperty(fd, connector->props[i]);
1401 if (!props)
1402 continue;
1403
1404 if (!strcmp(props->name, name))
1405 return props;
1406
1407 drmModeFreeProperty(props);
1408 }
1409
1410 return NULL;
1411}
1412
1413static void
1414drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1415{
1416 struct drm_output *output = (struct drm_output *) output_base;
1417 struct weston_compositor *ec = output_base->compositor;
1418 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001419
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001420 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001421 return;
1422
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001423 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1424 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001425}
1426
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001427static const char *connector_type_names[] = {
1428 "None",
1429 "VGA",
1430 "DVI",
1431 "DVI",
1432 "DVI",
1433 "Composite",
1434 "TV",
1435 "LVDS",
1436 "CTV",
1437 "DIN",
1438 "DP",
1439 "HDMI",
1440 "HDMI",
1441 "TV",
1442 "eDP",
1443};
1444
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001445static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001446find_crtc_for_connector(struct drm_compositor *ec,
1447 drmModeRes *resources, drmModeConnector *connector)
1448{
1449 drmModeEncoder *encoder;
1450 uint32_t possible_crtcs;
1451 int i, j;
1452
1453 for (j = 0; j < connector->count_encoders; j++) {
1454 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1455 if (encoder == NULL) {
1456 weston_log("Failed to get encoder.\n");
1457 return -1;
1458 }
1459 possible_crtcs = encoder->possible_crtcs;
1460 drmModeFreeEncoder(encoder);
1461
1462 for (i = 0; i < resources->count_crtcs; i++) {
1463 if (possible_crtcs & (1 << i) &&
1464 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1465 return i;
1466 }
1467 }
1468
1469 return -1;
1470}
1471
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001472/* Init output state that depends on gl or gbm */
1473static int
1474drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1475{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001476 int i, flags;
1477
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001478 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001479 output->base.current_mode->width,
1480 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001481 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001482 GBM_BO_USE_SCANOUT |
1483 GBM_BO_USE_RENDERING);
1484 if (!output->surface) {
1485 weston_log("failed to create gbm surface\n");
1486 return -1;
1487 }
1488
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001489 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001490 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001491 gbm_surface_destroy(output->surface);
1492 return -1;
1493 }
1494
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001495 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1496
1497 for (i = 0; i < 2; i++) {
1498 if (output->cursor_bo[i])
1499 continue;
1500
1501 output->cursor_bo[i] =
1502 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1503 flags);
1504 }
1505
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001506 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1507 weston_log("cursor buffers unavailable, using gl cursors\n");
1508 ec->cursors_are_broken = 1;
1509 }
1510
1511 return 0;
1512}
1513
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001514static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001515drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1516{
Hardeningff39efa2013-09-18 23:56:35 +02001517 int w = output->base.current_mode->width;
1518 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001519 unsigned int i;
1520
1521 /* FIXME error checking */
1522
1523 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001524 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001525 if (!output->dumb[i])
1526 goto err;
1527
1528 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001529 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001530 output->dumb[i]->map,
1531 output->dumb[i]->stride);
1532 if (!output->image[i])
1533 goto err;
1534 }
1535
1536 if (pixman_renderer_output_create(&output->base) < 0)
1537 goto err;
1538
1539 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001540 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001541
1542 return 0;
1543
1544err:
1545 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1546 if (output->dumb[i])
1547 drm_fb_destroy_dumb(output->dumb[i]);
1548 if (output->image[i])
1549 pixman_image_unref(output->image[i]);
1550
1551 output->dumb[i] = NULL;
1552 output->image[i] = NULL;
1553 }
1554
1555 return -1;
1556}
1557
1558static void
1559drm_output_fini_pixman(struct drm_output *output)
1560{
1561 unsigned int i;
1562
1563 pixman_renderer_output_destroy(&output->base);
1564 pixman_region32_fini(&output->previous_damage);
1565
1566 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1567 drm_fb_destroy_dumb(output->dumb[i]);
1568 pixman_image_unref(output->image[i]);
1569 output->dumb[i] = NULL;
1570 output->image[i] = NULL;
1571 }
1572}
1573
Richard Hughes2b2092a2013-04-24 14:58:02 +01001574static void
1575edid_parse_string(const uint8_t *data, char text[])
1576{
1577 int i;
1578 int replaced = 0;
1579
1580 /* this is always 12 bytes, but we can't guarantee it's null
1581 * terminated or not junk. */
1582 strncpy(text, (const char *) data, 12);
1583
1584 /* remove insane chars */
1585 for (i = 0; text[i] != '\0'; i++) {
1586 if (text[i] == '\n' ||
1587 text[i] == '\r') {
1588 text[i] = '\0';
1589 break;
1590 }
1591 }
1592
1593 /* ensure string is printable */
1594 for (i = 0; text[i] != '\0'; i++) {
1595 if (!isprint(text[i])) {
1596 text[i] = '-';
1597 replaced++;
1598 }
1599 }
1600
1601 /* if the string is random junk, ignore the string */
1602 if (replaced > 4)
1603 text[0] = '\0';
1604}
1605
1606#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1607#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1608#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1609#define EDID_OFFSET_DATA_BLOCKS 0x36
1610#define EDID_OFFSET_LAST_BLOCK 0x6c
1611#define EDID_OFFSET_PNPID 0x08
1612#define EDID_OFFSET_SERIAL 0x0c
1613
1614static int
1615edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1616{
1617 int i;
1618 uint32_t serial_number;
1619
1620 /* check header */
1621 if (length < 128)
1622 return -1;
1623 if (data[0] != 0x00 || data[1] != 0xff)
1624 return -1;
1625
1626 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1627 * /--08--\/--09--\
1628 * 7654321076543210
1629 * |\---/\---/\---/
1630 * R C1 C2 C3 */
1631 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1632 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1633 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1634 edid->pnp_id[3] = '\0';
1635
1636 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1637 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1638 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1639 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1640 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1641 if (serial_number > 0)
1642 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1643
1644 /* parse EDID data */
1645 for (i = EDID_OFFSET_DATA_BLOCKS;
1646 i <= EDID_OFFSET_LAST_BLOCK;
1647 i += 18) {
1648 /* ignore pixel clock data */
1649 if (data[i] != 0)
1650 continue;
1651 if (data[i+2] != 0)
1652 continue;
1653
1654 /* any useful blocks? */
1655 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1656 edid_parse_string(&data[i+5],
1657 edid->monitor_name);
1658 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1659 edid_parse_string(&data[i+5],
1660 edid->serial_number);
1661 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1662 edid_parse_string(&data[i+5],
1663 edid->eisa_id);
1664 }
1665 }
1666 return 0;
1667}
1668
1669static void
1670find_and_parse_output_edid(struct drm_compositor *ec,
1671 struct drm_output *output,
1672 drmModeConnector *connector)
1673{
1674 drmModePropertyBlobPtr edid_blob = NULL;
1675 drmModePropertyPtr property;
1676 int i;
1677 int rc;
1678
1679 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1680 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1681 if (!property)
1682 continue;
1683 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1684 !strcmp(property->name, "EDID")) {
1685 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1686 connector->prop_values[i]);
1687 }
1688 drmModeFreeProperty(property);
1689 }
1690 if (!edid_blob)
1691 return;
1692
1693 rc = edid_parse(&output->edid,
1694 edid_blob->data,
1695 edid_blob->length);
1696 if (!rc) {
1697 weston_log("EDID data '%s', '%s', '%s'\n",
1698 output->edid.pnp_id,
1699 output->edid.monitor_name,
1700 output->edid.serial_number);
1701 if (output->edid.pnp_id[0] != '\0')
1702 output->base.make = output->edid.pnp_id;
1703 if (output->edid.monitor_name[0] != '\0')
1704 output->base.model = output->edid.monitor_name;
1705 if (output->edid.serial_number[0] != '\0')
1706 output->base.serial_number = output->edid.serial_number;
1707 }
1708 drmModeFreePropertyBlob(edid_blob);
1709}
1710
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001711
1712
1713static int
1714parse_modeline(const char *s, drmModeModeInfo *mode)
1715{
1716 char hsync[16];
1717 char vsync[16];
1718 float fclock;
1719
1720 mode->type = DRM_MODE_TYPE_USERDEF;
1721 mode->hskew = 0;
1722 mode->vscan = 0;
1723 mode->vrefresh = 0;
1724 mode->flags = 0;
1725
Rob Bradford307e09e2013-07-26 16:29:40 +01001726 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001727 &fclock,
1728 &mode->hdisplay,
1729 &mode->hsync_start,
1730 &mode->hsync_end,
1731 &mode->htotal,
1732 &mode->vdisplay,
1733 &mode->vsync_start,
1734 &mode->vsync_end,
1735 &mode->vtotal, hsync, vsync) != 11)
1736 return -1;
1737
1738 mode->clock = fclock * 1000;
1739 if (strcmp(hsync, "+hsync") == 0)
1740 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1741 else if (strcmp(hsync, "-hsync") == 0)
1742 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1743 else
1744 return -1;
1745
1746 if (strcmp(vsync, "+vsync") == 0)
1747 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1748 else if (strcmp(vsync, "-vsync") == 0)
1749 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1750 else
1751 return -1;
1752
1753 return 0;
1754}
1755
1756static uint32_t
1757parse_transform(const char *transform, const char *output_name)
1758{
1759 static const struct { const char *name; uint32_t token; } names[] = {
1760 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1761 { "90", WL_OUTPUT_TRANSFORM_90 },
1762 { "180", WL_OUTPUT_TRANSFORM_180 },
1763 { "270", WL_OUTPUT_TRANSFORM_270 },
1764 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1765 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1766 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1767 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1768 };
1769 unsigned int i;
1770
1771 for (i = 0; i < ARRAY_LENGTH(names); i++)
1772 if (strcmp(names[i].name, transform) == 0)
1773 return names[i].token;
1774
1775 weston_log("Invalid transform \"%s\" for output %s\n",
1776 transform, output_name);
1777
1778 return WL_OUTPUT_TRANSFORM_NORMAL;
1779}
1780
Rob Bradford66bd9f52013-06-25 18:56:42 +01001781static void
1782setup_output_seat_constraint(struct drm_compositor *ec,
1783 struct weston_output *output,
1784 const char *s)
1785{
1786 if (strcmp(s, "") != 0) {
1787 struct udev_seat *seat;
1788
1789 seat = udev_seat_get_named(&ec->base, s);
1790 if (seat)
1791 seat->base.output = output;
1792
1793 if (seat && seat->base.pointer)
1794 weston_pointer_clamp(seat->base.pointer,
1795 &seat->base.pointer->x,
1796 &seat->base.pointer->y);
1797 }
1798}
1799
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001800static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001801create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001802 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001803 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001804 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001805{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001806 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001807 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1808 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001809 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001810 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001811 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001812 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001813 int i, width, height, scale;
1814 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001815 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001816 enum output_config config;
1817 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001818
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001819 i = find_crtc_for_connector(ec, resources, connector);
1820 if (i < 0) {
1821 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001822 return -1;
1823 }
1824
Peter Huttererf3d62272013-08-08 11:57:05 +10001825 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001826 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001827 return -1;
1828
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001829 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1830 output->base.make = "unknown";
1831 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001832 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001833 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001834
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001835 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1836 type_name = connector_type_names[connector->connector_type];
1837 else
1838 type_name = "UNKNOWN";
1839 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001840 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001841
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001842 section = weston_config_get_section(ec->base.config, "output", "name",
1843 output->base.name);
1844 weston_config_section_get_string(section, "mode", &s, "preferred");
1845 if (strcmp(s, "off") == 0)
1846 config = OUTPUT_CONFIG_OFF;
1847 else if (strcmp(s, "preferred") == 0)
1848 config = OUTPUT_CONFIG_PREFERRED;
1849 else if (strcmp(s, "current") == 0)
1850 config = OUTPUT_CONFIG_CURRENT;
1851 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1852 config = OUTPUT_CONFIG_MODE;
1853 else if (parse_modeline(s, &modeline) == 0)
1854 config = OUTPUT_CONFIG_MODELINE;
1855 else {
1856 weston_log("Invalid mode \"%s\" for output %s\n",
1857 s, output->base.name);
1858 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001859 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001860 free(s);
1861
1862 weston_config_section_get_int(section, "scale", &scale, 1);
1863 weston_config_section_get_string(section, "transform", &s, "normal");
1864 transform = parse_transform(s, output->base.name);
1865 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001866
Rob Bradford66bd9f52013-06-25 18:56:42 +01001867 weston_config_section_get_string(section, "seat", &s, "");
1868 setup_output_seat_constraint(ec, &output->base, s);
1869 free(s);
1870
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001871 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001872 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001873 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001874 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001875 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001876
Matt Roper361d2ad2011-08-29 13:52:23 -07001877 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001878 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001879
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001880 /* Get the current mode on the crtc that's currently driving
1881 * this connector. */
1882 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001883 memset(&crtc_mode, 0, sizeof crtc_mode);
1884 if (encoder != NULL) {
1885 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1886 drmModeFreeEncoder(encoder);
1887 if (crtc == NULL)
1888 goto err_free;
1889 if (crtc->mode_valid)
1890 crtc_mode = crtc->mode;
1891 drmModeFreeCrtc(crtc);
1892 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001893
David Herrmann0f0d54e2011-12-08 17:05:45 +01001894 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001895 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001896 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001897 goto err_free;
1898 }
1899
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001900 if (config == OUTPUT_CONFIG_OFF) {
1901 weston_log("Disabling output %s\n", output->base.name);
1902 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1903 0, 0, 0, 0, 0, NULL);
1904 goto err_free;
1905 }
1906
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001907 preferred = NULL;
1908 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001909 configured = NULL;
1910
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001911 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001912 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001913 width == drm_mode->base.width &&
1914 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001915 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001916 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001917 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001918 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001919 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001920 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001921
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001922 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001923 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001924 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001925 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001926 }
1927
Wang Quanxianacb805a2012-07-30 18:09:46 -04001928 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001929 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001930 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001931 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001932 }
1933
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001934 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001935 configured = current;
1936
Wang Quanxianacb805a2012-07-30 18:09:46 -04001937 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001938 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001939 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001940 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001941 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001942 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001943 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001944 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001945
Hardeningff39efa2013-09-18 23:56:35 +02001946 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001947 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001948 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001949 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001950
Hardeningff39efa2013-09-18 23:56:35 +02001951 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001952
John Kåre Alsaker94659272012-11-13 19:10:18 +01001953 weston_output_init(&output->base, &ec->base, x, y,
1954 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001955 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001956
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001957 if (ec->use_pixman) {
1958 if (drm_output_init_pixman(output, ec) < 0) {
1959 weston_log("Failed to init output pixman state\n");
1960 goto err_output;
1961 }
1962 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001963 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001964 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001965 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001966
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001967 output->backlight = backlight_init(drm_device,
1968 connector->connector_type);
1969 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001970 weston_log("Initialized backlight, device %s\n",
1971 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001972 output->base.set_backlight = drm_set_backlight;
1973 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001974 } else {
1975 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001976 }
1977
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001978 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1979
Richard Hughes2b2092a2013-04-24 14:58:02 +01001980 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001981 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1982 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001983
Jonas Ådahle5a12252013-04-05 23:07:11 +02001984 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001985 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001986 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001987 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001988 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001989 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001990
Richard Hughese7299962013-05-01 21:52:12 +01001991 output->base.gamma_size = output->original_crtc->gamma_size;
1992 output->base.set_gamma = drm_output_set_gamma;
1993
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001994 weston_plane_init(&output->cursor_plane, 0, 0);
1995 weston_plane_init(&output->fb_plane, 0, 0);
1996
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001997 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1998 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1999 &ec->base.primary_plane);
2000
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002001 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002002 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002003 wl_list_for_each(m, &output->base.mode_list, link)
2004 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
2005 m->width, m->height, m->refresh / 1000.0,
2006 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2007 ", preferred" : "",
2008 m->flags & WL_OUTPUT_MODE_CURRENT ?
2009 ", current" : "",
2010 connector->count_modes == 0 ?
2011 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002012
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002013 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002014
John Kåre Alsaker94659272012-11-13 19:10:18 +01002015err_output:
2016 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002017err_free:
2018 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2019 base.link) {
2020 wl_list_remove(&drm_mode->base.link);
2021 free(drm_mode);
2022 }
2023
2024 drmModeFreeCrtc(output->original_crtc);
2025 ec->crtc_allocator &= ~(1 << output->crtc_id);
2026 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002027 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002028
David Herrmann0f0d54e2011-12-08 17:05:45 +01002029 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002030}
2031
Jesse Barnes58ef3792012-02-23 09:45:49 -05002032static void
2033create_sprites(struct drm_compositor *ec)
2034{
2035 struct drm_sprite *sprite;
2036 drmModePlaneRes *plane_res;
2037 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002038 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002039
2040 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2041 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002042 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002043 strerror(errno));
2044 return;
2045 }
2046
2047 for (i = 0; i < plane_res->count_planes; i++) {
2048 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2049 if (!plane)
2050 continue;
2051
Peter Huttererf3d62272013-08-08 11:57:05 +10002052 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002053 plane->count_formats));
2054 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002055 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002056 __func__);
2057 free(plane);
2058 continue;
2059 }
2060
Jesse Barnes58ef3792012-02-23 09:45:49 -05002061 sprite->possible_crtcs = plane->possible_crtcs;
2062 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002063 sprite->current = NULL;
2064 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002065 sprite->compositor = ec;
2066 sprite->count_formats = plane->count_formats;
2067 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002068 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002069 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002070 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002071 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2072 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002073
2074 wl_list_insert(&ec->sprite_list, &sprite->link);
2075 }
2076
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002077 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002078}
2079
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002080static void
2081destroy_sprites(struct drm_compositor *compositor)
2082{
2083 struct drm_sprite *sprite, *next;
2084 struct drm_output *output;
2085
2086 output = container_of(compositor->base.output_list.next,
2087 struct drm_output, base.link);
2088
2089 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2090 drmModeSetPlane(compositor->drm.fd,
2091 sprite->plane_id,
2092 output->crtc_id, 0, 0,
2093 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002094 drm_output_release_fb(output, sprite->current);
2095 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002096 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002097 free(sprite);
2098 }
2099}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002100
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002101static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002102create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002103 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002104{
2105 drmModeConnector *connector;
2106 drmModeRes *resources;
2107 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002108 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002109
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002110 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002111 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002112 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002113 return -1;
2114 }
2115
Jesse Barnes58ef3792012-02-23 09:45:49 -05002116 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002117 if (!ec->crtcs) {
2118 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002119 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002120 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002121
Rob Clark4339add2012-08-09 14:18:28 -05002122 ec->min_width = resources->min_width;
2123 ec->max_width = resources->max_width;
2124 ec->min_height = resources->min_height;
2125 ec->max_height = resources->max_height;
2126
Jesse Barnes58ef3792012-02-23 09:45:49 -05002127 ec->num_crtcs = resources->count_crtcs;
2128 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2129
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002130 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002131 connector = drmModeGetConnector(ec->drm.fd,
2132 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002133 if (connector == NULL)
2134 continue;
2135
2136 if (connector->connection == DRM_MODE_CONNECTED &&
2137 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002138 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002139 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002140 connector, x, y,
2141 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002142 drmModeFreeConnector(connector);
2143 continue;
2144 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002145
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002146 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002147 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002148 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002149 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002150
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002151 drmModeFreeConnector(connector);
2152 }
2153
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002154 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002155 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002156 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002157 return -1;
2158 }
2159
2160 drmModeFreeResources(resources);
2161
2162 return 0;
2163}
2164
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002165static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002166update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002167{
2168 drmModeConnector *connector;
2169 drmModeRes *resources;
2170 struct drm_output *output, *next;
2171 int x = 0, y = 0;
2172 int x_offset = 0, y_offset = 0;
2173 uint32_t connected = 0, disconnects = 0;
2174 int i;
2175
2176 resources = drmModeGetResources(ec->drm.fd);
2177 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002178 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002179 return;
2180 }
2181
2182 /* collect new connects */
2183 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002184 int connector_id = resources->connectors[i];
2185
2186 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002187 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002188 continue;
2189
David Herrmann7551cff2011-12-08 17:05:43 +01002190 if (connector->connection != DRM_MODE_CONNECTED) {
2191 drmModeFreeConnector(connector);
2192 continue;
2193 }
2194
Benjamin Franzke117483d2011-08-30 11:38:26 +02002195 connected |= (1 << connector_id);
2196
2197 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002198 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002199 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002200 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002201
2202 /* XXX: not yet needed, we die with 0 outputs */
2203 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002204 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002205 else
2206 x = 0;
2207 y = 0;
2208 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002209 connector, x, y,
2210 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002211 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002212
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002213 }
2214 drmModeFreeConnector(connector);
2215 }
2216 drmModeFreeResources(resources);
2217
2218 disconnects = ec->connector_allocator & ~connected;
2219 if (disconnects) {
2220 wl_list_for_each_safe(output, next, &ec->base.output_list,
2221 base.link) {
2222 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002223 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002224 output->base.x - x_offset,
2225 output->base.y - y_offset);
2226 }
2227
2228 if (disconnects & (1 << output->connector_id)) {
2229 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002230 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002231 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002232 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002233 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002234 }
2235 }
2236 }
2237
2238 /* FIXME: handle zero outputs, without terminating */
2239 if (ec->connector_allocator == 0)
2240 wl_display_terminate(ec->base.wl_display);
2241}
2242
2243static int
David Herrmannd7488c22012-03-11 20:05:21 +01002244udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002245{
David Herrmannd7488c22012-03-11 20:05:21 +01002246 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002247 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002248
2249 sysnum = udev_device_get_sysnum(device);
2250 if (!sysnum || atoi(sysnum) != ec->drm.id)
2251 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002252
David Herrmann6ac52db2012-03-11 20:05:22 +01002253 val = udev_device_get_property_value(device, "HOTPLUG");
2254 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002255 return 0;
2256
David Herrmann6ac52db2012-03-11 20:05:22 +01002257 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002258}
2259
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002260static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002261udev_drm_event(int fd, uint32_t mask, void *data)
2262{
2263 struct drm_compositor *ec = data;
2264 struct udev_device *event;
2265
2266 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002267
David Herrmannd7488c22012-03-11 20:05:21 +01002268 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002269 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002270
2271 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002272
2273 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002274}
2275
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002276static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002277drm_restore(struct weston_compositor *ec)
2278{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002279 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002280}
2281
2282static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002283drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002284{
2285 struct drm_compositor *d = (struct drm_compositor *) ec;
2286
Rob Bradfordd355b802013-05-31 18:09:55 +01002287 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002288
2289 wl_event_source_remove(d->udev_drm_source);
2290 wl_event_source_remove(d->drm_source);
2291
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002292 destroy_sprites(d);
2293
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002294 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002295
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002296 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002297
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002298 if (d->gbm)
2299 gbm_device_destroy(d->gbm);
2300
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002301 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002302
Rob Bradford45c15b82013-07-26 16:29:35 +01002303 close(d->drm.fd);
2304
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002305 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002306}
2307
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002308static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002309drm_compositor_set_modes(struct drm_compositor *compositor)
2310{
2311 struct drm_output *output;
2312 struct drm_mode *drm_mode;
2313 int ret;
2314
2315 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002316 if (!output->current) {
2317 /* If something that would cause the output to
2318 * switch mode happened while in another vt, we
2319 * might not have a current drm_fb. In that case,
2320 * schedule a repaint and let drm_output_repaint
2321 * handle setting the mode. */
2322 weston_output_schedule_repaint(&output->base);
2323 continue;
2324 }
2325
Hardeningff39efa2013-09-18 23:56:35 +02002326 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002327 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002328 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002329 &output->connector_id, 1,
2330 &drm_mode->mode_info);
2331 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002332 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002333 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002334 drm_mode->base.width, drm_mode->base.height,
2335 output->base.x, output->base.y);
2336 }
2337 }
2338}
2339
2340static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002341session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002342{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002343 struct weston_compositor *compositor = data;
2344 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002345 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002346 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002347
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002348 if (ec->base.session_active) {
2349 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002350 compositor->focus = 1;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002351 if (ec->base.launcher == NULL && drmSetMaster(ec->drm.fd)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002352 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002353 wl_display_terminate(compositor->wl_display);
2354 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002355 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002356 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002357 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002358 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002359 } else {
2360 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002361 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002362
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002363 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002364 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002365 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002366
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002367 /* If we have a repaint scheduled (either from a
2368 * pending pageflip or the idle handler), make sure we
2369 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002370 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002371 * further attemps at repainting. When we switch
2372 * back, we schedule a repaint, which will process
2373 * pending frame callbacks. */
2374
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002375 wl_list_for_each(output, &ec->base.output_list, base.link) {
2376 output->base.repaint_needed = 0;
2377 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002378 }
2379
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002380 output = container_of(ec->base.output_list.next,
2381 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002382
2383 wl_list_for_each(sprite, &ec->sprite_list, link)
2384 drmModeSetPlane(ec->drm.fd,
2385 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002386 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002387 0, 0, 0, 0, 0, 0, 0, 0);
2388
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002389 if (ec->base.launcher == NULL && drmDropMaster(ec->drm.fd) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002390 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002391 };
2392}
2393
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002394static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002395switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002396{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002397 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002398
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002399 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002400}
2401
David Herrmann0af066f2012-10-29 19:21:16 +01002402/*
2403 * Find primary GPU
2404 * Some systems may have multiple DRM devices attached to a single seat. This
2405 * function loops over all devices and tries to find a PCI device with the
2406 * boot_vga sysfs attribute set to 1.
2407 * If no such device is found, the first DRM device reported by udev is used.
2408 */
2409static struct udev_device*
2410find_primary_gpu(struct drm_compositor *ec, const char *seat)
2411{
2412 struct udev_enumerate *e;
2413 struct udev_list_entry *entry;
2414 const char *path, *device_seat, *id;
2415 struct udev_device *device, *drm_device, *pci;
2416
2417 e = udev_enumerate_new(ec->udev);
2418 udev_enumerate_add_match_subsystem(e, "drm");
2419 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2420
2421 udev_enumerate_scan_devices(e);
2422 drm_device = NULL;
2423 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2424 path = udev_list_entry_get_name(entry);
2425 device = udev_device_new_from_syspath(ec->udev, path);
2426 if (!device)
2427 continue;
2428 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2429 if (!device_seat)
2430 device_seat = default_seat;
2431 if (strcmp(device_seat, seat)) {
2432 udev_device_unref(device);
2433 continue;
2434 }
2435
2436 pci = udev_device_get_parent_with_subsystem_devtype(device,
2437 "pci", NULL);
2438 if (pci) {
2439 id = udev_device_get_sysattr_value(pci, "boot_vga");
2440 if (id && !strcmp(id, "1")) {
2441 if (drm_device)
2442 udev_device_unref(drm_device);
2443 drm_device = device;
2444 break;
2445 }
2446 }
2447
2448 if (!drm_device)
2449 drm_device = device;
2450 else
2451 udev_device_unref(device);
2452 }
2453
2454 udev_enumerate_unref(e);
2455 return drm_device;
2456}
2457
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002458static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002459planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002460{
2461 struct drm_compositor *c = data;
2462
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002463 switch (key) {
2464 case KEY_C:
2465 c->cursors_are_broken ^= 1;
2466 break;
2467 case KEY_V:
2468 c->sprites_are_broken ^= 1;
2469 break;
2470 case KEY_O:
2471 c->sprites_hidden ^= 1;
2472 break;
2473 default:
2474 break;
2475 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002476}
2477
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002478#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002479static void
2480recorder_frame_notify(struct wl_listener *listener, void *data)
2481{
2482 struct drm_output *output;
2483 struct drm_compositor *c;
2484 int fd, ret;
2485
2486 output = container_of(listener, struct drm_output,
2487 recorder_frame_listener);
2488 c = (struct drm_compositor *) output->base.compositor;
2489
2490 if (!output->recorder)
2491 return;
2492
2493 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2494 DRM_CLOEXEC, &fd);
2495 if (ret) {
2496 weston_log("[libva recorder] "
2497 "failed to create prime fd for front buffer\n");
2498 return;
2499 }
2500
2501 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002502}
2503
2504static void *
2505create_recorder(struct drm_compositor *c, int width, int height,
2506 const char *filename)
2507{
2508 int fd;
2509 drm_magic_t magic;
2510
2511 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2512 if (fd < 0)
2513 return NULL;
2514
2515 drmGetMagic(fd, &magic);
2516 drmAuthMagic(c->drm.fd, magic);
2517
2518 return vaapi_recorder_create(fd, width, height, filename);
2519}
2520
2521static void
2522recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2523 void *data)
2524{
2525 struct drm_compositor *c = data;
2526 struct drm_output *output;
2527 int width, height;
2528
2529 output = container_of(c->base.output_list.next,
2530 struct drm_output, base.link);
2531
2532 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002533 width = output->base.current_mode->width;
2534 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002535
2536 output->recorder =
2537 create_recorder(c, width, height, "capture.h264");
2538 if (!output->recorder) {
2539 weston_log("failed to create vaapi recorder\n");
2540 return;
2541 }
2542
2543 output->base.disable_planes++;
2544
2545 output->recorder_frame_listener.notify = recorder_frame_notify;
2546 wl_signal_add(&output->base.frame_signal,
2547 &output->recorder_frame_listener);
2548
2549 weston_output_schedule_repaint(&output->base);
2550
2551 weston_log("[libva recorder] initialized\n");
2552 } else {
2553 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002554 output->recorder = NULL;
2555
2556 output->base.disable_planes--;
2557
2558 wl_list_remove(&output->recorder_frame_listener.link);
2559 weston_log("[libva recorder] done\n");
2560 }
2561}
2562#else
2563static void
2564recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2565 void *data)
2566{
2567 weston_log("Compiled without libva support\n");
2568}
2569#endif
2570
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002571static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002572drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002573 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002574 int *argc, char *argv[],
2575 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002576{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002577 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002578 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002579 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002580 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002581 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002582
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002583 weston_log("initializing drm backend\n");
2584
Peter Huttererf3d62272013-08-08 11:57:05 +10002585 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002586 if (ec == NULL)
2587 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002588
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002589 /* KMS support for sprites is not complete yet, so disable the
2590 * functionality for now. */
2591 ec->sprites_are_broken = 1;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07002592 ec->format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002593 ec->use_pixman = pixman;
2594
Daniel Stone725c2c32012-06-22 14:04:36 +01002595 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002596 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002597 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002598 goto err_base;
2599 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002600
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002601 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg6ff3ff52013-10-02 10:53:33 -07002602 ec->base.launcher = weston_launcher_connect(&ec->base, tty);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002603 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002604 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002605 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002606 goto err_compositor;
2607 }
2608
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002609 ec->udev = udev_new();
2610 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002611 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002612 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002613 }
2614
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002615 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002616 ec->session_listener.notify = session_notify;
2617 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002618
Rob Bradford643641d2013-05-31 18:09:53 +01002619 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002620 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002621 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002622 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002623 }
David Herrmann0af066f2012-10-29 19:21:16 +01002624 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002625
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002626 if (init_drm(ec, drm_device) < 0) {
2627 weston_log("failed to initialize kms\n");
2628 goto err_udev_dev;
2629 }
2630
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002631 if (ec->use_pixman) {
2632 if (init_pixman(ec) < 0) {
2633 weston_log("failed to initialize pixman renderer\n");
2634 goto err_udev_dev;
2635 }
2636 } else {
2637 if (init_egl(ec) < 0) {
2638 weston_log("failed to initialize egl\n");
2639 goto err_udev_dev;
2640 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002641 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002642
2643 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002644 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002645
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002646 ec->base.focus = 1;
2647
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002648 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002649
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002650 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002651 weston_compositor_add_key_binding(&ec->base, key,
2652 MODIFIER_CTRL | MODIFIER_ALT,
2653 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002654
Jesse Barnes58ef3792012-02-23 09:45:49 -05002655 wl_list_init(&ec->sprite_list);
2656 create_sprites(ec);
2657
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002658 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002659 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002660 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002661 }
2662
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002663 path = NULL;
2664
Rob Bradfordd355b802013-05-31 18:09:55 +01002665 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002666 weston_log("failed to create input devices\n");
2667 goto err_sprite;
2668 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002669
2670 loop = wl_display_get_event_loop(ec->base.wl_display);
2671 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002672 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002673 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002674
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002675 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2676 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002677 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002678 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002679 }
2680 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2681 "drm", NULL);
2682 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002683 wl_event_loop_add_fd(loop,
2684 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002685 WL_EVENT_READABLE, udev_drm_event, ec);
2686
2687 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002688 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002689 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002690 }
2691
Daniel Stonea96b93c2012-06-22 14:04:37 +01002692 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002693
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002694 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002695 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002696 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002697 planes_binding, ec);
2698 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2699 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002700 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2701 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002702
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002703 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002704
2705err_udev_monitor:
2706 wl_event_source_remove(ec->udev_drm_source);
2707 udev_monitor_unref(ec->udev_monitor);
2708err_drm_source:
2709 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002710 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002711err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002712 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002713 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002714 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002715err_udev_dev:
2716 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002717err_launcher:
2718 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002719err_udev:
2720 udev_unref(ec->udev);
2721err_compositor:
2722 weston_compositor_shutdown(&ec->base);
2723err_base:
2724 free(ec);
2725 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002726}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002727
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002728WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002729backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002730 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002731{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002732 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002733 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002734
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002735 const struct weston_option drm_options[] = {
2736 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002737 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002738 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002739 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002740 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002741 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002742
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002743 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002744
Rob Bradford643641d2013-05-31 18:09:53 +01002745 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002746 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002747}