compositor-drm.c 67.6 KB
Newer Older
1
/*
2 3
 * Copyright © 2008-2011 Kristian Høgsberg
 * Copyright © 2011 Intel Corporation
4
 *
5 6 7 8 9 10 11 12 13
 * Permission to use, copy, modify, distribute, and sell this software and
 * its documentation for any purpose is hereby granted without fee, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of the copyright holders not be used in
 * advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  The copyright holders make
 * no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
14
 *
15 16 17 18 19 20 21
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 23
 */

24
#include "config.h"
25

26
#include <errno.h>
27
#include <stdlib.h>
28
#include <ctype.h>
29 30 31
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
32
#include <linux/input.h>
33
#include <linux/vt.h>
34
#include <assert.h>
35
#include <sys/mman.h>
36
#include <time.h>
37

38 39
#include <xf86drm.h>
#include <xf86drmMode.h>
40
#include <drm_fourcc.h>
41

42
#include <gbm.h>
43
#include <libbacklight.h>
44
#include <libudev.h>
45

46
#include "compositor.h"
47
#include "gl-renderer.h"
48
#include "pixman-renderer.h"
49
#include "udev-seat.h"
50
#include "launcher-util.h"
51
#include "vaapi-recorder.h"
52

53 54 55 56
#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
#endif

57
static int option_current_mode = 0;
58 59 60 61 62 63

enum output_config {
	OUTPUT_CONFIG_INVALID = 0,
	OUTPUT_CONFIG_OFF,
	OUTPUT_CONFIG_PREFERRED,
	OUTPUT_CONFIG_CURRENT,
Scott Moreau's avatar
Scott Moreau committed
64 65
	OUTPUT_CONFIG_MODE,
	OUTPUT_CONFIG_MODELINE
66 67
};

68
struct drm_compositor {
69
	struct weston_compositor base;
70 71 72 73

	struct udev *udev;
	struct wl_event_source *drm_source;

74 75 76
	struct udev_monitor *udev_monitor;
	struct wl_event_source *udev_drm_source;

77
	struct {
78
		int id;
79
		int fd;
80
		char *filename;
81
	} drm;
82
	struct gbm_device *gbm;
83 84
	uint32_t *crtcs;
	int num_crtcs;
85
	uint32_t crtc_allocator;
86
	uint32_t connector_allocator;
87
	struct wl_listener session_listener;
88

89 90 91 92
	/* we need these parameters in order to not fail drmModeAddFB2()
	 * due to out of bounds dimensions, and then mistakenly set
	 * sprites_are_broken:
	 */
93 94 95
	uint32_t min_width, max_width;
	uint32_t min_height, max_height;
	int no_addfb2;
96

97
	struct wl_list sprite_list;
98
	int sprites_are_broken;
99
	int sprites_hidden;
100

101 102
	int cursors_are_broken;

103 104
	int use_pixman;

105
	uint32_t prev_state;
106 107

	clockid_t clock;
108
	struct udev_input input;
109 110
};

111
struct drm_mode {
112
	struct weston_mode base;
113 114 115
	drmModeModeInfo mode_info;
};

116 117 118 119
struct drm_output;

struct drm_fb {
	struct drm_output *output;
120 121
	uint32_t fb_id, stride, handle, size;
	int fd;
122
	int is_client_buffer;
123
	struct weston_buffer_reference buffer_ref;
124 125 126 127 128 129

	/* Used by gbm fbs */
	struct gbm_bo *bo;

	/* Used by dumb fbs */
	void *map;
130 131
};

132 133 134 135 136 137 138
struct drm_edid {
	char eisa_id[13];
	char monitor_name[13];
	char pnp_id[5];
	char serial_number[13];
};

139
struct drm_output {
140
	struct weston_output   base;
141 142

	uint32_t crtc_id;
143
	int pipe;
144
	uint32_t connector_id;
145
	drmModeCrtcPtr original_crtc;
146
	struct drm_edid edid;
147
	drmModePropertyPtr dpms_prop;
148

149 150 151
	int vblank_pending;
	int page_flip_pending;

152
	struct gbm_surface *surface;
153
	struct gbm_bo *cursor_bo[2];
154 155
	struct weston_plane cursor_plane;
	struct weston_plane fb_plane;
156 157
	struct weston_surface *cursor_surface;
	int current_cursor;
158
	struct drm_fb *current, *next;
159
	struct backlight *backlight;
160 161 162 163 164

	struct drm_fb *dumb[2];
	pixman_image_t *image[2];
	int current_image;
	pixman_region32_t previous_damage;
165 166 167

	struct vaapi_recorder *recorder;
	struct wl_listener recorder_frame_listener;
168 169
};

170 171 172 173 174 175 176
/*
 * An output has a primary display plane plus zero or more sprites for
 * blending display contents.
 */
struct drm_sprite {
	struct wl_list link;

177
	struct weston_plane plane;
178

179
	struct drm_fb *current, *next;
180
	struct drm_output *output;
181 182 183 184 185 186 187 188 189 190 191 192 193 194
	struct drm_compositor *compositor;

	uint32_t possible_crtcs;
	uint32_t plane_id;
	uint32_t count_formats;

	int32_t src_x, src_y;
	uint32_t src_w, src_h;
	uint32_t dest_x, dest_y;
	uint32_t dest_w, dest_h;

	uint32_t formats[];
};

195
static const char default_seat[] = "seat0";
196

197 198 199
static void
drm_output_set_cursor(struct drm_output *output);

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
static int
drm_sprite_crtc_supported(struct weston_output *output_base, uint32_t supported)
{
	struct weston_compositor *ec = output_base->compositor;
	struct drm_compositor *c =(struct drm_compositor *) ec;
	struct drm_output *output = (struct drm_output *) output_base;
	int crtc;

	for (crtc = 0; crtc < c->num_crtcs; crtc++) {
		if (c->crtcs[crtc] != output->crtc_id)
			continue;

		if (supported & (1 << crtc))
			return -1;
	}

	return 0;
}

219 220 221 222 223 224 225 226 227
static void
drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
{
	struct drm_fb *fb = data;
	struct gbm_device *gbm = gbm_bo_get_device(bo);

	if (fb->fb_id)
		drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);

228
	weston_buffer_reference(&fb->buffer_ref, NULL);
229 230 231 232

	free(data);
}

233 234 235 236 237 238 239 240 241 242
static struct drm_fb *
drm_fb_create_dumb(struct drm_compositor *ec, unsigned width, unsigned height)
{
	struct drm_fb *fb;
	int ret;

	struct drm_mode_create_dumb create_arg;
	struct drm_mode_destroy_dumb destroy_arg;
	struct drm_mode_map_dumb map_arg;

243
	fb = zalloc(sizeof *fb);
244 245 246
	if (!fb)
		return NULL;

247
	memset(&create_arg, 0, sizeof create_arg);
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	create_arg.bpp = 32;
	create_arg.width = width;
	create_arg.height = height;

	ret = drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
	if (ret)
		goto err_fb;

	fb->handle = create_arg.handle;
	fb->stride = create_arg.pitch;
	fb->size = create_arg.size;
	fb->fd = ec->drm.fd;

	ret = drmModeAddFB(ec->drm.fd, width, height, 24, 32,
			   fb->stride, fb->handle, &fb->fb_id);
	if (ret)
		goto err_bo;

266
	memset(&map_arg, 0, sizeof map_arg);
267
	map_arg.handle = fb->handle;
268
	ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
	if (ret)
		goto err_add_fb;

	fb->map = mmap(0, fb->size, PROT_WRITE,
		       MAP_SHARED, ec->drm.fd, map_arg.offset);
	if (fb->map == MAP_FAILED)
		goto err_add_fb;

	return fb;

err_add_fb:
	drmModeRmFB(ec->drm.fd, fb->fb_id);
err_bo:
	memset(&destroy_arg, 0, sizeof(destroy_arg));
	destroy_arg.handle = create_arg.handle;
	drmIoctl(ec->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
err_fb:
	free(fb);
	return NULL;
}

static void
drm_fb_destroy_dumb(struct drm_fb *fb)
{
	struct drm_mode_destroy_dumb destroy_arg;

	if (!fb->map)
		return;

	if (fb->fb_id)
		drmModeRmFB(fb->fd, fb->fb_id);

	weston_buffer_reference(&fb->buffer_ref, NULL);

	munmap(fb->map, fb->size);

	memset(&destroy_arg, 0, sizeof(destroy_arg));
	destroy_arg.handle = fb->handle;
	drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);

	free(fb);
}

312
static struct drm_fb *
313 314
drm_fb_get_from_bo(struct gbm_bo *bo,
		   struct drm_compositor *compositor, uint32_t format)
315 316
{
	struct drm_fb *fb = gbm_bo_get_user_data(bo);
317
	uint32_t width, height;
318
	uint32_t handles[4], pitches[4], offsets[4];
319 320 321 322 323
	int ret;

	if (fb)
		return fb;

324 325 326
	fb = calloc(1, sizeof *fb);
	if (!fb)
		return NULL;
327 328 329 330 331

	fb->bo = bo;

	width = gbm_bo_get_width(bo);
	height = gbm_bo_get_height(bo);
332 333 334 335
	fb->stride = gbm_bo_get_stride(bo);
	fb->handle = gbm_bo_get_handle(bo).u32;
	fb->size = fb->stride * height;
	fb->fd = compositor->drm.fd;
336

337 338 339 340 341 342 343 344 345 346
	if (compositor->min_width > width || width > compositor->max_width ||
	    compositor->min_height > height ||
	    height > compositor->max_height) {
		weston_log("bo geometry out of bounds\n");
		goto err_free;
	}

	ret = -1;

	if (format && !compositor->no_addfb2) {
347 348
		handles[0] = fb->handle;
		pitches[0] = fb->stride;
349 350 351 352 353 354 355 356 357 358 359 360 361 362
		offsets[0] = 0;

		ret = drmModeAddFB2(compositor->drm.fd, width, height,
				    format, handles, pitches, offsets,
				    &fb->fb_id, 0);
		if (ret) {
			weston_log("addfb2 failed: %m\n");
			compositor->no_addfb2 = 1;
			compositor->sprites_are_broken = 1;
		}
	}

	if (ret)
		ret = drmModeAddFB(compositor->drm.fd, width, height, 24, 32,
363
				   fb->stride, fb->handle, &fb->fb_id);
364

365
	if (ret) {
366
		weston_log("failed to create kms fb: %m\n");
367
		goto err_free;
368 369 370 371 372
	}

	gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);

	return fb;
373 374 375 376

err_free:
	free(fb);
	return NULL;
377 378
}

379
static void
380
drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
381
{
382
	assert(fb->buffer_ref.buffer == NULL);
383 384 385

	fb->is_client_buffer = 1;

386
	weston_buffer_reference(&fb->buffer_ref, buffer);
387 388
}

389 390 391 392 393 394
static void
drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
{
	if (!fb)
		return;

395 396
	if (fb->map &&
            (fb != output->dumb[0] && fb != output->dumb[1])) {
397 398
		drm_fb_destroy_dumb(fb);
	} else if (fb->bo) {
399 400 401 402 403 404 405 406
		if (fb->is_client_buffer)
			gbm_bo_destroy(fb->bo);
		else
			gbm_surface_release_buffer(output->surface,
						   output->current->bo);
	}
}

407
static uint32_t
408 409 410 411 412 413 414 415
drm_output_check_scanout_format(struct drm_output *output,
				struct weston_surface *es, struct gbm_bo *bo)
{
	uint32_t format;
	pixman_region32_t r;

	format = gbm_bo_get_format(bo);

416 417 418 419
	switch (format) {
	case GBM_FORMAT_XRGB8888:
		return format;
	case GBM_FORMAT_ARGB8888:
420 421 422 423 424 425 426
		/* We can only scanout an ARGB buffer if the surface's
		 * opaque region covers the whole output */
		pixman_region32_init(&r);
		pixman_region32_subtract(&r, &output->base.region,
					 &es->opaque);

		if (!pixman_region32_not_empty(&r))
427 428 429
			format = GBM_FORMAT_XRGB8888;
		else
			format = 0;
430 431 432

		pixman_region32_fini(&r);

433 434 435 436
		return format;
	default:
		return 0;
	}
437 438
}

439
static struct weston_plane *
440 441
drm_output_prepare_scanout_surface(struct weston_output *_output,
				   struct weston_surface *es)
442
{
443
	struct drm_output *output = (struct drm_output *) _output;
444 445
	struct drm_compositor *c =
		(struct drm_compositor *) output->base.compositor;
446
	struct weston_buffer *buffer = es->buffer_ref.buffer;
447
	struct gbm_bo *bo;
448
	uint32_t format;
449

450
	if (es->geometry.x != output->base.x ||
451
	    es->geometry.y != output->base.y ||
452
	    buffer == NULL || c->gbm == NULL ||
453 454
	    buffer->width != output->base.current->width ||
	    buffer->height != output->base.current->height ||
455 456
	    output->base.transform != es->buffer_transform ||
	    es->transform.enabled)
457
		return NULL;
458

459
	bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
460
			   buffer->resource, GBM_BO_USE_SCANOUT);
461

462 463 464 465
	/* Unable to use the buffer for scanout */
	if (!bo)
		return NULL;

466 467
	format = drm_output_check_scanout_format(output, es, bo);
	if (format == 0) {
468
		gbm_bo_destroy(bo);
469
		return NULL;
470 471
	}

472
	output->next = drm_fb_get_from_bo(bo, c, format);
473 474
	if (!output->next) {
		gbm_bo_destroy(bo);
475
		return NULL;
476
	}
477

478
	drm_fb_set_buffer(output->next, buffer);
479

480
	return &output->fb_plane;
481 482
}

483
static void
484
drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
485
{
486 487
	struct drm_compositor *c =
		(struct drm_compositor *) output->base.compositor;
488
	struct gbm_bo *bo;
489

490
	c->base.renderer->repaint_output(&output->base, damage);
491

492 493
	bo = gbm_surface_lock_front_buffer(output->surface);
	if (!bo) {
494
		weston_log("failed to lock front buffer: %m\n");
495 496
		return;
	}
497

498
	output->next = drm_fb_get_from_bo(bo, c, GBM_FORMAT_XRGB8888);
499
	if (!output->next) {
500
		weston_log("failed to get drm_fb for bo\n");
501 502 503
		gbm_surface_release_buffer(output->surface, bo);
		return;
	}
504 505
}

506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
static void
drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
{
	struct weston_compositor *ec = output->base.compositor;
	pixman_region32_t total_damage, previous_damage;

	pixman_region32_init(&total_damage);
	pixman_region32_init(&previous_damage);

	pixman_region32_copy(&previous_damage, damage);

	pixman_region32_union(&total_damage, damage, &output->previous_damage);
	pixman_region32_copy(&output->previous_damage, &previous_damage);

	output->current_image ^= 1;

	output->next = output->dumb[output->current_image];
	pixman_renderer_output_set_buffer(&output->base,
					  output->image[output->current_image]);

	ec->renderer->repaint_output(&output->base, &total_damage);

	pixman_region32_fini(&total_damage);
	pixman_region32_fini(&previous_damage);
}

static void
drm_output_render(struct drm_output *output, pixman_region32_t *damage)
{
	struct drm_compositor *c =
		(struct drm_compositor *) output->base.compositor;

	if (c->use_pixman)
		drm_output_render_pixman(output, damage);
	else
		drm_output_render_gl(output, damage);

	pixman_region32_subtract(&c->base.primary_plane.damage,
				 &c->base.primary_plane.damage, damage);
}

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
static void
drm_output_set_gamma(struct weston_output *output_base,
		     uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
{
	int rc;
	struct drm_output *output = (struct drm_output *) output_base;
	struct drm_compositor *compositor = (struct drm_compositor *) output->base.compositor;

	/* check */
	if (output_base->gamma_size != size)
		return;
	if (!output->original_crtc)
		return;

	rc = drmModeCrtcSetGamma(compositor->drm.fd,
				 output->crtc_id,
				 size, r, g, b);
	if (rc)
		weston_log("set gamma failed: %m\n");
}

568
static void
569
drm_output_repaint(struct weston_output *output_base,
570
		   pixman_region32_t *damage)
571 572
{
	struct drm_output *output = (struct drm_output *) output_base;
573 574
	struct drm_compositor *compositor =
		(struct drm_compositor *) output->base.compositor;
575
	struct drm_sprite *s;
576
	struct drm_mode *mode;
577
	int ret = 0;
578

579
	if (!output->next)
580
		drm_output_render(output, damage);
581
	if (!output->next)
582
		return;
583

584
	mode = container_of(output->base.current, struct drm_mode, base);
585
	if (!output->current) {
586
		ret = drmModeSetCrtc(compositor->drm.fd, output->crtc_id,
587
				     output->next->fb_id, 0, 0,
588 589 590
				     &output->connector_id, 1,
				     &mode->mode_info);
		if (ret) {
591
			weston_log("set mode failed: %m\n");
592 593
			return;
		}
594
		output_base->set_dpms(output_base, WESTON_DPMS_ON);
595 596
	}

597
	if (drmModePageFlip(compositor->drm.fd, output->crtc_id,
598
			    output->next->fb_id,
599
			    DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
600
		weston_log("queueing pageflip failed: %m\n");
601
		return;
602
	}
603

604 605
	output->page_flip_pending = 1;

606 607
	drm_output_set_cursor(output);

608 609 610 611
	/*
	 * Now, update all the sprite surfaces
	 */
	wl_list_for_each(s, &compositor->sprite_list, link) {
612
		uint32_t flags = 0, fb_id = 0;
613 614 615 616 617
		drmVBlank vbl = {
			.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
			.request.sequence = 1,
		};

618
		if ((!s->current && !s->next) ||
619
		    !drm_sprite_crtc_supported(output_base, s->possible_crtcs))
620 621
			continue;

622 623 624
		if (s->next && !compositor->sprites_hidden)
			fb_id = s->next->fb_id;

625
		ret = drmModeSetPlane(compositor->drm.fd, s->plane_id,
626
				      output->crtc_id, fb_id, flags,
627 628 629 630 631
				      s->dest_x, s->dest_y,
				      s->dest_w, s->dest_h,
				      s->src_x, s->src_y,
				      s->src_w, s->src_h);
		if (ret)
632
			weston_log("setplane failed: %d: %s\n",
633 634
				ret, strerror(errno));

635 636 637
		if (output->pipe > 0)
			vbl.request.type |= DRM_VBLANK_SECONDARY;

638 639 640 641 642 643 644
		/*
		 * Queue a vblank signal so we know when the surface
		 * becomes active on the display or has been replaced.
		 */
		vbl.request.signal = (unsigned long)s;
		ret = drmWaitVBlank(compositor->drm.fd, &vbl);
		if (ret) {
645
			weston_log("vblank event request failed: %d: %s\n",
646 647
				ret, strerror(errno));
		}
648 649 650

		s->output = output;
		output->vblank_pending = 1;
651 652
	}

653
	return;
654 655
}

656 657 658 659 660 661 662 663
static void
drm_output_start_repaint_loop(struct weston_output *output_base)
{
	struct drm_output *output = (struct drm_output *) output_base;
	struct drm_compositor *compositor = (struct drm_compositor *)
		output_base->compositor;
	uint32_t fb_id;

664 665 666 667 668 669 670 671 672 673 674 675 676
	struct timespec ts;

	if (!output->current) {
		/* We can't page flip if there's no mode set */
		uint32_t msec;

		clock_gettime(compositor->clock, &ts);
		msec = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
		weston_output_finish_frame(output_base, msec);
		return;
	}

	fb_id = output->current->fb_id;
677 678 679 680 681 682 683 684

	if (drmModePageFlip(compositor->drm.fd, output->crtc_id, fb_id,
			    DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
		weston_log("queueing pageflip failed: %m\n");
		return;
	}
}

685 686 687 688 689
static void
vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
	       void *data)
{
	struct drm_sprite *s = (struct drm_sprite *)data;
690 691 692 693
	struct drm_output *output = s->output;
	uint32_t msecs;

	output->vblank_pending = 0;
694

695
	drm_output_release_fb(output, s->current);
696 697
	s->current = s->next;
	s->next = NULL;
698 699 700 701 702

	if (!output->page_flip_pending) {
		msecs = sec * 1000 + usec / 1000;
		weston_output_finish_frame(&output->base, msecs);
	}
703 704
}

705 706 707 708
static void
page_flip_handler(int fd, unsigned int frame,
		  unsigned int sec, unsigned int usec, void *data)
{
709
	struct drm_output *output = (struct drm_output *) data;
710 711
	uint32_t msecs;

712 713 714 715 716 717 718 719
	/* We don't set page_flip_pending on start_repaint_loop, in that case
	 * we just want to page flip to the current buffer to get an accurate
	 * timestamp */
	if (output->page_flip_pending) {
		drm_output_release_fb(output, output->current);
		output->current = output->next;
		output->next = NULL;
	}
720

721
	output->page_flip_pending = 0;
722

723 724 725
	if (!output->vblank_pending) {
		msecs = sec * 1000 + usec / 1000;
		weston_output_finish_frame(&output->base, msecs);
726 727 728 729 730

		/* We can't call this from frame_notify, because the output's
		 * repaint needed flag is cleared just after that */
		if (output->recorder)
			weston_output_schedule_repaint(&output->base);
731
	}
732 733
}

734 735 736
static uint32_t
drm_output_check_sprite_format(struct drm_sprite *s,
			       struct weston_surface *es, struct gbm_bo *bo)
737
{
738 739 740 741 742 743 744
	uint32_t i, format;

	format = gbm_bo_get_format(bo);

	if (format == GBM_FORMAT_ARGB8888) {
		pixman_region32_t r;

745 746 747 748
		pixman_region32_init_rect(&r, 0, 0,
					  es->geometry.width,
					  es->geometry.height);
		pixman_region32_subtract(&r, &r, &es->opaque);
749 750 751 752 753 754

		if (!pixman_region32_not_empty(&r))
			format = GBM_FORMAT_XRGB8888;

		pixman_region32_fini(&r);
	}
755 756 757

	for (i = 0; i < s->count_formats; i++)
		if (s->formats[i] == format)
758
			return format;
759 760 761 762 763 764 765

	return 0;
}

static int
drm_surface_transform_supported(struct weston_surface *es)
{
766 767
	return !es->transform.enabled ||
		(es->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
768 769
}

770
static struct weston_plane *
771
drm_output_prepare_overlay_surface(struct weston_output *output_base,
772
				   struct weston_surface *es)
773 774 775 776 777 778 779
{
	struct weston_compositor *ec = output_base->compositor;
	struct drm_compositor *c =(struct drm_compositor *) ec;
	struct drm_sprite *s;
	int found = 0;
	struct gbm_bo *bo;
	pixman_region32_t dest_rect, src_rect;
780
	pixman_box32_t *box, tbox;
781
	uint32_t format;
782
	wl_fixed_t sx1, sy1, sx2, sy2;
783

784 785 786
	if (c->gbm == NULL)
		return NULL;

787
	if (es->buffer_transform != output_base->transform)
788 789
		return NULL;

790 791 792
	if (es->buffer_scale != output_base->scale)
		return NULL;

793
	if (c->sprites_are_broken)
794
		return NULL;
795

796
	if (es->output_mask != (1u << output_base->id))
797
		return NULL;
798

799
	if (es->buffer_ref.buffer == NULL)
800
		return NULL;
801

802 803 804
	if (es->alpha != 1.0f)
		return NULL;

805
	if (wl_shm_buffer_get(es->buffer_ref.buffer->resource))
806 807
		return NULL;

808
	if (!drm_surface_transform_supported(es))
809
		return NULL;
810 811 812 813 814

	wl_list_for_each(s, &c->sprite_list, link) {
		if (!drm_sprite_crtc_supported(output_base, s->possible_crtcs))
			continue;

815
		if (!s->next) {
816 817 818 819 820 821 822
			found = 1;
			break;
		}
	}

	/* No sprites available */
	if (!found)
823
		return NULL;
824

825
	bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER,
826 827
			   es->buffer_ref.buffer->resource,
			   GBM_BO_USE_SCANOUT);
828
	if (!bo)
829
		return NULL;
830

831 832
	format = drm_output_check_sprite_format(s, es, bo);
	if (format == 0) {
833
		gbm_bo_destroy(bo);
834
		return NULL;
835
	}
836

837
	s->next = drm_fb_get_from_bo(bo, c, format);
838 839
	if (!s->next) {
		gbm_bo_destroy(bo);
840
		return NULL;
841 842
	}

843
	drm_fb_set_buffer(s->next, es->buffer_ref.buffer);
844

845 846 847 848
	box = pixman_region32_extents(&es->transform.boundingbox);
	s->plane.x = box->x1;
	s->plane.y = box->y1;

849 850
	/*
	 * Calculate the source & dest rects properly based on actual
Martin Olsson's avatar
Martin Olsson committed
851
	 * position (note the caller has called weston_surface_update_transform()
852 853 854 855 856 857 858
	 * for us already).
	 */
	pixman_region32_init(&dest_rect);
	pixman_region32_intersect(&dest_rect, &es->transform.boundingbox,
				  &output_base->region);
	pixman_region32_translate(&dest_rect, -output_base->x, -output_base->y);
	box = pixman_region32_extents(&dest_rect);
859 860
	tbox = weston_transformed_rect(output_base->width,
				       output_base->height,
861
				       output_base->transform,
862 863
				       output_base->scale,
				       *box);
864 865 866 867
	s->dest_x = tbox.x1;
	s->dest_y = tbox.y1;
	s->dest_w = tbox.x2 - tbox.x1;
	s->dest_h = tbox.y2 - tbox.y1;
868 869 870 871 872 873
	pixman_region32_fini(&dest_rect);

	pixman_region32_init(&src_rect);
	pixman_region32_intersect(&src_rect, &es->transform.boundingbox,
				  &output_base->region);
	box = pixman_region32_extents(&src_rect);
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892

	weston_surface_from_global_fixed(es,
					 wl_fixed_from_int(box->x1),
					 wl_fixed_from_int(box->y1),
					 &sx1, &sy1);
	weston_surface_from_global_fixed(es,
					 wl_fixed_from_int(box->x2),
					 wl_fixed_from_int(box->y2),
					 &sx2, &sy2);

	if (sx1 < 0)
		sx1 = 0;
	if (sy1 < 0)
		sy1 = 0;
	if (sx2 > wl_fixed_from_int(es->geometry.width))
		sx2 = wl_fixed_from_int(es->geometry.width);
	if (sy2 > wl_fixed_from_int(es->geometry.height))
		sy2 = wl_fixed_from_int(es->geometry.height);

893 894 895 896 897 898 899
	tbox.x1 = sx1;
	tbox.y1 = sy1;
	tbox.x2 = sx2;
	tbox.y2 = sy2;

	tbox = weston_transformed_rect(wl_fixed_from_int(es->geometry.width),
				       wl_fixed_from_int(es->geometry.height),
900
				       es->buffer_transform, es->buffer_scale, tbox);
901 902 903 904 905

	s->src_x = tbox.x1 << 8;
	s->src_y = tbox.y1 << 8;
	s->src_w = (tbox.x2 - tbox.x1) << 8;
	s->src_h = (tbox.y2 - tbox.y1) << 8;
906 907
	pixman_region32_fini(&src_rect);

908
	return &s->plane;
909 910
}

911
static struct weston_plane *
912 913
drm_output_prepare_cursor_surface(struct weston_output *output_base,
				  struct weston_surface *es)
914
{
915 916
	struct drm_compositor *c =
		(struct drm_compositor *) output_base->compositor;
917
	struct drm_output *output = (struct drm_output *) output_base;
918

919 920
	if (c->gbm == NULL)
		return NULL;
921 922
	if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
		return NULL;
923 924 925 926
	if (output->cursor_surface)
		return NULL;
	if (es->output_mask != (1u << output_base->id))
		return NULL;
927
	if (c->cursors_are_broken)
928
		return NULL;
929
	if (es->buffer_ref.buffer == NULL ||
930
	    !wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
931 932 933 934 935 936 937 938 939 940 941 942
	    es->geometry.width > 64 || es->geometry.height > 64)
		return NULL;

	output->cursor_surface = es;

	return &output->cursor_plane;
}

static void
drm_output_set_cursor(struct drm_output *output)
{
	struct weston_surface *es = output->cursor_surface;
943 944 945 946 947 948
	struct drm_compositor *c =
		(struct drm_compositor *) output->base.compositor;
	EGLint handle, stride;
	struct gbm_bo *bo;
	uint32_t buf[64 * 64];
	unsigned char *s;
949
	int i, x, y;
950

951
	output->cursor_surface = NULL;
952 953 954 955
	if (es == NULL) {
		drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
		return;
	}
956

957 958
	if (es->buffer_ref.buffer &&
	    pixman_region32_not_empty(&output->cursor_plane.damage)) {
959 960
		pixman_region32_fini(&output->cursor_plane.damage);
		pixman_region32_init(&output->cursor_plane.damage);
961 962 963
		output->current_cursor ^= 1;
		bo = output->cursor_bo[output->current_cursor];
		memset(buf, 0, sizeof buf);
964 965
		stride = wl_shm_buffer_get_stride(es->buffer_ref.buffer->shm_buffer);
		s = wl_shm_buffer_get_data(es->buffer_ref.buffer->shm_buffer);
966 967 968 969 970
		for (i = 0; i < es->geometry.height; i++)
			memcpy(buf + i * 64, s + i * stride,
			       es->geometry.width * 4);

		if (gbm_bo_write(bo, buf, sizeof buf) < 0)
971
			weston_log("failed update cursor: %m\n");
972

973 974
		handle = gbm_bo_get_handle(bo).s32;
		if (drmModeSetCursor(c->drm.fd,
975
				     output->crtc_id, handle, 64, 64)) {
976
			weston_log("failed to set cursor: %m\n");
977 978
			c->cursors_are_broken = 1;
		}
979
	}
980

981 982
	x = (es->geometry.x - output->base.x) * output->base.scale;
	y = (es->geometry.y - output->base.y) * output->base.scale;
983
	if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
984
		if (drmModeMoveCursor(c->drm.fd, output->crtc_id, x, y)) {
985
			weston_log("failed to move cursor: %m\n");
986 987 988
			c->cursors_are_broken = 1;
		}

989 990
		output->cursor_plane.x = x;
		output->cursor_plane.y = y;
991
	}
992 993
}

994 995 996
static void
drm_assign_planes(struct weston_output *output)
{
997 998
	struct drm_compositor *c =
		(struct drm_compositor *) output->compositor;
999
	struct weston_surface *es, *next;
1000
	pixman_region32_t overlap, surface_overlap;
1001
	struct weston_plane *primary, *next_plane;
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016

	/*
	 * Find a surface for each sprite in the output using some heuristics:
	 * 1) size
	 * 2) frequency of update
	 * 3) opacity (though some hw might support alpha blending)
	 * 4) clipping (this can be fixed with color keys)
	 *
	 * The idea is to save on blitting since this should save power.
	 * If we can get a large video surface on the sprite for example,
	 * the main display surface may not need to update at all, and
	 * the client buffer can be used directly for the sprite surface
	 * as we do for flipping full screen surfaces.
	 */
	pixman_region32_init(&overlap);
1017
	primary = &c->base.primary_plane;
1018
	wl_list_for_each_safe(es, next, &c->base.surface_list, link) {
1019 1020 1021 1022
		/* test whether this buffer can ever go into a plane:
		 * non-shm, or small enough to be a cursor
		 */
		if ((es->buffer_ref.buffer &&
1023
		     !wl_shm_buffer_get(es->buffer_ref.buffer->resource)) ||
1024 1025 1026 1027 1028
		    (es->geometry.width <= 64 && es->geometry.height <= 64))
			es->keep_buffer = 1;
		else
			es->keep_buffer = 0;

1029 1030 1031 1032
		pixman_region32_init(&surface_overlap);
		pixman_region32_intersect(&surface_overlap, &overlap,
					  &es->transform.boundingbox);

1033
		next_plane = NULL;
1034
		if (pixman_region32_not_empty(&surface_overlap))
1035 1036
			next_plane = primary;
		if (next_plane == NULL)
1037
			next_plane = drm_output_prepare_cursor_surface(output, es);
1038 1039 1040 1041 1042 1043 1044 1045
		if (next_plane == NULL)
			next_plane = drm_output_prepare_scanout_surface(output, es);
		if (next_plane == NULL)
			next_plane = drm_output_prepare_overlay_surface(output, es);
		if (next_plane == NULL)
			next_plane = primary;
		weston_surface_move_to_plane(es, next_plane);
		if (next_plane == primary)
1046 1047
			pixman_region32_union(&overlap, &overlap,
					      &es->transform.boundingbox);
1048

1049 1050 1051 1052 1053
		pixman_region32_fini(&surface_overlap);
	}
	pixman_region32_fini(&overlap);
}

1054 1055 1056
static void
drm_output_fini_pixman(struct drm_output *output);

1057
static void
1058
drm_output_destroy(struct weston_output *output_base)
1059 1060 1061
{
	struct drm_output *output = (struct drm_output *) output_base;
	struct drm_compositor *c =
1062
		(struct drm_compositor *) output->base.compositor;
1063 1064
	drmModeCrtcPtr origcrtc = output->original_crtc;

1065 1066 1067
	if (output->backlight)
		backlight_destroy(output->backlight);

1068 1069
	drmModeFreeProperty(output->dpms_prop);

1070
	/* Turn off hardware cursor */
1071
	drmModeSetCursor(c->drm.fd, output->crtc_id, 0, 0, 0);
1072 1073 1074

	/* Restore original CRTC state */
	drmModeSetCrtc(c->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
1075 1076
		       origcrtc->x, origcrtc->y,
		       &output->connector_id, 1, &origcrtc->mode);
1077 1078
	drmModeFreeCrtc(origcrtc);

1079 1080 1081
	c->crtc_allocator &= ~(1 << output->crtc_id);
	c->connector_allocator &= ~(1 << output->connector_id);

1082 1083 1084 1085 1086 1087
	if (c->use_pixman) {
		drm_output_fini_pixman(output);
	} else {
		gl_renderer_output_destroy(output_base);
		gbm_surface_destroy(output->surface);
	}
1088

1089 1090 1091
	weston_plane_release(&output->fb_plane);
	weston_plane_release(&output->cursor_plane);

1092
	weston_output_destroy(&output->base);
1093 1094
	wl_list_remove(&output->base.link);

1095 1096 1097
	free(output);
}

1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
static struct drm_mode *
choose_mode (struct drm_output *output, struct weston_mode *target_mode)
{
	struct drm_mode *tmp_mode = NULL, *mode;

	if (output->base.current->width == target_mode->width && 
	    output->base.current->height == target_mode->height &&
	    (output->base.current->refresh == target_mode->refresh ||
	     target_mode->refresh == 0))
		return (struct drm_mode *)output->base.current;

	wl_list_for_each(mode, &output->base.mode_list, base.link) {
		if (mode->mode_info.hdisplay == target_mode->width &&
		    mode->mode_info.vdisplay == target_mode->height) {
			if (mode->mode_info.vrefresh == target_mode->refresh || 
          		    target_mode->refresh == 0) {
				return mode;
			} else if (!tmp_mode) 
				tmp_mode = mode;
		}
	}

	return tmp_mode;
}

1123 1124
static int
drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
1125 1126
static int
drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
1127

1128 1129 1130 1131 1132 1133 1134 1135
static int
drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
{
	struct drm_output *output;
	struct drm_mode *drm_mode;
	struct drm_compositor *ec;

	if (output_base == NULL) {
1136
		weston_log("output is NULL.\n");
1137 1138 1139 1140
		return -1;
	}

	if (mode == NULL) {
1141
		weston_log("mode is NULL.\n");
1142 1143 1144 1145 1146 1147 1148 1149
		return -1;
	}

	ec = (struct drm_compositor *)output_base->compositor;
	output = (struct drm_output *)output_base;
	drm_mode  = choose_mode (output, mode);

	if (!drm_mode) {
1150
		weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
1151 1152 1153
		return -1;
	}

1154 1155
	if (&drm_mode->base == output->base.current)
		return 0;
1156

1157
	output->base.current->flags = 0;
1158

1159 1160 1161
	output->base.current = &drm_mode->base;
	output->base.current->flags =
		WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
1162 1163

	/* reset rendering stuff. */
1164 1165 1166
	drm_output_release_fb(output, output->current);
	drm_output_release_fb(output, output->next);
	output->current = output->next = NULL;
1167

1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
	if (ec->use_pixman) {
		drm_output_fini_pixman(output);
		if (drm_output_init_pixman(output, ec) < 0) {
			weston_log("failed to init output pixman state with "
				   "new mode\n");
			return -1;
		}
	} else {
		gl_renderer_output_destroy(&output->base);
		gbm_surface_destroy(output->surface);
1178

1179 1180 1181 1182 1183
		if (drm_output_init_egl(output, ec) < 0) {
			weston_log("failed to init output egl state with "
				   "new mode");
			return -1;
		}
1184
	}
1185

1186
	return 0;
1187 1188
}

1189
static int
1190 1191 1192 1193 1194 1195 1196
on_drm_input(int fd, uint32_t mask, void *data)
{
	drmEventContext evctx;

	memset(&evctx, 0, sizeof evctx);
	evctx.version = DRM_EVENT_CONTEXT_VERSION;
	evctx.page_flip_handler = page_flip_handler;
1197
	evctx.vblank_handler = vblank_handler;
1198
	drmHandleEvent(fd, &evctx);
1199 1200

	return 1;
1201 1202 1203
}

static int
1204
init_drm(struct drm_compositor *ec, struct udev_device *device)
1205
{
1206
	const char *filename, *sysnum;
1207 1208
	uint64_t cap;
	int fd, ret;
1209

1210 1211 1212 1213
	sysnum = udev_device_get_sysnum(device);
	if (sysnum)
		ec->drm.id = atoi(sysnum);
	if (!sysnum || ec->drm.id < 0) {
1214
		weston_log("cannot get device sysnum\n");
1215 1216 1217
		return -1;
	}

1218
	filename = udev_device_get_devnode(device);
1219
	fd = weston_launcher_open(ec->base.launcher, filename, O_RDWR);
1220
	if (fd < 0) {
1221
		/* Probably permissions error */
1222
		weston_log("couldn't open %s, skipping\n",
1223 1224 1225 1226
			udev_device_get_devnode(device));
		return -1;
	}

1227 1228
	weston_log("using %s\n", filename);

1229
	ec->drm.fd = fd;
1230
	ec->drm.filename = strdup(filename);
1231

1232 1233 1234 1235 1236
	ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
	if (ret == 0 && cap == 1)
		ec->clock = CLOCK_MONOTONIC;
	else
		ec->clock = CLOCK_REALTIME;
1237

1238 1239 1240 1241 1242 1243
	return 0;
}

static int
init_egl(struct drm_compositor *ec)
{
1244
	ec->gbm = gbm_create_device(ec->drm.fd);
1245

1246 1247 1248
	if (!ec->gbm)
		return -1;

1249
	if (gl_renderer_create(&ec->base, ec->gbm, gl_renderer_opaque_attribs,
1250 1251
			NULL) < 0) {
		gbm_device_destroy(ec->gbm);
1252 1253 1254
		return -1;
	}

1255 1256 1257
	return 0;
}

1258 1259 1260 1261 1262 1263
static int
init_pixman(struct drm_compositor *ec)
{
	return pixman_renderer_init(&ec->base);
}

1264
static struct drm_mode *
1265
drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
1266 1267
{
	struct drm_mode *mode;
1268
	uint64_t refresh;
1269 1270 1271

	mode = malloc(sizeof *mode);
	if (mode == NULL)
1272
		return NULL;
1273 1274

	mode->base.flags = 0;
1275 1276
	mode->base.width = info->hdisplay;
	mode->base.height = info->vdisplay;
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286