blob: 26f7600039f921a6d9a1bccc1c1b888f47829a36 [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{
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700416 struct drm_compositor *c =
417 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200418 uint32_t format;
419 pixman_region32_t r;
420
421 format = gbm_bo_get_format(bo);
422
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700423 if (format == GBM_FORMAT_ARGB8888) {
424 /* We can scanout an ARGB buffer if the surface's
425 * opaque region covers the whole output, but we have
426 * to use XRGB as the KMS format code. */
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200427 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;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200433
434 pixman_region32_fini(&r);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500435 }
Kristian Høgsberg3f97b342013-10-16 16:08:57 -0700436
437 if (c->format == format)
438 return format;
439
440 return 0;
Ander Conselvan de Oliveirae9209412012-11-30 17:34:22 +0200441}
442
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400443static struct weston_plane *
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400444drm_output_prepare_scanout_surface(struct weston_output *_output,
445 struct weston_surface *es)
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500446{
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400447 struct drm_output *output = (struct drm_output *) _output;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500448 struct drm_compositor *c =
449 (struct drm_compositor *) output->base.compositor;
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500450 struct weston_buffer *buffer = es->buffer_ref.buffer;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300451 struct gbm_bo *bo;
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500452 uint32_t format;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500453
Kristian Høgsberg101cb652012-02-17 10:45:16 -0500454 if (es->geometry.x != output->base.x ||
Pekka Paalanenba3cf952012-01-25 16:22:05 +0200455 es->geometry.y != output->base.y ||
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200456 buffer == NULL || c->gbm == NULL ||
Hardeningff39efa2013-09-18 23:56:35 +0200457 buffer->width != output->base.current_mode->width ||
458 buffer->height != output->base.current_mode->height ||
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200459 output->base.transform != es->buffer_transform ||
460 es->transform.enabled)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400461 return NULL;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500462
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400463 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700464 buffer->resource, GBM_BO_USE_SCANOUT);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500465
Rob Bradford9b101872012-09-14 23:25:41 +0100466 /* Unable to use the buffer for scanout */
467 if (!bo)
468 return NULL;
469
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500470 format = drm_output_check_scanout_format(output, es, bo);
471 if (format == 0) {
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300472 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400473 return NULL;
Ander Conselvan de Oliveiraa64b15d2012-05-02 16:42:22 +0300474 }
475
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500476 output->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300477 if (!output->next) {
478 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400479 return NULL;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300480 }
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500481
Pekka Paalanende685b82012-12-04 15:58:12 +0200482 drm_fb_set_buffer(output->next, buffer);
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500483
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400484 return &output->fb_plane;
Kristian Høgsberg5f5e42e2012-01-25 23:59:42 -0500485}
486
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500487static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200488drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400489{
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200490 struct drm_compositor *c =
491 (struct drm_compositor *) output->base.compositor;
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300492 struct gbm_bo *bo;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400493
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200494 c->base.renderer->repaint_output(&output->base, damage);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400495
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300496 bo = gbm_surface_lock_front_buffer(output->surface);
497 if (!bo) {
Martin Minarik6d118362012-06-07 18:01:59 +0200498 weston_log("failed to lock front buffer: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400499 return;
500 }
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300501
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -0700502 output->next = drm_fb_get_from_bo(bo, c, c->format);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300503 if (!output->next) {
Martin Minarik6d118362012-06-07 18:01:59 +0200504 weston_log("failed to get drm_fb for bo\n");
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300505 gbm_surface_release_buffer(output->surface, bo);
506 return;
507 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400508}
509
510static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200511drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
512{
513 struct weston_compositor *ec = output->base.compositor;
514 pixman_region32_t total_damage, previous_damage;
515
516 pixman_region32_init(&total_damage);
517 pixman_region32_init(&previous_damage);
518
519 pixman_region32_copy(&previous_damage, damage);
520
521 pixman_region32_union(&total_damage, damage, &output->previous_damage);
522 pixman_region32_copy(&output->previous_damage, &previous_damage);
523
524 output->current_image ^= 1;
525
526 output->next = output->dumb[output->current_image];
527 pixman_renderer_output_set_buffer(&output->base,
528 output->image[output->current_image]);
529
530 ec->renderer->repaint_output(&output->base, &total_damage);
531
532 pixman_region32_fini(&total_damage);
533 pixman_region32_fini(&previous_damage);
534}
535
536static void
537drm_output_render(struct drm_output *output, pixman_region32_t *damage)
538{
539 struct drm_compositor *c =
540 (struct drm_compositor *) output->base.compositor;
541
542 if (c->use_pixman)
543 drm_output_render_pixman(output, damage);
544 else
545 drm_output_render_gl(output, damage);
546
547 pixman_region32_subtract(&c->base.primary_plane.damage,
548 &c->base.primary_plane.damage, damage);
549}
550
551static void
Richard Hughese7299962013-05-01 21:52:12 +0100552drm_output_set_gamma(struct weston_output *output_base,
553 uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
554{
555 int rc;
556 struct drm_output *output = (struct drm_output *) output_base;
557 struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;
558
559 /* check */
560 if (output_base->gamma_size != size)
561 return;
562 if (!output->original_crtc)
563 return;
564
565 rc = drmModeCrtcSetGamma(compositor->drm.fd,
566 output->crtc_id,
567 size, r, g, b);
568 if (rc)
569 weston_log("set gamma failed: %m\n");
570}
571
572static void
Kristian Høgsberg6ddcdae2012-02-28 22:31:58 -0500573drm_output_repaint(struct weston_output *output_base,
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400574 pixman_region32_t *damage)
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100575{
576 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500577 struct drm_compositor *compositor =
578 (struct drm_compositor *) output->base.compositor;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500579 struct drm_sprite *s;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400580 struct drm_mode *mode;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500581 int ret = 0;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100582
Xiong Zhangabd5d472013-10-11 14:43:07 +0800583 if (output->destroy_pending)
584 return;
585
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300586 if (!output->next)
Kristian Høgsbergd7c17262012-09-05 21:54:15 -0400587 drm_output_render(output, damage);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300588 if (!output->next)
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400589 return;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +0100590
Hardeningff39efa2013-09-18 23:56:35 +0200591 mode = container_of(output->base.current_mode, struct drm_mode, base);
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300592 if (!output->current) {
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400593 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300594 output->next->fb_id, 0, 0,
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400595 &output->connector_id, 1,
596 &mode->mode_info);
597 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200598 weston_log("set mode failed: %m\n");
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400599 return;
600 }
Ander Conselvan de Oliveira722a2d52013-06-04 16:24:05 +0300601 output_base->set_dpms(output_base, WESTON_DPMS_ON);
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200602 }
603
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500604 if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +0300605 output->next->fb_id,
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500606 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +0200607 weston_log("queueing pageflip failed: %m\n");
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500608 return;
Kristian Høgsberg54f14c32012-01-18 11:47:41 -0500609 }
Benjamin Franzkeec4d3422011-03-14 12:07:26 +0100610
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300611 output->page_flip_pending = 1;
612
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400613 drm_output_set_cursor(output);
614
Jesse Barnes58ef3792012-02-23 09:45:49 -0500615 /*
616 * Now, update all the sprite surfaces
617 */
618 wl_list_for_each(s, &compositor->sprite_list, link) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200619 uint32_t flags = 0, fb_id = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500620 drmVBlank vbl = {
621 .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
622 .request.sequence = 1,
623 };
624
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200625 if ((!s->current && !s->next) ||
Ander Conselvan de Oliveira2f7a30b2012-11-09 14:19:03 +0200626 !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
Jesse Barnes58ef3792012-02-23 09:45:49 -0500627 continue;
628
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200629 if (s->next && !compositor->sprites_hidden)
630 fb_id = s->next->fb_id;
631
Jesse Barnes58ef3792012-02-23 09:45:49 -0500632 ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200633 output->crtc_id, fb_id, flags,
Jesse Barnes58ef3792012-02-23 09:45:49 -0500634 s->dest_x, s->dest_y,
635 s->dest_w, s->dest_h,
636 s->src_x, s->src_y,
637 s->src_w, s->src_h);
638 if (ret)
Martin Minarik6d118362012-06-07 18:01:59 +0200639 weston_log("setplane failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500640 ret, strerror(errno));
641
Rob Clark5ca1a472012-08-08 20:27:37 -0500642 if (output->pipe > 0)
643 vbl.request.type |= DRM_VBLANK_SECONDARY;
644
Jesse Barnes58ef3792012-02-23 09:45:49 -0500645 /*
646 * Queue a vblank signal so we know when the surface
647 * becomes active on the display or has been replaced.
648 */
649 vbl.request.signal = (unsigned long)s;
650 ret = drmWaitVBlank(compositor->drm.fd, &vbl);
651 if (ret) {
Martin Minarik6d118362012-06-07 18:01:59 +0200652 weston_log("vblank event request failed: %d: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -0500653 ret, strerror(errno));
654 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300655
656 s->output = output;
657 output->vblank_pending = 1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500658 }
659
Kristian Høgsberg06cf6b02012-01-25 23:47:45 -0500660 return;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400661}
662
663static void
Jonas Ådahle5a12252013-04-05 23:07:11 +0200664drm_output_start_repaint_loop(struct weston_output *output_base)
665{
666 struct drm_output *output = (struct drm_output *) output_base;
667 struct drm_compositor *compositor = (struct drm_compositor *)
668 output_base->compositor;
669 uint32_t fb_id;
670
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300671 struct timespec ts;
672
Xiong Zhangabd5d472013-10-11 14:43:07 +0800673 if (output->destroy_pending)
674 return;
675
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +0300676 if (!output->current) {
677 /* We can't page flip if there's no mode set */
678 uint32_t msec;
679
680 clock_gettime(compositor->clock, &ts);
681 msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
682 weston_output_finish_frame(output_base, msec);
683 return;
684 }
685
686 fb_id = output->current->fb_id;
Jonas Ådahle5a12252013-04-05 23:07:11 +0200687
688 if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
689 DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
690 weston_log("queueing pageflip failed: %m\n");
691 return;
692 }
693}
694
695static void
Jesse Barnes58ef3792012-02-23 09:45:49 -0500696vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
697 void *data)
698{
699 struct drm_sprite *s = (struct drm_sprite *)data;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300700 struct drm_output *output = s->output;
701 uint32_t msecs;
702
703 output->vblank_pending = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500704
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +0200705 drm_output_release_fb(output, s->current);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200706 s->current = s->next;
707 s->next = NULL;
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300708
709 if (!output->page_flip_pending) {
710 msecs = sec * 1000 + usec / 1000;
711 weston_output_finish_frame(&output->base, msecs);
712 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500713}
714
715static void
Xiong Zhangabd5d472013-10-11 14:43:07 +0800716drm_output_destroy(struct weston_output *output_base);
717
718static void
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400719page_flip_handler(int fd, unsigned int frame,
720 unsigned int sec, unsigned int usec, void *data)
721{
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200722 struct drm_output *output = (struct drm_output *) data;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -0400723 uint32_t msecs;
724
Jonas Ådahle5a12252013-04-05 23:07:11 +0200725 /* We don't set page_flip_pending on start_repaint_loop, in that case
726 * we just want to page flip to the current buffer to get an accurate
727 * timestamp */
728 if (output->page_flip_pending) {
729 drm_output_release_fb(output, output->current);
730 output->current = output->next;
731 output->next = NULL;
732 }
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300733
Jonas Ådahle5a12252013-04-05 23:07:11 +0200734 output->page_flip_pending = 0;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -0400735
Xiong Zhangabd5d472013-10-11 14:43:07 +0800736 if (output->destroy_pending)
737 drm_output_destroy(&output->base);
738 else if (!output->vblank_pending) {
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300739 msecs = sec * 1000 + usec / 1000;
740 weston_output_finish_frame(&output->base, msecs);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +0300741
742 /* We can't call this from frame_notify, because the output's
743 * repaint needed flag is cleared just after that */
744 if (output->recorder)
745 weston_output_schedule_repaint(&output->base);
Ander Conselvan de Oliveiraa7326962012-06-26 17:09:13 +0300746 }
Benjamin Franzke1178a3c2011-04-10 16:49:52 +0200747}
748
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500749static uint32_t
750drm_output_check_sprite_format(struct drm_sprite *s,
751 struct weston_surface *es, struct gbm_bo *bo)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500752{
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500753 uint32_t i, format;
754
755 format = gbm_bo_get_format(bo);
756
757 if (format == GBM_FORMAT_ARGB8888) {
758 pixman_region32_t r;
759
Kristian Høgsberg63093a32013-03-01 14:29:16 -0500760 pixman_region32_init_rect(&r, 0, 0,
761 es->geometry.width,
762 es->geometry.height);
763 pixman_region32_subtract(&r, &r, &es->opaque);
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500764
765 if (!pixman_region32_not_empty(&r))
766 format = GBM_FORMAT_XRGB8888;
767
768 pixman_region32_fini(&r);
769 }
Jesse Barnes58ef3792012-02-23 09:45:49 -0500770
771 for (i = 0; i < s->count_formats; i++)
772 if (s->formats[i] == format)
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500773 return format;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500774
775 return 0;
776}
777
778static int
779drm_surface_transform_supported(struct weston_surface *es)
780{
Kristian Høgsbergd92c09c2013-01-29 16:56:15 -0500781 return !es->transform.enabled ||
782 (es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500783}
784
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400785static struct weston_plane *
Jesse Barnes58ef3792012-02-23 09:45:49 -0500786drm_output_prepare_overlay_surface(struct weston_output *output_base,
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -0400787 struct weston_surface *es)
Jesse Barnes58ef3792012-02-23 09:45:49 -0500788{
789 struct weston_compositor *ec = output_base->compositor;
790 struct drm_compositor *c =(struct drm_compositor *) ec;
791 struct drm_sprite *s;
792 int found = 0;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500793 struct gbm_bo *bo;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500794 pixman_region32_t dest_rect, src_rect;
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200795 pixman_box32_t *box, tbox;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500796 uint32_t format;
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400797 wl_fixed_t sx1, sy1, sx2, sy2;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500798
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200799 if (c->gbm == NULL)
800 return NULL;
801
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200802 if (es->buffer_transform != output_base->transform)
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200803 return NULL;
804
Hardeningff39efa2013-09-18 23:56:35 +0200805 if (es->buffer_scale != output_base->current_scale)
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200806 return NULL;
807
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500808 if (c->sprites_are_broken)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400809 return NULL;
Kristian Høgsberg65bec242012-03-05 19:57:35 -0500810
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300811 if (es->output_mask != (1u << output_base->id))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400812 return NULL;
Ander Conselvan de Oliveirad450b192012-06-26 17:09:12 +0300813
Pekka Paalanende685b82012-12-04 15:58:12 +0200814 if (es->buffer_ref.buffer == NULL)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400815 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500816
Ville Syrjälä5a84f312012-11-16 11:48:46 +0200817 if (es->alpha != 1.0f)
818 return NULL;
819
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500820 if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
Rob Clark702ffae2012-08-09 14:18:27 -0500821 return NULL;
822
Jesse Barnes58ef3792012-02-23 09:45:49 -0500823 if (!drm_surface_transform_supported(es))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400824 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500825
Jesse Barnes58ef3792012-02-23 09:45:49 -0500826 wl_list_for_each(s, &c->sprite_list, link) {
827 if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
828 continue;
829
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200830 if (!s->next) {
Jesse Barnes58ef3792012-02-23 09:45:49 -0500831 found = 1;
832 break;
833 }
834 }
835
836 /* No sprites available */
837 if (!found)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400838 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500839
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400840 bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
Kristian Høgsberg63996462013-09-03 22:27:08 -0700841 es->buffer_ref.buffer->resource,
842 GBM_BO_USE_SCANOUT);
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400843 if (!bo)
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400844 return NULL;
Kristian Høgsberg2763a2e2012-07-13 22:54:43 -0400845
Kristian Høgsberga2f84cc2012-12-07 12:37:58 -0500846 format = drm_output_check_sprite_format(s, es, bo);
847 if (format == 0) {
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200848 gbm_bo_destroy(bo);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400849 return NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500850 }
851
Ander Conselvan de Oliveiraca5c6ae2012-12-07 13:18:11 +0200852 s->next = drm_fb_get_from_bo(bo, c, format);
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +0200853 if (!s->next) {
854 gbm_bo_destroy(bo);
855 return NULL;
856 }
857
Pekka Paalanende685b82012-12-04 15:58:12 +0200858 drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500859
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400860 box = pixman_region32_extents(&es->transform.boundingbox);
861 s->plane.x = box->x1;
862 s->plane.y = box->y1;
863
Jesse Barnes58ef3792012-02-23 09:45:49 -0500864 /*
865 * Calculate the source & dest rects properly based on actual
Martin Olsson3b132e32012-09-29 15:13:56 +0200866 * position (note the caller has called weston_surface_update_transform()
Jesse Barnes58ef3792012-02-23 09:45:49 -0500867 * for us already).
868 */
869 pixman_region32_init(&dest_rect);
870 pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
871 &output_base->region);
872 pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
873 box = pixman_region32_extents(&dest_rect);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200874 tbox = weston_transformed_rect(output_base->width,
875 output_base->height,
Alexander Larsson4ea95522013-05-22 14:41:37 +0200876 output_base->transform,
Hardeningff39efa2013-09-18 23:56:35 +0200877 output_base->current_scale,
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200878 *box);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200879 s->dest_x = tbox.x1;
880 s->dest_y = tbox.y1;
881 s->dest_w = tbox.x2 - tbox.x1;
882 s->dest_h = tbox.y2 - tbox.y1;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500883 pixman_region32_fini(&dest_rect);
884
885 pixman_region32_init(&src_rect);
886 pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
887 &output_base->region);
Jesse Barnes58ef3792012-02-23 09:45:49 -0500888 box = pixman_region32_extents(&src_rect);
Kristian Høgsberg3b00bae2012-07-13 15:25:07 -0400889
890 weston_surface_from_global_fixed(es,
891 wl_fixed_from_int(box->x1),
892 wl_fixed_from_int(box->y1),
893 &sx1, &sy1);
894 weston_surface_from_global_fixed(es,
895 wl_fixed_from_int(box->x2),
896 wl_fixed_from_int(box->y2),
897 &sx2, &sy2);
898
899 if (sx1 < 0)
900 sx1 = 0;
901 if (sy1 < 0)
902 sy1 = 0;
903 if (sx2 > wl_fixed_from_int(es->geometry.width))
904 sx2 = wl_fixed_from_int(es->geometry.width);
905 if (sy2 > wl_fixed_from_int(es->geometry.height))
906 sy2 = wl_fixed_from_int(es->geometry.height);
907
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200908 tbox.x1 = sx1;
909 tbox.y1 = sy1;
910 tbox.x2 = sx2;
911 tbox.y2 = sy2;
912
913 tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
914 wl_fixed_from_int(es->geometry.height),
Alexander Larssond9a7bb72013-05-22 14:41:39 +0200915 es->buffer_transform, es->buffer_scale, tbox);
Ander Conselvan de Oliveira409eebf2012-12-05 15:14:04 +0200916
917 s->src_x = tbox.x1 << 8;
918 s->src_y = tbox.y1 << 8;
919 s->src_w = (tbox.x2 - tbox.x1) << 8;
920 s->src_h = (tbox.y2 - tbox.y1) << 8;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500921 pixman_region32_fini(&src_rect);
922
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400923 return &s->plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -0500924}
925
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400926static struct weston_plane *
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400927drm_output_prepare_cursor_surface(struct weston_output *output_base,
928 struct weston_surface *es)
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500929{
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400930 struct drm_compositor *c =
931 (struct drm_compositor *) output_base->compositor;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400932 struct drm_output *output = (struct drm_output *) output_base;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400933
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +0200934 if (c->gbm == NULL)
935 return NULL;
Ander Conselvan de Oliveira2908a3d2012-11-27 17:03:43 +0200936 if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
937 return NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400938 if (output->cursor_surface)
939 return NULL;
940 if (es->output_mask != (1u << output_base->id))
941 return NULL;
Rob Clarkab5b1e32012-08-09 13:24:45 -0500942 if (c->cursors_are_broken)
Kristian Høgsberg8a015802012-08-09 17:19:23 -0400943 return NULL;
Pekka Paalanende685b82012-12-04 15:58:12 +0200944 if (es->buffer_ref.buffer == NULL ||
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500945 !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400946 es->geometry.width > 64 || es->geometry.height > 64)
947 return NULL;
948
949 output->cursor_surface = es;
950
951 return &output->cursor_plane;
952}
953
954static void
955drm_output_set_cursor(struct drm_output *output)
956{
957 struct weston_surface *es = output->cursor_surface;
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400958 struct drm_compositor *c =
959 (struct drm_compositor *) output->base.compositor;
960 EGLint handle, stride;
961 struct gbm_bo *bo;
962 uint32_t buf[64 * 64];
963 unsigned char *s;
Kristian Høgsberg24e42752012-07-18 12:08:37 -0400964 int i, x, y;
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500965
Kristian Høgsberg79af73e2012-08-03 15:45:23 -0400966 output->cursor_surface = NULL;
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400967 if (es == NULL) {
968 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
969 return;
970 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500971
Pekka Paalanende685b82012-12-04 15:58:12 +0200972 if (es->buffer_ref.buffer &&
973 pixman_region32_not_empty(&output->cursor_plane.damage)) {
Kristian Høgsberg5626d342012-08-03 11:50:05 -0400974 pixman_region32_fini(&output->cursor_plane.damage);
975 pixman_region32_init(&output->cursor_plane.damage);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400976 output->current_cursor ^= 1;
977 bo = output->cursor_bo[output->current_cursor];
978 memset(buf, 0, sizeof buf);
Jason Ekstrand6bd62942013-06-20 20:38:23 -0500979 stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
980 s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400981 for (i = 0; i < es->geometry.height; i++)
982 memcpy(buf + i * 64, s + i * stride,
983 es->geometry.width * 4);
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -0500984
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400985 if (gbm_bo_write(bo, buf, sizeof buf) < 0)
Pekka Paalanenae29da22012-08-06 14:57:05 +0300986 weston_log("failed update cursor: %m\n");
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400987
Kristian Høgsberg1f5de352012-07-18 12:09:58 -0400988 handle = gbm_bo_get_handle(bo).s32;
989 if (drmModeSetCursor(c->drm.fd,
Rob Clarkab5b1e32012-08-09 13:24:45 -0500990 output->crtc_id, handle, 64, 64)) {
Pekka Paalanenae29da22012-08-06 14:57:05 +0300991 weston_log("failed to set cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -0500992 c->cursors_are_broken = 1;
993 }
Kristian Høgsberga6edab32012-07-14 01:06:28 -0400994 }
995
Hardeningff39efa2013-09-18 23:56:35 +0200996 x = (es->geometry.x - output->base.x) * output->base.current_scale;
997 y = (es->geometry.y - output->base.y) * output->base.current_scale;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -0400998 if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
Rob Clarkab5b1e32012-08-09 13:24:45 -0500999 if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
Kristian Høgsberg24e42752012-07-18 12:08:37 -04001000 weston_log("failed to move cursor: %m\n");
Rob Clarkab5b1e32012-08-09 13:24:45 -05001001 c->cursors_are_broken = 1;
1002 }
1003
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001004 output->cursor_plane.x = x;
1005 output->cursor_plane.y = y;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001006 }
Kristian Høgsbergd8bf90c2012-02-23 23:03:14 -05001007}
1008
Jesse Barnes58ef3792012-02-23 09:45:49 -05001009static void
1010drm_assign_planes(struct weston_output *output)
1011{
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001012 struct drm_compositor *c =
1013 (struct drm_compositor *) output->compositor;
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001014 struct weston_surface *es, *next;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001015 pixman_region32_t overlap, surface_overlap;
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001016 struct weston_plane *primary, *next_plane;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001017
1018 /*
1019 * Find a surface for each sprite in the output using some heuristics:
1020 * 1) size
1021 * 2) frequency of update
1022 * 3) opacity (though some hw might support alpha blending)
1023 * 4) clipping (this can be fixed with color keys)
1024 *
1025 * The idea is to save on blitting since this should save power.
1026 * If we can get a large video surface on the sprite for example,
1027 * the main display surface may not need to update at all, and
1028 * the client buffer can be used directly for the sprite surface
1029 * as we do for flipping full screen surfaces.
1030 */
1031 pixman_region32_init(&overlap);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001032 primary = &c->base.primary_plane;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001033 wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001034 /* test whether this buffer can ever go into a plane:
1035 * non-shm, or small enough to be a cursor
1036 */
1037 if ((es->buffer_ref.buffer &&
Jason Ekstrand6bd62942013-06-20 20:38:23 -05001038 !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
Pekka Paalanenccfeae22012-12-04 15:58:14 +02001039 (es->geometry.width <= 64 && es->geometry.height <= 64))
1040 es->keep_buffer = 1;
1041 else
1042 es->keep_buffer = 0;
1043
Jesse Barnes58ef3792012-02-23 09:45:49 -05001044 pixman_region32_init(&surface_overlap);
1045 pixman_region32_intersect(&surface_overlap, &overlap,
1046 &es->transform.boundingbox);
1047
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001048 next_plane = NULL;
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001049 if (pixman_region32_not_empty(&surface_overlap))
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001050 next_plane = primary;
1051 if (next_plane == NULL)
Kristian Høgsberg5626d342012-08-03 11:50:05 -04001052 next_plane = drm_output_prepare_cursor_surface(output, es);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001053 if (next_plane == NULL)
1054 next_plane = drm_output_prepare_scanout_surface(output, es);
1055 if (next_plane == NULL)
1056 next_plane = drm_output_prepare_overlay_surface(output, es);
1057 if (next_plane == NULL)
1058 next_plane = primary;
1059 weston_surface_move_to_plane(es, next_plane);
1060 if (next_plane == primary)
Jesse Barnes58ef3792012-02-23 09:45:49 -05001061 pixman_region32_union(&overlap, &overlap,
1062 &es->transform.boundingbox);
Kristian Høgsberg6143f7d2012-07-14 00:31:32 -04001063
Jesse Barnes58ef3792012-02-23 09:45:49 -05001064 pixman_region32_fini(&surface_overlap);
1065 }
1066 pixman_region32_fini(&overlap);
Jesse Barnes58ef3792012-02-23 09:45:49 -05001067}
1068
Matt Roper361d2ad2011-08-29 13:52:23 -07001069static void
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001070drm_output_fini_pixman(struct drm_output *output);
1071
1072static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001073drm_output_destroy(struct weston_output *output_base)
Matt Roper361d2ad2011-08-29 13:52:23 -07001074{
1075 struct drm_output *output = (struct drm_output *) output_base;
1076 struct drm_compositor *c =
Benjamin Franzke117483d2011-08-30 11:38:26 +02001077 (struct drm_compositor *) output->base.compositor;
Matt Roper361d2ad2011-08-29 13:52:23 -07001078 drmModeCrtcPtr origcrtc = output->original_crtc;
Matt Roper361d2ad2011-08-29 13:52:23 -07001079
Xiong Zhangabd5d472013-10-11 14:43:07 +08001080 if (output->page_flip_pending) {
1081 output->destroy_pending = 1;
1082 weston_log("destroy output while page flip pending\n");
1083 return;
1084 }
1085
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001086 if (output->backlight)
1087 backlight_destroy(output->backlight);
1088
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001089 drmModeFreeProperty(output->dpms_prop);
1090
Matt Roper361d2ad2011-08-29 13:52:23 -07001091 /* Turn off hardware cursor */
Kristian Høgsberga6edab32012-07-14 01:06:28 -04001092 drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
Matt Roper361d2ad2011-08-29 13:52:23 -07001093
1094 /* Restore original CRTC state */
1095 drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
Benjamin Franzke117483d2011-08-30 11:38:26 +02001096 origcrtc->x, origcrtc->y,
1097 &output->connector_id, 1, &origcrtc->mode);
Matt Roper361d2ad2011-08-29 13:52:23 -07001098 drmModeFreeCrtc(origcrtc);
1099
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001100 c->crtc_allocator &= ~(1 << output->crtc_id);
1101 c->connector_allocator &= ~(1 << output->connector_id);
1102
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001103 if (c->use_pixman) {
1104 drm_output_fini_pixman(output);
1105 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001106 gl_renderer->output_destroy(output_base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001107 gbm_surface_destroy(output->surface);
1108 }
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001109
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001110 weston_plane_release(&output->fb_plane);
1111 weston_plane_release(&output->cursor_plane);
1112
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05001113 weston_output_destroy(&output->base);
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02001114 wl_list_remove(&output->base.link);
1115
Matt Roper361d2ad2011-08-29 13:52:23 -07001116 free(output);
1117}
1118
Alex Wub7b8bda2012-04-17 17:20:48 +08001119static struct drm_mode *
1120choose_mode (struct drm_output *output, struct weston_mode *target_mode)
1121{
1122 struct drm_mode *tmp_mode = NULL, *mode;
1123
Hardeningff39efa2013-09-18 23:56:35 +02001124 if (output->base.current_mode->width == target_mode->width &&
1125 output->base.current_mode->height == target_mode->height &&
1126 (output->base.current_mode->refresh == target_mode->refresh ||
Alex Wub7b8bda2012-04-17 17:20:48 +08001127 target_mode->refresh == 0))
Hardeningff39efa2013-09-18 23:56:35 +02001128 return (struct drm_mode *)output->base.current_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001129
1130 wl_list_for_each(mode, &output->base.mode_list, base.link) {
1131 if (mode->mode_info.hdisplay == target_mode->width &&
1132 mode->mode_info.vdisplay == target_mode->height) {
1133 if (mode->mode_info.vrefresh == target_mode->refresh ||
1134 target_mode->refresh == 0) {
1135 return mode;
1136 } else if (!tmp_mode)
1137 tmp_mode = mode;
1138 }
1139 }
1140
1141 return tmp_mode;
1142}
1143
1144static int
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001145drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001146static int
1147drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001148
1149static int
Alex Wub7b8bda2012-04-17 17:20:48 +08001150drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
1151{
1152 struct drm_output *output;
1153 struct drm_mode *drm_mode;
Alex Wub7b8bda2012-04-17 17:20:48 +08001154 struct drm_compositor *ec;
Alex Wub7b8bda2012-04-17 17:20:48 +08001155
1156 if (output_base == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001157 weston_log("output is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001158 return -1;
1159 }
1160
1161 if (mode == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02001162 weston_log("mode is NULL.\n");
Alex Wub7b8bda2012-04-17 17:20:48 +08001163 return -1;
1164 }
1165
1166 ec = (struct drm_compositor *)output_base->compositor;
1167 output = (struct drm_output *)output_base;
1168 drm_mode = choose_mode (output, mode);
1169
1170 if (!drm_mode) {
Martin Minarik6d118362012-06-07 18:01:59 +02001171 weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
Alex Wub7b8bda2012-04-17 17:20:48 +08001172 return -1;
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001173 }
1174
Hardeningff39efa2013-09-18 23:56:35 +02001175 if (&drm_mode->base == output->base.current_mode)
Alex Wub7b8bda2012-04-17 17:20:48 +08001176 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001177
Hardeningff39efa2013-09-18 23:56:35 +02001178 output->base.current_mode->flags = 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001179
Hardeningff39efa2013-09-18 23:56:35 +02001180 output->base.current_mode = &drm_mode->base;
1181 output->base.current_mode->flags =
Alex Wub7b8bda2012-04-17 17:20:48 +08001182 WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1183
Alex Wub7b8bda2012-04-17 17:20:48 +08001184 /* reset rendering stuff. */
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02001185 drm_output_release_fb(output, output->current);
1186 drm_output_release_fb(output, output->next);
1187 output->current = output->next = NULL;
Alex Wub7b8bda2012-04-17 17:20:48 +08001188
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001189 if (ec->use_pixman) {
1190 drm_output_fini_pixman(output);
1191 if (drm_output_init_pixman(output, ec) < 0) {
1192 weston_log("failed to init output pixman state with "
1193 "new mode\n");
1194 return -1;
1195 }
1196 } else {
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001197 gl_renderer->output_destroy(&output->base);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001198 gbm_surface_destroy(output->surface);
Alex Wub7b8bda2012-04-17 17:20:48 +08001199
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001200 if (drm_output_init_egl(output, ec) < 0) {
1201 weston_log("failed to init output egl state with "
1202 "new mode");
1203 return -1;
1204 }
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001205 }
1206
Alex Wub7b8bda2012-04-17 17:20:48 +08001207 return 0;
Alex Wub7b8bda2012-04-17 17:20:48 +08001208}
1209
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001210static int
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001211on_drm_input(int fd, uint32_t mask, void *data)
1212{
1213 drmEventContext evctx;
1214
1215 memset(&evctx, 0, sizeof evctx);
1216 evctx.version = DRM_EVENT_CONTEXT_VERSION;
1217 evctx.page_flip_handler = page_flip_handler;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001218 evctx.vblank_handler = vblank_handler;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001219 drmHandleEvent(fd, &evctx);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04001220
1221 return 1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001222}
1223
1224static int
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001225init_drm(struct drm_compositor *ec, struct udev_device *device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001226{
Kristian Høgsbergb5ef5912012-03-28 22:53:49 -04001227 const char *filename, *sysnum;
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001228 uint64_t cap;
1229 int fd, ret;
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001230
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001231 sysnum = udev_device_get_sysnum(device);
1232 if (sysnum)
1233 ec->drm.id = atoi(sysnum);
1234 if (!sysnum || ec->drm.id < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02001235 weston_log("cannot get device sysnum\n");
Kristian Høgsbergb71302e2012-05-10 12:28:35 -04001236 return -1;
1237 }
1238
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001239 filename = udev_device_get_devnode(device);
Kristian Høgsberg05ad1e42013-09-17 14:41:03 -07001240 fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
Kristian Høgsberg5fcd0aa2010-08-09 14:43:33 -04001241 if (fd < 0) {
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001242 /* Probably permissions error */
Martin Minarik6d118362012-06-07 18:01:59 +02001243 weston_log("couldn't open %s, skipping\n",
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001244 udev_device_get_devnode(device));
1245 return -1;
1246 }
1247
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04001248 weston_log("using %s\n", filename);
1249
Benjamin Franzke2af7f102011-03-02 11:14:59 +01001250 ec->drm.fd = fd;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03001251 ec->drm.filename = strdup(filename);
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001252
Ander Conselvan de Oliveira95eb3a22013-05-07 14:16:59 +03001253 ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
1254 if (ret == 0 && cap == 1)
1255 ec->clock = CLOCK_MONOTONIC;
1256 else
1257 ec->clock = CLOCK_REALTIME;
Ander Conselvan de Oliveira1d41ad42013-01-25 15:13:04 +02001258
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02001259 return 0;
1260}
1261
1262static int
1263init_egl(struct drm_compositor *ec)
1264{
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001265 EGLint format;
1266
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001267 gl_renderer = weston_load_module("gl-renderer.so",
1268 "gl_renderer_interface");
1269 if (!gl_renderer)
1270 return -1;
1271
1272 /* GBM will load a dri driver, but even though they need symbols from
1273 * libglapi, in some version of Mesa they are not linked to it. Since
1274 * only the gl-renderer module links to it, the call above won't make
1275 * these symbols globally available, and loading the DRI driver fails.
1276 * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
1277 dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
1278
Benjamin Franzke060cf802011-04-30 09:32:11 +02001279 ec->gbm = gbm_create_device(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001280
John Kåre Alsakeref591aa2013-03-02 12:27:39 +01001281 if (!ec->gbm)
1282 return -1;
1283
Alexandru DAMIANbe0ac5b2013-10-02 17:51:05 +01001284 format = ec->format;
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001285 if (gl_renderer->create(&ec->base, ec->gbm,
1286 gl_renderer->opaque_attribs, &format) < 0) {
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01001287 gbm_device_destroy(ec->gbm);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04001288 return -1;
1289 }
1290
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001291 return 0;
1292}
1293
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001294static int
1295init_pixman(struct drm_compositor *ec)
1296{
1297 return pixman_renderer_init(&ec->base);
1298}
1299
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001300static struct drm_mode *
Alexander Larsson0b135062013-05-28 16:23:36 +02001301drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001302{
1303 struct drm_mode *mode;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001304 uint64_t refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001305
1306 mode = malloc(sizeof *mode);
1307 if (mode == NULL)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001308 return NULL;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001309
1310 mode->base.flags = 0;
Alexander Larsson0b135062013-05-28 16:23:36 +02001311 mode->base.width = info->hdisplay;
1312 mode->base.height = info->vdisplay;
Kristian Høgsbergc4621b02012-05-10 12:23:53 -04001313
1314 /* Calculate higher precision (mHz) refresh rate */
1315 refresh = (info->clock * 1000000LL / info->htotal +
1316 info->vtotal / 2) / info->vtotal;
1317
1318 if (info->flags & DRM_MODE_FLAG_INTERLACE)
1319 refresh *= 2;
1320 if (info->flags & DRM_MODE_FLAG_DBLSCAN)
1321 refresh /= 2;
1322 if (info->vscan > 1)
1323 refresh /= info->vscan;
1324
1325 mode->base.refresh = refresh;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001326 mode->mode_info = *info;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001327
1328 if (info->type & DRM_MODE_TYPE_PREFERRED)
1329 mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
1330
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001331 wl_list_insert(output->base.mode_list.prev, &mode->base.link);
1332
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001333 return mode;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001334}
1335
1336static int
1337drm_subpixel_to_wayland(int drm_value)
1338{
1339 switch (drm_value) {
1340 default:
1341 case DRM_MODE_SUBPIXEL_UNKNOWN:
1342 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
1343 case DRM_MODE_SUBPIXEL_NONE:
1344 return WL_OUTPUT_SUBPIXEL_NONE;
1345 case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
1346 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
1347 case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
1348 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
1349 case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
1350 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
1351 case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
1352 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
1353 }
1354}
1355
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001356/* returns a value between 0-255 range, where higher is brighter */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001357static uint32_t
1358drm_get_backlight(struct drm_output *output)
1359{
1360 long brightness, max_brightness, norm;
1361
1362 brightness = backlight_get_brightness(output->backlight);
1363 max_brightness = backlight_get_max_brightness(output->backlight);
1364
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001365 /* convert it on a scale of 0 to 255 */
1366 norm = (brightness * 255)/(max_brightness);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001367
1368 return (uint32_t) norm;
1369}
1370
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001371/* values accepted are between 0-255 range */
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001372static void
1373drm_set_backlight(struct weston_output *output_base, uint32_t value)
1374{
1375 struct drm_output *output = (struct drm_output *) output_base;
1376 long max_brightness, new_brightness;
1377
1378 if (!output->backlight)
1379 return;
1380
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04001381 if (value > 255)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001382 return;
1383
1384 max_brightness = backlight_get_max_brightness(output->backlight);
1385
1386 /* get denormalized value */
Tiago Vignatti5ab91ad2012-03-12 19:40:09 -03001387 new_brightness = (value * max_brightness) / 255;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001388
1389 backlight_set_brightness(output->backlight, new_brightness);
1390}
1391
1392static drmModePropertyPtr
1393drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
1394{
1395 drmModePropertyPtr props;
1396 int i;
1397
1398 for (i = 0; i < connector->count_props; i++) {
1399 props = drmModeGetProperty(fd, connector->props[i]);
1400 if (!props)
1401 continue;
1402
1403 if (!strcmp(props->name, name))
1404 return props;
1405
1406 drmModeFreeProperty(props);
1407 }
1408
1409 return NULL;
1410}
1411
1412static void
1413drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
1414{
1415 struct drm_output *output = (struct drm_output *) output_base;
1416 struct weston_compositor *ec = output_base->compositor;
1417 struct drm_compositor *c = (struct drm_compositor *) ec;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001418
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001419 if (!output->dpms_prop)
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001420 return;
1421
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001422 drmModeConnectorSetProperty(c->drm.fd, output->connector_id,
1423 output->dpms_prop->prop_id, level);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001424}
1425
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001426static const char *connector_type_names[] = {
1427 "None",
1428 "VGA",
1429 "DVI",
1430 "DVI",
1431 "DVI",
1432 "Composite",
1433 "TV",
1434 "LVDS",
1435 "CTV",
1436 "DIN",
1437 "DP",
1438 "HDMI",
1439 "HDMI",
1440 "TV",
1441 "eDP",
1442};
1443
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001444static int
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001445find_crtc_for_connector(struct drm_compositor *ec,
1446 drmModeRes *resources, drmModeConnector *connector)
1447{
1448 drmModeEncoder *encoder;
1449 uint32_t possible_crtcs;
1450 int i, j;
1451
1452 for (j = 0; j < connector->count_encoders; j++) {
1453 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[j]);
1454 if (encoder == NULL) {
1455 weston_log("Failed to get encoder.\n");
1456 return -1;
1457 }
1458 possible_crtcs = encoder->possible_crtcs;
1459 drmModeFreeEncoder(encoder);
1460
1461 for (i = 0; i < resources->count_crtcs; i++) {
1462 if (possible_crtcs & (1 << i) &&
1463 !(ec->crtc_allocator & (1 << resources->crtcs[i])))
1464 return i;
1465 }
1466 }
1467
1468 return -1;
1469}
1470
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001471/* Init output state that depends on gl or gbm */
1472static int
1473drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
1474{
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001475 int i, flags;
1476
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001477 output->surface = gbm_surface_create(ec->gbm,
Hardeningff39efa2013-09-18 23:56:35 +02001478 output->base.current_mode->width,
1479 output->base.current_mode->height,
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07001480 ec->format,
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001481 GBM_BO_USE_SCANOUT |
1482 GBM_BO_USE_RENDERING);
1483 if (!output->surface) {
1484 weston_log("failed to create gbm surface\n");
1485 return -1;
1486 }
1487
Ander Conselvan de Oliveira97f29522013-10-14 15:57:11 +03001488 if (gl_renderer->output_create(&output->base, output->surface) < 0) {
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001489 weston_log("failed to create gl renderer output state\n");
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001490 gbm_surface_destroy(output->surface);
1491 return -1;
1492 }
1493
Ander Conselvan de Oliveira6c01c9c2012-12-14 13:37:30 -02001494 flags = GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE;
1495
1496 for (i = 0; i < 2; i++) {
1497 if (output->cursor_bo[i])
1498 continue;
1499
1500 output->cursor_bo[i] =
1501 gbm_bo_create(ec->gbm, 64, 64, GBM_FORMAT_ARGB8888,
1502 flags);
1503 }
1504
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001505 if (output->cursor_bo[0] == NULL || output->cursor_bo[1] == NULL) {
1506 weston_log("cursor buffers unavailable, using gl cursors\n");
1507 ec->cursors_are_broken = 1;
1508 }
1509
1510 return 0;
1511}
1512
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001513static int
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001514drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c)
1515{
Hardeningff39efa2013-09-18 23:56:35 +02001516 int w = output->base.current_mode->width;
1517 int h = output->base.current_mode->height;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001518 unsigned int i;
1519
1520 /* FIXME error checking */
1521
1522 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001523 output->dumb[i] = drm_fb_create_dumb(c, w, h);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001524 if (!output->dumb[i])
1525 goto err;
1526
1527 output->image[i] =
Alexander Larsson0b135062013-05-28 16:23:36 +02001528 pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001529 output->dumb[i]->map,
1530 output->dumb[i]->stride);
1531 if (!output->image[i])
1532 goto err;
1533 }
1534
1535 if (pixman_renderer_output_create(&output->base) < 0)
1536 goto err;
1537
1538 pixman_region32_init_rect(&output->previous_damage,
Alexander Larsson0b135062013-05-28 16:23:36 +02001539 output->base.x, output->base.y, output->base.width, output->base.height);
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001540
1541 return 0;
1542
1543err:
1544 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1545 if (output->dumb[i])
1546 drm_fb_destroy_dumb(output->dumb[i]);
1547 if (output->image[i])
1548 pixman_image_unref(output->image[i]);
1549
1550 output->dumb[i] = NULL;
1551 output->image[i] = NULL;
1552 }
1553
1554 return -1;
1555}
1556
1557static void
1558drm_output_fini_pixman(struct drm_output *output)
1559{
1560 unsigned int i;
1561
1562 pixman_renderer_output_destroy(&output->base);
1563 pixman_region32_fini(&output->previous_damage);
1564
1565 for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
1566 drm_fb_destroy_dumb(output->dumb[i]);
1567 pixman_image_unref(output->image[i]);
1568 output->dumb[i] = NULL;
1569 output->image[i] = NULL;
1570 }
1571}
1572
Richard Hughes2b2092a2013-04-24 14:58:02 +01001573static void
1574edid_parse_string(const uint8_t *data, char text[])
1575{
1576 int i;
1577 int replaced = 0;
1578
1579 /* this is always 12 bytes, but we can't guarantee it's null
1580 * terminated or not junk. */
1581 strncpy(text, (const char *) data, 12);
1582
1583 /* remove insane chars */
1584 for (i = 0; text[i] != '\0'; i++) {
1585 if (text[i] == '\n' ||
1586 text[i] == '\r') {
1587 text[i] = '\0';
1588 break;
1589 }
1590 }
1591
1592 /* ensure string is printable */
1593 for (i = 0; text[i] != '\0'; i++) {
1594 if (!isprint(text[i])) {
1595 text[i] = '-';
1596 replaced++;
1597 }
1598 }
1599
1600 /* if the string is random junk, ignore the string */
1601 if (replaced > 4)
1602 text[0] = '\0';
1603}
1604
1605#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe
1606#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc
1607#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff
1608#define EDID_OFFSET_DATA_BLOCKS 0x36
1609#define EDID_OFFSET_LAST_BLOCK 0x6c
1610#define EDID_OFFSET_PNPID 0x08
1611#define EDID_OFFSET_SERIAL 0x0c
1612
1613static int
1614edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
1615{
1616 int i;
1617 uint32_t serial_number;
1618
1619 /* check header */
1620 if (length < 128)
1621 return -1;
1622 if (data[0] != 0x00 || data[1] != 0xff)
1623 return -1;
1624
1625 /* decode the PNP ID from three 5 bit words packed into 2 bytes
1626 * /--08--\/--09--\
1627 * 7654321076543210
1628 * |\---/\---/\---/
1629 * R C1 C2 C3 */
1630 edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
1631 edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
1632 edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
1633 edid->pnp_id[3] = '\0';
1634
1635 /* maybe there isn't a ASCII serial number descriptor, so use this instead */
1636 serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
1637 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
1638 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
1639 serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
1640 if (serial_number > 0)
1641 sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
1642
1643 /* parse EDID data */
1644 for (i = EDID_OFFSET_DATA_BLOCKS;
1645 i <= EDID_OFFSET_LAST_BLOCK;
1646 i += 18) {
1647 /* ignore pixel clock data */
1648 if (data[i] != 0)
1649 continue;
1650 if (data[i+2] != 0)
1651 continue;
1652
1653 /* any useful blocks? */
1654 if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
1655 edid_parse_string(&data[i+5],
1656 edid->monitor_name);
1657 } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
1658 edid_parse_string(&data[i+5],
1659 edid->serial_number);
1660 } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
1661 edid_parse_string(&data[i+5],
1662 edid->eisa_id);
1663 }
1664 }
1665 return 0;
1666}
1667
1668static void
1669find_and_parse_output_edid(struct drm_compositor *ec,
1670 struct drm_output *output,
1671 drmModeConnector *connector)
1672{
1673 drmModePropertyBlobPtr edid_blob = NULL;
1674 drmModePropertyPtr property;
1675 int i;
1676 int rc;
1677
1678 for (i = 0; i < connector->count_props && !edid_blob; i++) {
1679 property = drmModeGetProperty(ec->drm.fd, connector->props[i]);
1680 if (!property)
1681 continue;
1682 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1683 !strcmp(property->name, "EDID")) {
1684 edid_blob = drmModeGetPropertyBlob(ec->drm.fd,
1685 connector->prop_values[i]);
1686 }
1687 drmModeFreeProperty(property);
1688 }
1689 if (!edid_blob)
1690 return;
1691
1692 rc = edid_parse(&output->edid,
1693 edid_blob->data,
1694 edid_blob->length);
1695 if (!rc) {
1696 weston_log("EDID data '%s', '%s', '%s'\n",
1697 output->edid.pnp_id,
1698 output->edid.monitor_name,
1699 output->edid.serial_number);
1700 if (output->edid.pnp_id[0] != '\0')
1701 output->base.make = output->edid.pnp_id;
1702 if (output->edid.monitor_name[0] != '\0')
1703 output->base.model = output->edid.monitor_name;
1704 if (output->edid.serial_number[0] != '\0')
1705 output->base.serial_number = output->edid.serial_number;
1706 }
1707 drmModeFreePropertyBlob(edid_blob);
1708}
1709
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001710
1711
1712static int
1713parse_modeline(const char *s, drmModeModeInfo *mode)
1714{
1715 char hsync[16];
1716 char vsync[16];
1717 float fclock;
1718
1719 mode->type = DRM_MODE_TYPE_USERDEF;
1720 mode->hskew = 0;
1721 mode->vscan = 0;
1722 mode->vrefresh = 0;
1723 mode->flags = 0;
1724
Rob Bradford307e09e2013-07-26 16:29:40 +01001725 if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001726 &fclock,
1727 &mode->hdisplay,
1728 &mode->hsync_start,
1729 &mode->hsync_end,
1730 &mode->htotal,
1731 &mode->vdisplay,
1732 &mode->vsync_start,
1733 &mode->vsync_end,
1734 &mode->vtotal, hsync, vsync) != 11)
1735 return -1;
1736
1737 mode->clock = fclock * 1000;
1738 if (strcmp(hsync, "+hsync") == 0)
1739 mode->flags |= DRM_MODE_FLAG_PHSYNC;
1740 else if (strcmp(hsync, "-hsync") == 0)
1741 mode->flags |= DRM_MODE_FLAG_NHSYNC;
1742 else
1743 return -1;
1744
1745 if (strcmp(vsync, "+vsync") == 0)
1746 mode->flags |= DRM_MODE_FLAG_PVSYNC;
1747 else if (strcmp(vsync, "-vsync") == 0)
1748 mode->flags |= DRM_MODE_FLAG_NVSYNC;
1749 else
1750 return -1;
1751
1752 return 0;
1753}
1754
1755static uint32_t
1756parse_transform(const char *transform, const char *output_name)
1757{
1758 static const struct { const char *name; uint32_t token; } names[] = {
1759 { "normal", WL_OUTPUT_TRANSFORM_NORMAL },
1760 { "90", WL_OUTPUT_TRANSFORM_90 },
1761 { "180", WL_OUTPUT_TRANSFORM_180 },
1762 { "270", WL_OUTPUT_TRANSFORM_270 },
1763 { "flipped", WL_OUTPUT_TRANSFORM_FLIPPED },
1764 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
1765 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
1766 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
1767 };
1768 unsigned int i;
1769
1770 for (i = 0; i < ARRAY_LENGTH(names); i++)
1771 if (strcmp(names[i].name, transform) == 0)
1772 return names[i].token;
1773
1774 weston_log("Invalid transform \"%s\" for output %s\n",
1775 transform, output_name);
1776
1777 return WL_OUTPUT_TRANSFORM_NORMAL;
1778}
1779
Rob Bradford66bd9f52013-06-25 18:56:42 +01001780static void
1781setup_output_seat_constraint(struct drm_compositor *ec,
1782 struct weston_output *output,
1783 const char *s)
1784{
1785 if (strcmp(s, "") != 0) {
1786 struct udev_seat *seat;
1787
1788 seat = udev_seat_get_named(&ec->base, s);
1789 if (seat)
1790 seat->base.output = output;
1791
1792 if (seat && seat->base.pointer)
1793 weston_pointer_clamp(seat->base.pointer,
1794 &seat->base.pointer->x,
1795 &seat->base.pointer->y);
1796 }
1797}
1798
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001799static int
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001800create_output_for_connector(struct drm_compositor *ec,
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001801 drmModeRes *resources,
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001802 drmModeConnector *connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001803 int x, int y, struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001804{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001805 struct drm_output *output;
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001806 struct drm_mode *drm_mode, *next, *preferred, *current, *configured;
1807 struct weston_mode *m;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001808 struct weston_config_section *section;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001809 drmModeEncoder *encoder;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001810 drmModeModeInfo crtc_mode, modeline;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001811 drmModeCrtc *crtc;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001812 int i, width, height, scale;
1813 char name[32], *s;
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001814 const char *type_name;
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001815 enum output_config config;
1816 uint32_t transform;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001817
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001818 i = find_crtc_for_connector(ec, resources, connector);
1819 if (i < 0) {
1820 weston_log("No usable crtc/encoder pair for connector.\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001821 return -1;
1822 }
1823
Peter Huttererf3d62272013-08-08 11:57:05 +10001824 output = zalloc(sizeof *output);
Kristian Høgsberg9ca38462012-07-26 22:44:55 -04001825 if (output == NULL)
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001826 return -1;
1827
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001828 output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
1829 output->base.make = "unknown";
1830 output->base.model = "unknown";
Richard Hughes2b2092a2013-04-24 14:58:02 +01001831 output->base.serial_number = "unknown";
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001832 wl_list_init(&output->base.mode_list);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04001833
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001834 if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
1835 type_name = connector_type_names[connector->connector_type];
1836 else
1837 type_name = "UNKNOWN";
1838 snprintf(name, 32, "%s%d", type_name, connector->connector_type_id);
Richard Hughesafe690c2013-05-02 10:10:04 +01001839 output->base.name = strdup(name);
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04001840
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001841 section = weston_config_get_section(ec->base.config, "output", "name",
1842 output->base.name);
1843 weston_config_section_get_string(section, "mode", &s, "preferred");
1844 if (strcmp(s, "off") == 0)
1845 config = OUTPUT_CONFIG_OFF;
1846 else if (strcmp(s, "preferred") == 0)
1847 config = OUTPUT_CONFIG_PREFERRED;
1848 else if (strcmp(s, "current") == 0)
1849 config = OUTPUT_CONFIG_CURRENT;
1850 else if (sscanf(s, "%dx%d", &width, &height) == 2)
1851 config = OUTPUT_CONFIG_MODE;
1852 else if (parse_modeline(s, &modeline) == 0)
1853 config = OUTPUT_CONFIG_MODELINE;
1854 else {
1855 weston_log("Invalid mode \"%s\" for output %s\n",
1856 s, output->base.name);
1857 config = OUTPUT_CONFIG_PREFERRED;
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001858 }
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001859 free(s);
1860
1861 weston_config_section_get_int(section, "scale", &scale, 1);
1862 weston_config_section_get_string(section, "transform", &s, "normal");
1863 transform = parse_transform(s, output->base.name);
1864 free(s);
Alexander Larssond9a7bb72013-05-22 14:41:39 +02001865
Rob Bradford66bd9f52013-06-25 18:56:42 +01001866 weston_config_section_get_string(section, "seat", &s, "");
1867 setup_output_seat_constraint(ec, &output->base, s);
1868 free(s);
1869
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001870 output->crtc_id = resources->crtcs[i];
Rob Clark5ca1a472012-08-08 20:27:37 -05001871 output->pipe = i;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001872 ec->crtc_allocator |= (1 << output->crtc_id);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04001873 output->connector_id = connector->connector_id;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01001874 ec->connector_allocator |= (1 << output->connector_id);
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001875
Matt Roper361d2ad2011-08-29 13:52:23 -07001876 output->original_crtc = drmModeGetCrtc(ec->drm.fd, output->crtc_id);
Ander Conselvan de Oliveiraa0a433a2013-06-04 16:24:04 +03001877 output->dpms_prop = drm_get_prop(ec->drm.fd, connector, "DPMS");
Matt Roper361d2ad2011-08-29 13:52:23 -07001878
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001879 /* Get the current mode on the crtc that's currently driving
1880 * this connector. */
1881 encoder = drmModeGetEncoder(ec->drm.fd, connector->encoder_id);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001882 memset(&crtc_mode, 0, sizeof crtc_mode);
1883 if (encoder != NULL) {
1884 crtc = drmModeGetCrtc(ec->drm.fd, encoder->crtc_id);
1885 drmModeFreeEncoder(encoder);
1886 if (crtc == NULL)
1887 goto err_free;
1888 if (crtc->mode_valid)
1889 crtc_mode = crtc->mode;
1890 drmModeFreeCrtc(crtc);
1891 }
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001892
David Herrmann0f0d54e2011-12-08 17:05:45 +01001893 for (i = 0; i < connector->count_modes; i++) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001894 drm_mode = drm_output_add_mode(output, &connector->modes[i]);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001895 if (!drm_mode)
David Herrmann0f0d54e2011-12-08 17:05:45 +01001896 goto err_free;
1897 }
1898
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001899 if (config == OUTPUT_CONFIG_OFF) {
1900 weston_log("Disabling output %s\n", output->base.name);
1901 drmModeSetCrtc(ec->drm.fd, output->crtc_id,
1902 0, 0, 0, 0, 0, NULL);
1903 goto err_free;
1904 }
1905
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001906 preferred = NULL;
1907 current = NULL;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001908 configured = NULL;
1909
Giulio Camuffoc0b94872013-06-19 15:19:19 +02001910 wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001911 if (config == OUTPUT_CONFIG_MODE &&
Alexander Larsson0b135062013-05-28 16:23:36 +02001912 width == drm_mode->base.width &&
1913 height == drm_mode->base.height)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001914 configured = drm_mode;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001915 if (!memcmp(&crtc_mode, &drm_mode->mode_info, sizeof crtc_mode))
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001916 current = drm_mode;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001917 if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001918 preferred = drm_mode;
David Herrmann0f0d54e2011-12-08 17:05:45 +01001919 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001920
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001921 if (config == OUTPUT_CONFIG_MODELINE) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001922 configured = drm_output_add_mode(output, &modeline);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001923 if (!configured)
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001924 goto err_free;
Scott Moreau8f37e0b2012-07-31 15:30:41 -06001925 }
1926
Wang Quanxianacb805a2012-07-30 18:09:46 -04001927 if (current == NULL && crtc_mode.clock != 0) {
Alexander Larsson0b135062013-05-28 16:23:36 +02001928 current = drm_output_add_mode(output, &crtc_mode);
Ander Conselvan de Oliveira42c46462012-08-09 16:45:00 +03001929 if (!current)
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001930 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001931 }
1932
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001933 if (config == OUTPUT_CONFIG_CURRENT)
Scott Moreau8ab5d452012-07-30 19:51:08 -06001934 configured = current;
1935
Wang Quanxianacb805a2012-07-30 18:09:46 -04001936 if (option_current_mode && current)
Hardeningff39efa2013-09-18 23:56:35 +02001937 output->base.current_mode = &current->base;
Scott Moreau8ab5d452012-07-30 19:51:08 -06001938 else if (configured)
Hardeningff39efa2013-09-18 23:56:35 +02001939 output->base.current_mode = &configured->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001940 else if (preferred)
Hardeningff39efa2013-09-18 23:56:35 +02001941 output->base.current_mode = &preferred->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001942 else if (current)
Hardeningff39efa2013-09-18 23:56:35 +02001943 output->base.current_mode = &current->base;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001944
Hardeningff39efa2013-09-18 23:56:35 +02001945 if (output->base.current_mode == NULL) {
Richard Hughesafe690c2013-05-02 10:10:04 +01001946 weston_log("no available modes for %s\n", output->base.name);
Wang Quanxianacb805a2012-07-30 18:09:46 -04001947 goto err_free;
Kristian Høgsberg061c4252012-06-28 11:28:15 -04001948 }
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -04001949
Hardeningff39efa2013-09-18 23:56:35 +02001950 output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
Wang Quanxianacb805a2012-07-30 18:09:46 -04001951
John Kåre Alsaker94659272012-11-13 19:10:18 +01001952 weston_output_init(&output->base, &ec->base, x, y,
1953 connector->mmWidth, connector->mmHeight,
Kristian Høgsberga30989a2013-05-23 17:23:15 -04001954 transform, scale);
John Kåre Alsaker94659272012-11-13 19:10:18 +01001955
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02001956 if (ec->use_pixman) {
1957 if (drm_output_init_pixman(output, ec) < 0) {
1958 weston_log("Failed to init output pixman state\n");
1959 goto err_output;
1960 }
1961 } else if (drm_output_init_egl(output, ec) < 0) {
Ander Conselvan de Oliveira475cf152012-12-14 13:37:29 -02001962 weston_log("Failed to init output gl state\n");
John Kåre Alsaker94659272012-11-13 19:10:18 +01001963 goto err_output;
Kristian Høgsberg1d1e0a52012-10-21 13:29:26 -04001964 }
Kristian Høgsberg8e1f77f2012-05-03 11:39:35 -04001965
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001966 output->backlight = backlight_init(drm_device,
1967 connector->connector_type);
1968 if (output->backlight) {
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001969 weston_log("Initialized backlight, device %s\n",
1970 output->backlight->path);
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001971 output->base.set_backlight = drm_set_backlight;
1972 output->base.backlight_current = drm_get_backlight(output);
Kristian Høgsberg220819f2013-05-23 20:29:40 -04001973 } else {
1974 weston_log("Failed to initialize backlight\n");
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001975 }
1976
Kristian Høgsberga4b7e202011-10-24 13:26:32 -04001977 wl_list_insert(ec->base.output_list.prev, &output->base.link);
1978
Richard Hughes2b2092a2013-04-24 14:58:02 +01001979 find_and_parse_output_edid(ec, output, connector);
Richard Hughesb24e48e2013-05-09 20:31:09 +01001980 if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1981 output->base.connection_internal = 1;
Richard Hughes2b2092a2013-04-24 14:58:02 +01001982
Jonas Ådahle5a12252013-04-05 23:07:11 +02001983 output->base.start_repaint_loop = drm_output_start_repaint_loop;
Kristian Høgsberg68c479a2012-01-25 23:32:28 -05001984 output->base.repaint = drm_output_repaint;
Matt Roper361d2ad2011-08-29 13:52:23 -07001985 output->base.destroy = drm_output_destroy;
Jesse Barnes58ef3792012-02-23 09:45:49 -05001986 output->base.assign_planes = drm_assign_planes;
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02001987 output->base.set_dpms = drm_set_dpms;
Alex Wub7b8bda2012-04-17 17:20:48 +08001988 output->base.switch_mode = drm_output_switch_mode;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01001989
Richard Hughese7299962013-05-01 21:52:12 +01001990 output->base.gamma_size = output->original_crtc->gamma_size;
1991 output->base.set_gamma = drm_output_set_gamma;
1992
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04001993 weston_plane_init(&output->cursor_plane, 0, 0);
1994 weston_plane_init(&output->fb_plane, 0, 0);
1995
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02001996 weston_compositor_stack_plane(&ec->base, &output->cursor_plane, NULL);
1997 weston_compositor_stack_plane(&ec->base, &output->fb_plane,
1998 &ec->base.primary_plane);
1999
Kristian Høgsberg2f9ed712012-07-26 17:57:15 -04002000 weston_log("Output %s, (connector %d, crtc %d)\n",
Richard Hughesafe690c2013-05-02 10:10:04 +01002001 output->base.name, output->connector_id, output->crtc_id);
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002002 wl_list_for_each(m, &output->base.mode_list, link)
2003 weston_log_continue(" mode %dx%d@%.1f%s%s%s\n",
2004 m->width, m->height, m->refresh / 1000.0,
2005 m->flags & WL_OUTPUT_MODE_PREFERRED ?
2006 ", preferred" : "",
2007 m->flags & WL_OUTPUT_MODE_CURRENT ?
2008 ", current" : "",
2009 connector->count_modes == 0 ?
2010 ", built-in" : "");
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002011
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002012 return 0;
David Herrmann0f0d54e2011-12-08 17:05:45 +01002013
John Kåre Alsaker94659272012-11-13 19:10:18 +01002014err_output:
2015 weston_output_destroy(&output->base);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002016err_free:
2017 wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
2018 base.link) {
2019 wl_list_remove(&drm_mode->base.link);
2020 free(drm_mode);
2021 }
2022
2023 drmModeFreeCrtc(output->original_crtc);
2024 ec->crtc_allocator &= ~(1 << output->crtc_id);
2025 ec->connector_allocator &= ~(1 << output->connector_id);
David Herrmann0f0d54e2011-12-08 17:05:45 +01002026 free(output);
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002027
David Herrmann0f0d54e2011-12-08 17:05:45 +01002028 return -1;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002029}
2030
Jesse Barnes58ef3792012-02-23 09:45:49 -05002031static void
2032create_sprites(struct drm_compositor *ec)
2033{
2034 struct drm_sprite *sprite;
2035 drmModePlaneRes *plane_res;
2036 drmModePlane *plane;
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002037 uint32_t i;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002038
2039 plane_res = drmModeGetPlaneResources(ec->drm.fd);
2040 if (!plane_res) {
Martin Minarik6d118362012-06-07 18:01:59 +02002041 weston_log("failed to get plane resources: %s\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002042 strerror(errno));
2043 return;
2044 }
2045
2046 for (i = 0; i < plane_res->count_planes; i++) {
2047 plane = drmModeGetPlane(ec->drm.fd, plane_res->planes[i]);
2048 if (!plane)
2049 continue;
2050
Peter Huttererf3d62272013-08-08 11:57:05 +10002051 sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
Jesse Barnes58ef3792012-02-23 09:45:49 -05002052 plane->count_formats));
2053 if (!sprite) {
Martin Minarik6d118362012-06-07 18:01:59 +02002054 weston_log("%s: out of memory\n",
Jesse Barnes58ef3792012-02-23 09:45:49 -05002055 __func__);
2056 free(plane);
2057 continue;
2058 }
2059
Jesse Barnes58ef3792012-02-23 09:45:49 -05002060 sprite->possible_crtcs = plane->possible_crtcs;
2061 sprite->plane_id = plane->plane_id;
Ander Conselvan de Oliveira8d360b42012-11-09 14:19:05 +02002062 sprite->current = NULL;
2063 sprite->next = NULL;
Jesse Barnes58ef3792012-02-23 09:45:49 -05002064 sprite->compositor = ec;
2065 sprite->count_formats = plane->count_formats;
2066 memcpy(sprite->formats, plane->formats,
Rob Clark8efbc8e2012-03-11 19:48:44 -05002067 plane->count_formats * sizeof(plane->formats[0]));
Jesse Barnes58ef3792012-02-23 09:45:49 -05002068 drmModeFreePlane(plane);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002069 weston_plane_init(&sprite->plane, 0, 0);
Ander Conselvan de Oliveira8ad19822013-03-05 17:30:27 +02002070 weston_compositor_stack_plane(&ec->base, &sprite->plane,
2071 &ec->base.primary_plane);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002072
2073 wl_list_insert(&ec->sprite_list, &sprite->link);
2074 }
2075
Samuel Iglesias Gonsalvezde466732013-06-13 10:03:33 +02002076 drmModeFreePlaneResources(plane_res);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002077}
2078
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002079static void
2080destroy_sprites(struct drm_compositor *compositor)
2081{
2082 struct drm_sprite *sprite, *next;
2083 struct drm_output *output;
2084
2085 output = container_of(compositor->base.output_list.next,
2086 struct drm_output, base.link);
2087
2088 wl_list_for_each_safe(sprite, next, &compositor->sprite_list, link) {
2089 drmModeSetPlane(compositor->drm.fd,
2090 sprite->plane_id,
2091 output->crtc_id, 0, 0,
2092 0, 0, 0, 0, 0, 0, 0, 0);
Ander Conselvan de Oliveira526d4612013-01-25 15:13:03 +02002093 drm_output_release_fb(output, sprite->current);
2094 drm_output_release_fb(output, sprite->next);
Kristian Høgsberg65a11e12012-08-03 11:30:18 -04002095 weston_plane_release(&sprite->plane);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002096 free(sprite);
2097 }
2098}
Jesse Barnes58ef3792012-02-23 09:45:49 -05002099
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002100static int
Kristian Høgsberg875ab9e2012-03-30 11:52:39 -04002101create_outputs(struct drm_compositor *ec, uint32_t option_connector,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002102 struct udev_device *drm_device)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002103{
2104 drmModeConnector *connector;
2105 drmModeRes *resources;
2106 int i;
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002107 int x = 0, y = 0;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002108
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002109 resources = drmModeGetResources(ec->drm.fd);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002110 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002111 weston_log("drmModeGetResources failed\n");
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002112 return -1;
2113 }
2114
Jesse Barnes58ef3792012-02-23 09:45:49 -05002115 ec->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002116 if (!ec->crtcs) {
2117 drmModeFreeResources(resources);
Jesse Barnes58ef3792012-02-23 09:45:49 -05002118 return -1;
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002119 }
Jesse Barnes58ef3792012-02-23 09:45:49 -05002120
Rob Clark4339add2012-08-09 14:18:28 -05002121 ec->min_width = resources->min_width;
2122 ec->max_width = resources->max_width;
2123 ec->min_height = resources->min_height;
2124 ec->max_height = resources->max_height;
2125
Jesse Barnes58ef3792012-02-23 09:45:49 -05002126 ec->num_crtcs = resources->count_crtcs;
2127 memcpy(ec->crtcs, resources->crtcs, sizeof(uint32_t) * ec->num_crtcs);
2128
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002129 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002130 connector = drmModeGetConnector(ec->drm.fd,
2131 resources->connectors[i]);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002132 if (connector == NULL)
2133 continue;
2134
2135 if (connector->connection == DRM_MODE_CONNECTED &&
2136 (option_connector == 0 ||
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002137 connector->connector_id == option_connector)) {
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002138 if (create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002139 connector, x, y,
2140 drm_device) < 0) {
Benjamin Franzke439d9862011-10-07 08:20:53 +02002141 drmModeFreeConnector(connector);
2142 continue;
2143 }
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002144
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002145 x += container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002146 struct weston_output,
Scott Moreau1bad5db2012-08-18 01:04:05 -06002147 link)->width;
Benjamin Franzke9eaee352011-08-02 13:03:54 +02002148 }
Benjamin Franzkeeefc36c2011-03-11 16:39:20 +01002149
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002150 drmModeFreeConnector(connector);
2151 }
2152
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002153 if (wl_list_empty(&ec->base.output_list)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002154 weston_log("No currently active connector found.\n");
Christopher Michaeleb866cd2012-03-07 14:55:21 -05002155 drmModeFreeResources(resources);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002156 return -1;
2157 }
2158
2159 drmModeFreeResources(resources);
2160
2161 return 0;
2162}
2163
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002164static void
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002165update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002166{
2167 drmModeConnector *connector;
2168 drmModeRes *resources;
2169 struct drm_output *output, *next;
2170 int x = 0, y = 0;
2171 int x_offset = 0, y_offset = 0;
2172 uint32_t connected = 0, disconnects = 0;
2173 int i;
2174
2175 resources = drmModeGetResources(ec->drm.fd);
2176 if (!resources) {
Martin Minarik6d118362012-06-07 18:01:59 +02002177 weston_log("drmModeGetResources failed\n");
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002178 return;
2179 }
2180
2181 /* collect new connects */
2182 for (i = 0; i < resources->count_connectors; i++) {
Benjamin Franzke117483d2011-08-30 11:38:26 +02002183 int connector_id = resources->connectors[i];
2184
2185 connector = drmModeGetConnector(ec->drm.fd, connector_id);
David Herrmann7551cff2011-12-08 17:05:43 +01002186 if (connector == NULL)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002187 continue;
2188
David Herrmann7551cff2011-12-08 17:05:43 +01002189 if (connector->connection != DRM_MODE_CONNECTED) {
2190 drmModeFreeConnector(connector);
2191 continue;
2192 }
2193
Benjamin Franzke117483d2011-08-30 11:38:26 +02002194 connected |= (1 << connector_id);
2195
2196 if (!(ec->connector_allocator & (1 << connector_id))) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002197 struct weston_output *last =
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002198 container_of(ec->base.output_list.prev,
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002199 struct weston_output, link);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002200
2201 /* XXX: not yet needed, we die with 0 outputs */
2202 if (!wl_list_empty(&ec->base.output_list))
Scott Moreau1bad5db2012-08-18 01:04:05 -06002203 x = last->x + last->width;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002204 else
2205 x = 0;
2206 y = 0;
2207 create_output_for_connector(ec, resources,
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002208 connector, x, y,
2209 drm_device);
Martin Minarik6d118362012-06-07 18:01:59 +02002210 weston_log("connector %d connected\n", connector_id);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002211
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002212 }
2213 drmModeFreeConnector(connector);
2214 }
2215 drmModeFreeResources(resources);
2216
2217 disconnects = ec->connector_allocator & ~connected;
2218 if (disconnects) {
2219 wl_list_for_each_safe(output, next, &ec->base.output_list,
2220 base.link) {
2221 if (x_offset != 0 || y_offset != 0) {
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002222 weston_output_move(&output->base,
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002223 output->base.x - x_offset,
2224 output->base.y - y_offset);
2225 }
2226
2227 if (disconnects & (1 << output->connector_id)) {
2228 disconnects &= ~(1 << output->connector_id);
Martin Minarik6d118362012-06-07 18:01:59 +02002229 weston_log("connector %d disconnected\n",
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002230 output->connector_id);
Scott Moreau1bad5db2012-08-18 01:04:05 -06002231 x_offset += output->base.width;
Benjamin Franzke48c4ea22011-08-30 11:44:56 +02002232 drm_output_destroy(&output->base);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002233 }
2234 }
2235 }
2236
2237 /* FIXME: handle zero outputs, without terminating */
2238 if (ec->connector_allocator == 0)
2239 wl_display_terminate(ec->base.wl_display);
2240}
2241
2242static int
David Herrmannd7488c22012-03-11 20:05:21 +01002243udev_event_is_hotplug(struct drm_compositor *ec, struct udev_device *device)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002244{
David Herrmannd7488c22012-03-11 20:05:21 +01002245 const char *sysnum;
David Herrmann6ac52db2012-03-11 20:05:22 +01002246 const char *val;
David Herrmannd7488c22012-03-11 20:05:21 +01002247
2248 sysnum = udev_device_get_sysnum(device);
2249 if (!sysnum || atoi(sysnum) != ec->drm.id)
2250 return 0;
Benjamin Franzke117483d2011-08-30 11:38:26 +02002251
David Herrmann6ac52db2012-03-11 20:05:22 +01002252 val = udev_device_get_property_value(device, "HOTPLUG");
2253 if (!val)
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002254 return 0;
2255
David Herrmann6ac52db2012-03-11 20:05:22 +01002256 return strcmp(val, "1") == 0;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002257}
2258
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002259static int
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002260udev_drm_event(int fd, uint32_t mask, void *data)
2261{
2262 struct drm_compositor *ec = data;
2263 struct udev_device *event;
2264
2265 event = udev_monitor_receive_device(ec->udev_monitor);
Benjamin Franzke117483d2011-08-30 11:38:26 +02002266
David Herrmannd7488c22012-03-11 20:05:21 +01002267 if (udev_event_is_hotplug(ec, event))
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002268 update_outputs(ec, event);
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002269
2270 udev_device_unref(event);
Kristian Høgsbergb1868472011-04-22 12:27:57 -04002271
2272 return 1;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002273}
2274
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002275static void
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002276drm_restore(struct weston_compositor *ec)
2277{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002278 weston_launcher_restore(ec->launcher);
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002279}
2280
2281static void
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002282drm_destroy(struct weston_compositor *ec)
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002283{
2284 struct drm_compositor *d = (struct drm_compositor *) ec;
2285
Rob Bradfordd355b802013-05-31 18:09:55 +01002286 udev_input_destroy(&d->input);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002287
2288 wl_event_source_remove(d->udev_drm_source);
2289 wl_event_source_remove(d->drm_source);
2290
Kristian Høgsberg3d64a3e2013-05-10 12:36:04 -04002291 destroy_sprites(d);
2292
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002293 weston_compositor_shutdown(ec);
Jonas Ådahlc97af922012-03-28 22:36:09 +02002294
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002295 ec->renderer->destroy(ec);
Kristian Høgsberg3a0de882012-09-06 21:44:24 -04002296
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002297 if (d->gbm)
2298 gbm_device_destroy(d->gbm);
2299
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002300 weston_launcher_destroy(d->base.launcher);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002301
Rob Bradford45c15b82013-07-26 16:29:35 +01002302 close(d->drm.fd);
2303
Kristian Høgsberge4762a62011-01-14 14:59:13 -05002304 free(d);
Kristian Høgsbergcaa64422010-12-01 16:52:15 -05002305}
2306
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002307static void
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002308drm_compositor_set_modes(struct drm_compositor *compositor)
2309{
2310 struct drm_output *output;
2311 struct drm_mode *drm_mode;
2312 int ret;
2313
2314 wl_list_for_each(output, &compositor->base.output_list, base.link) {
Ander Conselvan de Oliveira2002f882013-02-26 13:44:58 +02002315 if (!output->current) {
2316 /* If something that would cause the output to
2317 * switch mode happened while in another vt, we
2318 * might not have a current drm_fb. In that case,
2319 * schedule a repaint and let drm_output_repaint
2320 * handle setting the mode. */
2321 weston_output_schedule_repaint(&output->base);
2322 continue;
2323 }
2324
Hardeningff39efa2013-09-18 23:56:35 +02002325 drm_mode = (struct drm_mode *) output->base.current_mode;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002326 ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
Ander Conselvan de Oliveira555c17d2012-05-02 16:42:21 +03002327 output->current->fb_id, 0, 0,
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002328 &output->connector_id, 1,
2329 &drm_mode->mode_info);
2330 if (ret < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002331 weston_log(
Kristian Høgsbergcbcd0472012-03-11 18:27:41 -04002332 "failed to set mode %dx%d for output at %d,%d: %m\n",
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002333 drm_mode->base.width, drm_mode->base.height,
2334 output->base.x, output->base.y);
2335 }
2336 }
2337}
2338
2339static void
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002340session_notify(struct wl_listener *listener, void *data)
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002341{
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002342 struct weston_compositor *compositor = data;
2343 struct drm_compositor *ec = data;
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002344 struct drm_sprite *sprite;
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002345 struct drm_output *output;
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002346
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002347 if (ec->base.session_active) {
2348 weston_log("activating session\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002349 compositor->focus = 1;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002350 if (ec->base.launcher == NULL && drmSetMaster(ec->drm.fd)) {
Martin Minarik6d118362012-06-07 18:01:59 +02002351 weston_log("failed to set master: %m\n");
Kristian Høgsberga018fb02012-01-16 10:52:52 -05002352 wl_display_terminate(compositor->wl_display);
2353 }
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002354 compositor->state = ec->prev_state;
Kristian Høgsberg835cd492012-01-18 11:48:46 -05002355 drm_compositor_set_modes(ec);
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002356 weston_compositor_damage_all(compositor);
Rob Bradfordd355b802013-05-31 18:09:55 +01002357 udev_input_enable(&ec->input, ec->udev);
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002358 } else {
2359 weston_log("deactivating session\n");
Rob Bradfordd355b802013-05-31 18:09:55 +01002360 udev_input_disable(&ec->input);
Kristian Høgsberg4014a6b2012-04-10 00:08:45 -04002361
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002362 compositor->focus = 0;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002363 ec->prev_state = compositor->state;
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002364 weston_compositor_offscreen(compositor);
Kristian Høgsbergd8e181b2011-05-06 15:38:28 -04002365
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002366 /* If we have a repaint scheduled (either from a
2367 * pending pageflip or the idle handler), make sure we
2368 * cancel that so we don't try to pageflip when we're
Philipp Brüschweiler57edf7f2013-03-29 13:01:56 +01002369 * vt switched away. The OFFSCREEN state will prevent
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002370 * further attemps at repainting. When we switch
2371 * back, we schedule a repaint, which will process
2372 * pending frame callbacks. */
2373
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002374 wl_list_for_each(output, &ec->base.output_list, base.link) {
2375 output->base.repaint_needed = 0;
2376 drmModeSetCursor(ec->drm.fd, output->crtc_id, 0, 0, 0);
Kristian Høgsberg34f80ff2012-01-18 11:50:31 -05002377 }
2378
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002379 output = container_of(ec->base.output_list.next,
2380 struct drm_output, base.link);
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002381
2382 wl_list_for_each(sprite, &ec->sprite_list, link)
2383 drmModeSetPlane(ec->drm.fd,
2384 sprite->plane_id,
Kristian Høgsberga6edab32012-07-14 01:06:28 -04002385 output->crtc_id, 0, 0,
Kristian Høgsberg85fd3272012-02-23 21:45:32 -05002386 0, 0, 0, 0, 0, 0, 0, 0);
2387
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -07002388 if (ec->base.launcher == NULL && drmDropMaster(ec->drm.fd) < 0)
Martin Minarik6d118362012-06-07 18:01:59 +02002389 weston_log("failed to drop master: %m\n");
Kristian Høgsberg9396fc52011-05-06 15:15:37 -04002390 };
2391}
2392
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002393static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002394switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002395{
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002396 struct weston_compositor *compositor = data;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002397
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002398 weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002399}
2400
David Herrmann0af066f2012-10-29 19:21:16 +01002401/*
2402 * Find primary GPU
2403 * Some systems may have multiple DRM devices attached to a single seat. This
2404 * function loops over all devices and tries to find a PCI device with the
2405 * boot_vga sysfs attribute set to 1.
2406 * If no such device is found, the first DRM device reported by udev is used.
2407 */
2408static struct udev_device*
2409find_primary_gpu(struct drm_compositor *ec, const char *seat)
2410{
2411 struct udev_enumerate *e;
2412 struct udev_list_entry *entry;
2413 const char *path, *device_seat, *id;
2414 struct udev_device *device, *drm_device, *pci;
2415
2416 e = udev_enumerate_new(ec->udev);
2417 udev_enumerate_add_match_subsystem(e, "drm");
2418 udev_enumerate_add_match_sysname(e, "card[0-9]*");
2419
2420 udev_enumerate_scan_devices(e);
2421 drm_device = NULL;
2422 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
2423 path = udev_list_entry_get_name(entry);
2424 device = udev_device_new_from_syspath(ec->udev, path);
2425 if (!device)
2426 continue;
2427 device_seat = udev_device_get_property_value(device, "ID_SEAT");
2428 if (!device_seat)
2429 device_seat = default_seat;
2430 if (strcmp(device_seat, seat)) {
2431 udev_device_unref(device);
2432 continue;
2433 }
2434
2435 pci = udev_device_get_parent_with_subsystem_devtype(device,
2436 "pci", NULL);
2437 if (pci) {
2438 id = udev_device_get_sysattr_value(pci, "boot_vga");
2439 if (id && !strcmp(id, "1")) {
2440 if (drm_device)
2441 udev_device_unref(drm_device);
2442 drm_device = device;
2443 break;
2444 }
2445 }
2446
2447 if (!drm_device)
2448 drm_device = device;
2449 else
2450 udev_device_unref(device);
2451 }
2452
2453 udev_enumerate_unref(e);
2454 return drm_device;
2455}
2456
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002457static void
Kristian Høgsberge3148752013-05-06 23:19:49 -04002458planes_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *data)
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002459{
2460 struct drm_compositor *c = data;
2461
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002462 switch (key) {
2463 case KEY_C:
2464 c->cursors_are_broken ^= 1;
2465 break;
2466 case KEY_V:
2467 c->sprites_are_broken ^= 1;
2468 break;
2469 case KEY_O:
2470 c->sprites_hidden ^= 1;
2471 break;
2472 default:
2473 break;
2474 }
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002475}
2476
Kristian Høgsberg0eac34a2013-08-30 14:28:22 -07002477#ifdef BUILD_VAAPI_RECORDER
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002478static void
2479recorder_frame_notify(struct wl_listener *listener, void *data)
2480{
2481 struct drm_output *output;
2482 struct drm_compositor *c;
2483 int fd, ret;
2484
2485 output = container_of(listener, struct drm_output,
2486 recorder_frame_listener);
2487 c = (struct drm_compositor *) output->base.compositor;
2488
2489 if (!output->recorder)
2490 return;
2491
2492 ret = drmPrimeHandleToFD(c->drm.fd, output->current->handle,
2493 DRM_CLOEXEC, &fd);
2494 if (ret) {
2495 weston_log("[libva recorder] "
2496 "failed to create prime fd for front buffer\n");
2497 return;
2498 }
2499
2500 vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002501}
2502
2503static void *
2504create_recorder(struct drm_compositor *c, int width, int height,
2505 const char *filename)
2506{
2507 int fd;
2508 drm_magic_t magic;
2509
2510 fd = open(c->drm.filename, O_RDWR | O_CLOEXEC);
2511 if (fd < 0)
2512 return NULL;
2513
2514 drmGetMagic(fd, &magic);
2515 drmAuthMagic(c->drm.fd, magic);
2516
2517 return vaapi_recorder_create(fd, width, height, filename);
2518}
2519
2520static void
2521recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2522 void *data)
2523{
2524 struct drm_compositor *c = data;
2525 struct drm_output *output;
2526 int width, height;
2527
2528 output = container_of(c->base.output_list.next,
2529 struct drm_output, base.link);
2530
2531 if (!output->recorder) {
Hardeningff39efa2013-09-18 23:56:35 +02002532 width = output->base.current_mode->width;
2533 height = output->base.current_mode->height;
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002534
2535 output->recorder =
2536 create_recorder(c, width, height, "capture.h264");
2537 if (!output->recorder) {
2538 weston_log("failed to create vaapi recorder\n");
2539 return;
2540 }
2541
2542 output->base.disable_planes++;
2543
2544 output->recorder_frame_listener.notify = recorder_frame_notify;
2545 wl_signal_add(&output->base.frame_signal,
2546 &output->recorder_frame_listener);
2547
2548 weston_output_schedule_repaint(&output->base);
2549
2550 weston_log("[libva recorder] initialized\n");
2551 } else {
2552 vaapi_recorder_destroy(output->recorder);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002553 output->recorder = NULL;
2554
2555 output->base.disable_planes--;
2556
2557 wl_list_remove(&output->recorder_frame_listener.link);
2558 weston_log("[libva recorder] done\n");
2559 }
2560}
2561#else
2562static void
2563recorder_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
2564 void *data)
2565{
2566 weston_log("Compiled without libva support\n");
2567}
2568#endif
2569
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002570static struct weston_compositor *
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002571drm_compositor_create(struct wl_display *display,
Rob Bradford643641d2013-05-31 18:09:53 +01002572 int connector, const char *seat_id, int tty, int pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002573 int *argc, char *argv[],
2574 struct weston_config *config)
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002575{
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002576 struct drm_compositor *ec;
David Herrmann0af066f2012-10-29 19:21:16 +01002577 struct udev_device *drm_device;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002578 struct wl_event_loop *loop;
David Herrmann0af066f2012-10-29 19:21:16 +01002579 const char *path;
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002580 uint32_t key;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002581
Kristian Høgsbergfc9c5e02012-06-08 16:45:33 -04002582 weston_log("initializing drm backend\n");
2583
Peter Huttererf3d62272013-08-08 11:57:05 +10002584 ec = zalloc(sizeof *ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002585 if (ec == NULL)
2586 return NULL;
Daniel Stone725c2c32012-06-22 14:04:36 +01002587
Kristian Høgsbergde37d672012-11-02 10:14:40 -04002588 /* KMS support for sprites is not complete yet, so disable the
2589 * functionality for now. */
2590 ec->sprites_are_broken = 1;
Kristian Høgsbergc3ea26c2013-09-25 15:46:42 -07002591 ec->format = GBM_FORMAT_XRGB8888;
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002592 ec->use_pixman = pixman;
2593
Daniel Stone725c2c32012-06-22 14:04:36 +01002594 if (weston_compositor_init(&ec->base, display, argc, argv,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002595 config) < 0) {
Scott Moreau8eb67482013-02-23 12:04:56 -07002596 weston_log("%s failed\n", __func__);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002597 goto err_base;
2598 }
Daniel Stone725c2c32012-06-22 14:04:36 +01002599
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002600 /* Check if we run drm-backend using weston-launch */
Kristian Høgsberg6ff3ff52013-10-02 10:53:33 -07002601 ec->base.launcher = weston_launcher_connect(&ec->base, tty);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002602 if (ec->base.launcher == NULL) {
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002603 weston_log("fatal: drm backend should be run "
Kristian Høgsbergb76237e2013-04-04 21:36:20 -04002604 "using weston-launch binary or as root\n");
Rafal Mielniczuk32069c02013-03-27 18:39:28 +01002605 goto err_compositor;
2606 }
2607
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002608 ec->udev = udev_new();
2609 if (ec->udev == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002610 weston_log("failed to initialize udev context\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002611 goto err_launcher;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002612 }
2613
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002614 ec->base.wl_display = display;
Kristian Høgsberg61741a22013-09-17 16:02:57 -07002615 ec->session_listener.notify = session_notify;
2616 wl_signal_add(&ec->base.session_signal, &ec->session_listener);
Kristian Høgsbergc5b9ddb2012-01-15 14:29:09 -05002617
Rob Bradford643641d2013-05-31 18:09:53 +01002618 drm_device = find_primary_gpu(ec, seat_id);
Kristian Høgsberg8d51f142011-07-15 21:28:38 -04002619 if (drm_device == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002620 weston_log("no drm device found\n");
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002621 goto err_udev;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002622 }
David Herrmann0af066f2012-10-29 19:21:16 +01002623 path = udev_device_get_syspath(drm_device);
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002624
Ander Conselvan de Oliveira22929172013-01-25 15:13:02 +02002625 if (init_drm(ec, drm_device) < 0) {
2626 weston_log("failed to initialize kms\n");
2627 goto err_udev_dev;
2628 }
2629
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002630 if (ec->use_pixman) {
2631 if (init_pixman(ec) < 0) {
2632 weston_log("failed to initialize pixman renderer\n");
2633 goto err_udev_dev;
2634 }
2635 } else {
2636 if (init_egl(ec) < 0) {
2637 weston_log("failed to initialize egl\n");
2638 goto err_udev_dev;
2639 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002640 }
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002641
2642 ec->base.destroy = drm_destroy;
Kristian Høgsberg7b884bc2012-07-31 14:32:01 -04002643 ec->base.restore = drm_restore;
Benjamin Franzke431da9a2011-04-20 11:02:58 +02002644
Kristian Høgsberg8525a502011-01-14 16:20:21 -05002645 ec->base.focus = 1;
2646
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002647 ec->prev_state = WESTON_COMPOSITOR_ACTIVE;
Pekka Paalanenbce2d3f2011-12-02 13:07:27 +02002648
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002649 for (key = KEY_F1; key < KEY_F9; key++)
Daniel Stone325fc2d2012-05-30 16:31:58 +01002650 weston_compositor_add_key_binding(&ec->base, key,
2651 MODIFIER_CTRL | MODIFIER_ALT,
2652 switch_vt_binding, ec);
Kristian Høgsberg5d1c0c52012-04-10 00:11:50 -04002653
Jesse Barnes58ef3792012-02-23 09:45:49 -05002654 wl_list_init(&ec->sprite_list);
2655 create_sprites(ec);
2656
Tiago Vignatti8e53c7f2012-02-29 19:53:50 +02002657 if (create_outputs(ec, connector, drm_device) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002658 weston_log("failed to create output for %s\n", path);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002659 goto err_sprite;
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002660 }
2661
Benjamin Franzke02dee2c2011-10-07 08:27:26 +02002662 path = NULL;
2663
Rob Bradfordd355b802013-05-31 18:09:55 +01002664 if (udev_input_init(&ec->input, &ec->base, ec->udev, seat_id) < 0) {
Kristian Høgsberg2f07ef62013-02-16 14:29:24 -05002665 weston_log("failed to create input devices\n");
2666 goto err_sprite;
2667 }
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002668
2669 loop = wl_display_get_event_loop(ec->base.wl_display);
2670 ec->drm_source =
Benjamin Franzke2af7f102011-03-02 11:14:59 +01002671 wl_event_loop_add_fd(loop, ec->drm.fd,
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002672 WL_EVENT_READABLE, on_drm_input, ec);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002673
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002674 ec->udev_monitor = udev_monitor_new_from_netlink(ec->udev, "udev");
2675 if (ec->udev_monitor == NULL) {
Martin Minarik6d118362012-06-07 18:01:59 +02002676 weston_log("failed to intialize udev monitor\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002677 goto err_drm_source;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002678 }
2679 udev_monitor_filter_add_match_subsystem_devtype(ec->udev_monitor,
2680 "drm", NULL);
2681 ec->udev_drm_source =
Benjamin Franzke117483d2011-08-30 11:38:26 +02002682 wl_event_loop_add_fd(loop,
2683 udev_monitor_get_fd(ec->udev_monitor),
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002684 WL_EVENT_READABLE, udev_drm_event, ec);
2685
2686 if (udev_monitor_enable_receiving(ec->udev_monitor) < 0) {
Martin Minarik6d118362012-06-07 18:01:59 +02002687 weston_log("failed to enable udev-monitor receiving\n");
Daniel Stonea96b93c2012-06-22 14:04:37 +01002688 goto err_udev_monitor;
Benjamin Franzke9c26ff32011-03-15 15:08:41 +01002689 }
2690
Daniel Stonea96b93c2012-06-22 14:04:37 +01002691 udev_device_unref(drm_device);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002692
Ander Conselvan de Oliveirac509d2b2012-11-08 17:20:45 +02002693 weston_compositor_add_debug_binding(&ec->base, KEY_O,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002694 planes_binding, ec);
Ander Conselvan de Oliveira180f42a2012-11-21 15:11:37 +02002695 weston_compositor_add_debug_binding(&ec->base, KEY_C,
Ander Conselvan de Oliveira7e918da2012-11-22 15:56:59 +02002696 planes_binding, ec);
2697 weston_compositor_add_debug_binding(&ec->base, KEY_V,
2698 planes_binding, ec);
Ander Conselvan de Oliveira6aae4d32013-08-23 17:15:48 +03002699 weston_compositor_add_debug_binding(&ec->base, KEY_Q,
2700 recorder_binding, ec);
Ander Conselvan de Oliveirada1c9082012-10-31 17:55:46 +02002701
Kristian Høgsbergce5325d2010-06-14 11:54:00 -04002702 return &ec->base;
Daniel Stonea96b93c2012-06-22 14:04:37 +01002703
2704err_udev_monitor:
2705 wl_event_source_remove(ec->udev_drm_source);
2706 udev_monitor_unref(ec->udev_monitor);
2707err_drm_source:
2708 wl_event_source_remove(ec->drm_source);
Rob Bradfordd355b802013-05-31 18:09:55 +01002709 udev_input_destroy(&ec->input);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002710err_sprite:
Vasily Khoruzhick52cfd612013-01-08 19:09:01 +03002711 ec->base.renderer->destroy(&ec->base);
John Kåre Alsaker1b7ad162012-11-13 19:10:19 +01002712 gbm_device_destroy(ec->gbm);
Kristian Høgsberg2bc5e8e2012-09-06 20:51:00 -04002713 destroy_sprites(ec);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002714err_udev_dev:
2715 udev_device_unref(drm_device);
Kristian Høgsberg3f495872013-09-18 23:00:17 -07002716err_launcher:
2717 weston_launcher_destroy(ec->base.launcher);
Daniel Stonea96b93c2012-06-22 14:04:37 +01002718err_udev:
2719 udev_unref(ec->udev);
2720err_compositor:
2721 weston_compositor_shutdown(&ec->base);
2722err_base:
2723 free(ec);
2724 return NULL;
Kristian Høgsbergfc783d42010-06-11 12:56:24 -04002725}
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002726
Kristian Høgsberg8334bc12012-01-03 10:29:47 -05002727WL_EXPORT struct weston_compositor *
Kristian Høgsberg4172f662013-02-20 15:27:49 -05002728backend_init(struct wl_display *display, int *argc, char *argv[],
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002729 struct weston_config *config)
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002730{
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002731 int connector = 0, tty = 0, use_pixman = 0;
Rob Bradford643641d2013-05-31 18:09:53 +01002732 const char *seat_id = default_seat;
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002733
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002734 const struct weston_option drm_options[] = {
2735 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
Rob Bradford643641d2013-05-31 18:09:53 +01002736 { WESTON_OPTION_STRING, "seat", 0, &seat_id },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002737 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
Kristian Høgsberg061c4252012-06-28 11:28:15 -04002738 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &option_current_mode },
Ander Conselvan de Oliveira5fb44142013-01-25 15:13:05 +02002739 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002740 };
Benjamin Franzke117483d2011-08-30 11:38:26 +02002741
Kristian Høgsbergbcacef12012-03-11 21:05:57 -04002742 parse_options(drm_options, ARRAY_LENGTH(drm_options), argc, argv);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002743
Rob Bradford643641d2013-05-31 18:09:53 +01002744 return drm_compositor_create(display, connector, seat_id, tty, use_pixman,
Kristian Høgsberg14e438c2013-05-26 21:48:14 -04002745 argc, argv, config);
Kristian Høgsberg1c562182011-05-02 22:09:20 -04002746}