sna_display.c 247 KB
Newer Older
1
2
/*
 * Copyright © 2007 Red Hat, Inc.
3
 * Copyright © 2013-2014 Intel Corporation
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Authors:
 *    Dave Airlie <airlied@redhat.com>
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
36
#include <sys/mman.h>
37
38
39
40
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <poll.h>
41
#include <ctype.h>
42
#include <dirent.h>
43

44
45
#if HAVE_ALLOCA_H
#include <alloca.h>
Chris Wilson's avatar
Chris Wilson committed
46
47
48
49
50
51
52
53
54
#elif defined __GNUC__
#define alloca __builtin_alloca
#elif defined _AIX
#define alloca __alloca
#elif defined _MSC_VER
#include <malloc.h>
#define alloca _alloca
#else
void *alloca(size_t);
55
56
#endif

57
58
59
60
61
#define _PARSE_EDID_
/* Jump through a few hoops in order to fixup EDIDs */
#undef VERSION
#undef REVISION

62
63
64
#include "sna.h"
#include "sna_reg.h"
#include "fb/fbpict.h"
65
#include "intel_options.h"
66
#include "backlight.h"
67
68

#include <xf86Crtc.h>
69
#include <xf86RandR12.h>
70
#include <cursorstr.h>
71
72
73
74
75
76
77

#if XF86_CRTC_VERSION >= 3
#define HAS_GAMMA 1
#else
#define HAS_GAMMA 0
#endif

78
#include <X11/Xatom.h>
79
#if defined(HAVE_X11_EXTENSIONS_DPMSCONST_H)
80
#include <X11/extensions/dpmsconst.h>
81
82
83
84
#else
#define DPMSModeOn 0
#define DPMSModeOff 3
#endif
Chris Wilson's avatar
Chris Wilson committed
85
#include <xf86DDC.h> /* for xf86InterpretEDID */
86

87
88
#include <xf86drm.h>

89
90
91
92
93
#ifdef HAVE_VALGRIND
#include <valgrind.h>
#include <memcheck.h>
#endif

94
95
#define FAIL_CURSOR_IOCTL 0

96
97
#define COLDPLUG_DELAY_MS 2000

98
99
100
101
102
/* Minor discrepancy between 32-bit/64-bit ABI in old kernels */
union compat_mode_get_connector{
	struct drm_mode_get_connector conn;
	uint32_t pad[20];
};
103

104
105
#define KNOWN_MODE_FLAGS ((1<<14)-1)

106
107
108
109
#ifndef MONITOR_EDID_COMPLETE_RAWDATA
#define MONITOR_EDID_COMPLETE_RAWDATA 1
#endif

110
111
112
113
#ifndef DEFAULT_DPI
#define DEFAULT_DPI 96
#endif

114
115
#define OUTPUT_STATUS_CACHE_MS 15000

116
117
#define DRM_MODE_PAGE_FLIP_ASYNC 0x02

118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
#define DRM_PLANE_TYPE_OVERLAY 0
#define DRM_PLANE_TYPE_PRIMARY 1
#define DRM_PLANE_TYPE_CURSOR  2

#define LOCAL_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xb9, struct local_mode_obj_get_properties)
struct local_mode_obj_get_properties {
	uint64_t props_ptr;
	uint64_t prop_values_ptr;
	uint32_t count_props;
	uint32_t obj_id;
	uint32_t obj_type;
	uint32_t pad;
};
#define LOCAL_MODE_OBJECT_PLANE 0xeeeeeeee

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
struct local_mode_set_plane {
	uint32_t plane_id;
	uint32_t crtc_id;
	uint32_t fb_id; /* fb object contains surface format type */
	uint32_t flags;

	/* Signed dest location allows it to be partially off screen */
	int32_t crtc_x, crtc_y;
	uint32_t crtc_w, crtc_h;

	/* Source values are 16.16 fixed point */
	uint32_t src_x, src_y;
	uint32_t src_h, src_w;
};
#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)

struct local_mode_get_plane {
	uint32_t plane_id;

	uint32_t crtc_id;
	uint32_t fb_id;

	uint32_t possible_crtcs;
	uint32_t gamma_size;

	uint32_t count_format_types;
	uint64_t format_type_ptr;
};
#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane)

struct local_mode_get_plane_res {
	uint64_t plane_id_ptr;
	uint64_t count_planes;
};
#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res)

170
#if 1
171
172
173
174
175
#define __DBG DBG
#else
#define __DBG(x)
#endif

176
177
#define DBG_NATIVE_ROTATION ~0 /* minimum RR_Rotate_0 */

178
179
extern XF86ConfigPtr xf86configptr;

180
181
182
183
184
185
186
187
188
189
190
191
192
193
struct sna_cursor {
	struct sna_cursor *next;
	uint32_t *image;
	bool transformed;
	Rotation rotation;
	int ref;
	int size;
	int last_width;
	int last_height;
	unsigned handle;
	unsigned serial;
	unsigned alloc;
};

194
struct sna_crtc {
195
	struct sna_crtc_public public;
Chris Wilson's avatar
Chris Wilson committed
196
	uint32_t id;
197
	xf86CrtcPtr base;
198
	struct drm_mode_modeinfo kmode;
199
200
	PixmapPtr slave_pixmap;
	DamagePtr slave_damage;
201
	struct kgem_bo *bo, *shadow_bo, *client_bo, *cache_bo;
202
	struct sna_cursor *cursor;
Chris Wilson's avatar
Chris Wilson committed
203
	unsigned int last_cursor_size;
204
	uint32_t offset;
205
	bool shadow;
206
	bool fallback_shadow;
207
	bool transform;
208
	bool cursor_transform;
209
	bool hwcursor;
210
	bool flip_pending;
211

212
213
	struct pict_f_transform cursor_to_fb, fb_to_cursor;

214
	RegionRec crtc_damage;
215
216
	uint16_t shadow_bo_width, shadow_bo_height;

217
	uint32_t rotation;
218
219
220
221
222
223
224
	struct plane {
		uint32_t id;
		struct {
			uint32_t prop;
			uint32_t supported;
			uint32_t current;
		} rotation;
225
226
227
228
		struct {
			uint32_t prop;
			uint64_t values[2];
		} color_encoding;
229
230
231
		struct list link;
	} primary;
	struct list sprites;
232

233
234
	uint32_t mode_serial, flip_serial;

235
236
	uint32_t last_seq, wrap_seq;
	struct ust_msc swap;
237
238
239
240

	sna_flip_handler_t flip_handler;
	struct kgem_bo *flip_bo;
	void *flip_data;
241
242

	struct list shadow_link;
243
244
245
};

struct sna_property {
246
	drmModePropertyPtr kprop;
247
248
249
250
251
	int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */
	Atom *atoms;
};

struct sna_output {
252
	xf86OutputPtr base;
253
254
	unsigned id;
	unsigned serial;
255

256
257
258
	unsigned possible_encoders;
	unsigned attached_encoders;

259
	unsigned int is_panel : 1;
260
	unsigned int add_default_modes : 1;
261
262
	int connector_type;
	int connector_type_id;
263

264
265
	uint32_t link_status_idx;

266
267
268
269
	uint32_t edid_idx;
	uint32_t edid_blob_id;
	uint32_t edid_len;
	void *edid_raw;
270
	void *fake_edid_raw;
271

272
	bool has_panel_limits;
273
274
275
	int panel_hdisplay;
	int panel_vdisplay;

276
	uint32_t dpms_id;
277
	uint8_t dpms_mode;
278
	struct backlight backlight;
279
	int backlight_active_level;
280

281
282
	uint32_t last_detect;
	uint32_t status;
283
	unsigned int hotplug_count;
284
	bool update_properties;
285
	bool reprobe;
286

287
288
289
290
291
292
293
	int num_modes;
	struct drm_mode_modeinfo *modes;

	int num_props;
	uint32_t *prop_ids;
	uint64_t *prop_values;
	struct sna_property *props;
294
295
};

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
enum { /* XXX copied from hw/xfree86/modes/xf86Crtc.c */
	OPTION_PREFERRED_MODE,
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,1,0)
	OPTION_ZOOM_MODES,
#endif
	OPTION_POSITION,
	OPTION_BELOW,
	OPTION_RIGHT_OF,
	OPTION_ABOVE,
	OPTION_LEFT_OF,
	OPTION_ENABLE,
	OPTION_DISABLE,
	OPTION_MIN_CLOCK,
	OPTION_MAX_CLOCK,
	OPTION_IGNORE,
	OPTION_ROTATE,
	OPTION_PANNING,
	OPTION_PRIMARY,
	OPTION_DEFAULT_MODES,
};

317
static void __sna_output_dpms(xf86OutputPtr output, int dpms, int fixup);
Chris Wilson's avatar
Chris Wilson committed
318
static void sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc);
319
320
static bool sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc,
			  struct kgem_bo *bo, int x, int y);
Chris Wilson's avatar
Chris Wilson committed
321

322
323
324
325
326
static bool is_zaphod(ScrnInfoPtr scrn)
{
	return xf86IsEntityShared(scrn->entityList[0]);
}

327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
static bool
sna_zaphod_match(struct sna *sna, const char *output)
{
	const char *s, *colon;
	char t[20];
	unsigned int i = 0;

	s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
	if (s == NULL)
		return false;

	colon = strchr(s, ':');
	if (colon) /* Skip over the ZaphodPipes */
		s = colon + 1;

	do {
		/* match any outputs in a comma list, stopping at whitespace */
		switch (*s) {
		case '\0':
			t[i] = '\0';
			return strcmp(t, output) == 0;

		case ',':
			t[i] ='\0';
			if (strcmp(t, output) == 0)
				return TRUE;
			i = 0;
			break;

		case ' ':
		case '\t':
		case '\n':
		case '\r':
			break;

		default:
			t[i++] = *s;
			break;
		}

		s++;
	} while (i < sizeof(t));

	return false;
}

static unsigned
get_zaphod_crtcs(struct sna *sna)
{
	const char *str, *colon;
	unsigned crtcs = 0;

	str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
	if (str == NULL || (colon = strchr(str, ':')) == NULL) {
		DBG(("%s: no zaphod pipes, using screen number: %x\n",
		     __FUNCTION__,
		     sna->scrn->confScreen->device->screen));
		return 1 << sna->scrn->confScreen->device->screen;
	}

	DBG(("%s: ZaphodHeads='%s'\n", __FUNCTION__, str));
	while (str < colon) {
		char *end;
		unsigned crtc = strtoul(str, &end, 0);
		if (end == str)
			break;
		DBG(("%s: adding CRTC %d to zaphod pipes\n",
		     __FUNCTION__, crtc));
		crtcs |= 1 << crtc;
		str = end + 1;
	}
	DBG(("%s: ZaphodPipes=%x\n", __FUNCTION__, crtcs));
	return crtcs;
}

402
403
404
405
406
inline static unsigned count_to_mask(int x)
{
	return (1 << x) - 1;
}

407
408
409
410
411
412
413
static inline struct sna_output *to_sna_output(xf86OutputPtr output)
{
	return output->driver_private;
}

static inline int to_connector_id(xf86OutputPtr output)
{
414
415
	assert(to_sna_output(output));
	assert(to_sna_output(output)->id);
416
	return to_sna_output(output)->id;
417
418
}

419
420
421
422
static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc)
{
	return crtc->driver_private;
}
423

424
425
static inline unsigned __sna_crtc_pipe(struct sna_crtc *crtc)
{
426
	return crtc->public.flags >> 8 & 0xff;
427
428
429
430
}

static inline unsigned __sna_crtc_id(struct sna_crtc *crtc)
{
Chris Wilson's avatar
Chris Wilson committed
431
432
433
434
435
436
	return crtc->id;
}

uint32_t sna_crtc_id(xf86CrtcPtr crtc)
{
	return __sna_crtc_id(to_sna_crtc(crtc));
437
438
}

439
static inline bool event_pending(int fd)
440
441
{
	struct pollfd pfd;
442
	pfd.fd = fd;
443
444
445
446
	pfd.events = POLLIN;
	return poll(&pfd, 1, 0) == 1;
}

447
448
449
450
451
452
453
454
static bool sna_mode_wait_for_event(struct sna *sna)
{
	struct pollfd pfd;
	pfd.fd = sna->kgem.fd;
	pfd.events = POLLIN;
	return poll(&pfd, 1, -1) == 1;
}

455
static inline uint32_t fb_id(struct kgem_bo *bo)
456
{
457
	return bo->delta;
458
459
}

460
461
462
463
464
465
466
467
468
469
470
471
unsigned sna_crtc_count_sprites(xf86CrtcPtr crtc)
{
	struct plane *sprite;
	unsigned count;

	count = 0;
	list_for_each_entry(sprite, &to_sna_crtc(crtc)->sprites, link)
		count++;

	return count;
}

472
static struct plane *lookup_sprite(struct sna_crtc *crtc, unsigned idx)
473
{
474
475
476
477
478
479
480
481
482
483
484
485
486
	struct plane *sprite;

	list_for_each_entry(sprite, &crtc->sprites, link)
		if (idx-- == 0)
			return sprite;

	return NULL;
}

uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc, unsigned idx)
{
	struct plane *sprite;

487
	assert(to_sna_crtc(crtc));
488
489
490

	sprite = lookup_sprite(to_sna_crtc(crtc), idx);
	return sprite ? sprite->id : 0;
491
492
}

493
494
495
496
497
498
bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
{
	assert(to_sna_crtc(crtc));
	return to_sna_crtc(crtc)->transform;
}

499
static inline bool msc64(struct sna_crtc *sna_crtc, uint32_t seq, uint64_t *msc)
500
{
501
	bool record = true;
502
503
504
505
	if (seq < sna_crtc->last_seq) {
		if (sna_crtc->last_seq - seq > 0x40000000) {
			sna_crtc->wrap_seq++;
			DBG(("%s: pipe=%d wrapped; was %u, now %u, wraps=%u\n",
506
			     __FUNCTION__, __sna_crtc_pipe(sna_crtc),
507
			     sna_crtc->last_seq, seq, sna_crtc->wrap_seq));
508
509
		} else {
			DBG(("%s: pipe=%d msc went backwards; was %u, now %u; ignoring for last_swap\n",
510
			     __FUNCTION__, __sna_crtc_pipe(sna_crtc), sna_crtc->last_seq, seq));
511
512

			record = false;
513
		}
514
	}
515
516
	*msc = (uint64_t)sna_crtc->wrap_seq << 32 | seq;
	return record;
517
518
519
520
521
522
}

uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc,
			      int tv_sec, int tv_usec, unsigned seq)
{
	struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
523
524
	uint64_t msc;

525
	assert(sna_crtc);
526
527

	if (msc64(sna_crtc, seq, &msc)) {
528
		DBG(("%s: recording last swap on pipe=%d, frame %d [msc=%08lld], time %d.%06d\n",
529
		     __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
530
531
532
533
534
		     tv_sec, tv_usec));
		sna_crtc->swap.tv_sec = tv_sec;
		sna_crtc->swap.tv_usec = tv_usec;
		sna_crtc->swap.msc = msc;
	} else {
535
		DBG(("%s: swap event on pipe=%d, frame %d [msc=%08lld], time %d.%06d\n",
536
		     __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
537
538
539
540
		     tv_sec, tv_usec));
	}

	return msc;
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
}

const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
{
	static struct ust_msc zero;

	if (crtc == NULL) {
		return &zero;
	} else {
		struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
		assert(sna_crtc);
		return &sna_crtc->swap;
	}
}

556
557
558
559
560
561
562
563
564
565
#ifndef NDEBUG
static void gem_close(int fd, uint32_t handle);
static void assert_scanout(struct kgem *kgem, struct kgem_bo *bo,
			   int width, int height)
{
	struct drm_mode_fb_cmd info;

	assert(bo->scanout);

	VG_CLEAR(info);
566
	info.fb_id = fb_id(bo);
567
568
569
570

	assert(drmIoctl(kgem->fd, DRM_IOCTL_MODE_GETFB, &info) == 0);
	gem_close(kgem->fd, info.handle);

Chris Wilson's avatar
Chris Wilson committed
571
	assert(width <= info.width && height <= info.height);
572
}
573
574
#else
#define assert_scanout(k, b, w, h)
575
576
#endif

577
578
579
580
581
582
583
584
585
static void assert_crtc_fb(struct sna *sna, struct sna_crtc *crtc)
{
#ifndef NDEBUG
	struct drm_mode_crtc mode = { .crtc_id = __sna_crtc_id(crtc) };
	drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
	assert(mode.fb_id == fb_id(crtc->bo));
#endif
}

Chris Wilson's avatar
Chris Wilson committed
586
587
588
589
static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
		       int width, int height)
{
	ScrnInfoPtr scrn = sna->scrn;
Chris Wilson's avatar
Chris Wilson committed
590
	struct drm_mode_fb_cmd arg;
Chris Wilson's avatar
Chris Wilson committed
591

592
593
594
	if (!kgem_bo_is_fenced(&sna->kgem, bo))
		return 0;

595
	assert(bo->refcnt);
Chris Wilson's avatar
Chris Wilson committed
596
	assert(bo->proxy == NULL);
597
	assert(!bo->snoop);
598
	assert(8*bo->pitch >= width * scrn->bitsPerPixel);
599
	assert(height * bo->pitch <= kgem_bo_size(bo)); /* XXX crtc offset */
600
	if (fb_id(bo)) {
Chris Wilson's avatar
Chris Wilson committed
601
		DBG(("%s: reusing fb=%d for handle=%d\n",
602
		     __FUNCTION__, fb_id(bo), bo->handle));
603
		assert_scanout(&sna->kgem, bo, width, height);
604
		return fb_id(bo);
Chris Wilson's avatar
Chris Wilson committed
605
606
607
608
609
	}

	DBG(("%s: create fb %dx%d@%d/%d\n",
	     __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel));

610
	assert(bo->tiling != I915_TILING_Y || sna->kgem.can_scanout_y);
611
	assert((bo->pitch & 63) == 0);
612
	assert(scrn->vtSema); /* must be master */
Chris Wilson's avatar
Chris Wilson committed
613
614
615
616
617
618
619
620
621

	VG_CLEAR(arg);
	arg.width = width;
	arg.height = height;
	arg.pitch = bo->pitch;
	arg.bpp = scrn->bitsPerPixel;
	arg.depth = scrn->depth;
	arg.handle = bo->handle;

622
	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_ADDFB, &arg)) {
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
		/* Try again with the fancy version */
		struct local_mode_fb_cmd2 {
			uint32_t fb_id;
			uint32_t width, height;
			uint32_t pixel_format;
			uint32_t flags;

			uint32_t handles[4];
			uint32_t pitches[4]; /* pitch for each plane */
			uint32_t offsets[4]; /* offset of each plane */
			uint64_t modifiers[4];
		} f;
#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2)
		memset(&f, 0, sizeof(f));
		f.width = width;
		f.height = height;
		/* XXX interlaced */
		f.flags = 1 << 1; /* +modifiers */
		f.handles[0] = bo->handle;
		f.pitches[0] = bo->pitch;

		switch (bo->tiling) {
		case I915_TILING_NONE:
			break;
		case I915_TILING_X:
			/* I915_FORMAT_MOD_X_TILED */
			f.modifiers[0] = (uint64_t)1 << 56 | 1;
			break;
		case I915_TILING_Y:
			/* I915_FORMAT_MOD_X_TILED */
			f.modifiers[0] = (uint64_t)1 << 56 | 2;
			break;
		}

#define fourcc(a,b,c,d) ((a) | (b) << 8 | (c) << 16 | (d) << 24)
		switch (scrn->depth) {
		default:
			ERR(("%s: unhandled screen format, depth=%d\n",
			     __FUNCTION__, scrn->depth));
			goto fail;
		case 8:
			f.pixel_format = fourcc('C', '8', ' ', ' ');
			break;
		case 15:
			f.pixel_format = fourcc('X', 'R', '1', '5');
			break;
		case 16:
			f.pixel_format = fourcc('R', 'G', '1', '6');
			break;
		case 24:
			f.pixel_format = fourcc('X', 'R', '2', '4');
			break;
		case 30:
			f.pixel_format = fourcc('X', 'R', '3', '0');
			break;
		}
#undef fourcc

		if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_ADDFB2, &f)) {
fail:
			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
				   "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
				   __FUNCTION__, width, height,
				   scrn->depth, scrn->bitsPerPixel, bo->pitch, errno);
			return 0;
		}

		arg.fb_id = f.fb_id;
Chris Wilson's avatar
Chris Wilson committed
691
	}
692
	assert(arg.fb_id != 0);
693
	bo->delta = arg.fb_id;
694
	DBG(("%s: attached fb=%d to handle=%d\n",
695
	     __FUNCTION__, bo->delta, arg.handle));
696

Chris Wilson's avatar
Chris Wilson committed
697
	bo->scanout = true;
698
	return bo->delta;
Chris Wilson's avatar
Chris Wilson committed
699
700
}

701
702
703
704
static uint32_t gem_create(int fd, int size)
{
	struct drm_i915_gem_create create;

705
706
	assert((size & 4095) == 0);

707
	VG_CLEAR(create);
708
	create.handle = 0;
709
	create.size = size;
710
711
712
713
714
	(void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);

	return create.handle;
}

715
716
717
static void *gem_mmap(int fd, int handle, int size)
{
	struct drm_i915_gem_mmap_gtt mmap_arg;
718
	struct drm_i915_gem_set_domain set_domain;
719
720
721
722
723
724
725
726
727
728
729
	void *ptr;

	VG_CLEAR(mmap_arg);
	mmap_arg.handle = handle;
	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
		return NULL;

	ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mmap_arg.offset);
	if (ptr == MAP_FAILED)
		return NULL;

730
731
732
733
734
735
736
737
738
	VG_CLEAR(set_domain);
	set_domain.handle = handle;
	set_domain.read_domains = I915_GEM_DOMAIN_GTT;
	set_domain.write_domain = I915_GEM_DOMAIN_GTT;
	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
		munmap(ptr, size);
		return NULL;
	}

739
740
741
	return ptr;
}

742
743
744
745
static void gem_close(int fd, uint32_t handle)
{
	struct drm_gem_close close;

746
	VG_CLEAR(close);
747
748
749
750
	close.handle = handle;
	(void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
}

751
752
753
#define BACKLIGHT_NAME             "Backlight"
#define BACKLIGHT_DEPRECATED_NAME  "BACKLIGHT"
static Atom backlight_atom, backlight_deprecated_atom;
754

755
756
757
758
759
760
761
762
763
764
765
#if HAVE_UDEV
static void
sna_backlight_uevent(int fd, void *closure)
{
	struct sna *sna = closure;
	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
	int i;

	DBG(("%s()\n", __FUNCTION__));

	/* Drain the event queue */
766
	while (event_pending(fd)) {
767
768
		struct udev_device *dev;

769
		DBG(("%s: waiting for uevent\n", __FUNCTION__));
770
771
772
773
774
		dev = udev_monitor_receive_device(sna->mode.backlight_monitor);
		if (dev == NULL)
			break;

		udev_device_unref(dev);
775
	}
776
777

	/* Query all backlights for any changes */
778
	DBG(("%s: probing backlights for changes\n", __FUNCTION__));
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
	for (i = 0; i < sna->mode.num_real_output; i++) {
		xf86OutputPtr output = config->output[i];
		struct sna_output *sna_output = to_sna_output(output);
		int val;

		if (sna_output->dpms_mode != DPMSModeOn)
			continue;

		val = backlight_get(&sna_output->backlight);
		if (val < 0)
			continue;
		DBG(("%s(%s): backlight '%s' was %d, now %d\n",
		     __FUNCTION__, output->name, sna_output->backlight.iface,
		     sna_output->backlight_active_level, val));

		if (val == sna_output->backlight_active_level)
			continue;

		sna_output->backlight_active_level = val;

799
800
801
802
803
804
805
806
807
808
809
		if (output->randr_output) {
			DBG(("%s(%s): sending change notification\n", __FUNCTION__, output->name));
			RRChangeOutputProperty(output->randr_output,
					       backlight_atom, XA_INTEGER,
					       32, PropModeReplace, 1, &val,
					       TRUE, FALSE);
			RRChangeOutputProperty(output->randr_output,
					       backlight_deprecated_atom, XA_INTEGER,
					       32, PropModeReplace, 1, &val,
					       TRUE, FALSE);
		}
810
	}
811
	DBG(("%s: complete\n", __FUNCTION__));
812
813
814
815
816
817
818
}

static void sna_backlight_pre_init(struct sna *sna)
{
	struct udev *u;
	struct udev_monitor *mon;

819
820
821
822
#if !USE_BACKLIGHT
	return;
#endif

823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
	u = udev_new();
	if (!u)
		return;

	mon = udev_monitor_new_from_netlink(u, "udev");
	if (!mon)
		goto free_udev;

	if (udev_monitor_filter_add_match_subsystem_devtype(mon, "backlight", NULL))
		goto free_monitor;

	if (udev_monitor_enable_receiving(mon))
		goto free_monitor;

	sna->mode.backlight_handler =
		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
				      sna_backlight_uevent, sna);
	if (!sna->mode.backlight_handler)
		goto free_monitor;

	DBG(("%s: installed backlight monitor\n", __FUNCTION__));
	sna->mode.backlight_monitor = mon;

	return;

free_monitor:
	udev_monitor_unref(mon);
free_udev:
	udev_unref(u);
}

static void sna_backlight_drain_uevents(struct sna *sna)
{
	if (sna->mode.backlight_monitor == NULL)
		return;

859
	DBG(("%s()\n", __FUNCTION__));
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
	sna_backlight_uevent(udev_monitor_get_fd(sna->mode.backlight_monitor),
			     sna);
}

static void sna_backlight_close(struct sna *sna)
{
	struct udev *u;

	if (sna->mode.backlight_handler == NULL)
		return;

	xf86RemoveGeneralHandler(sna->mode.backlight_handler);

	u = udev_monitor_get_udev(sna->mode.backlight_monitor);
	udev_monitor_unref(sna->mode.backlight_monitor);
	udev_unref(u);

	sna->mode.backlight_handler = NULL;
	sna->mode.backlight_monitor = NULL;
}
#else
static void sna_backlight_pre_init(struct sna *sna) { }
static void sna_backlight_drain_uevents(struct sna *sna) { }
static void sna_backlight_close(struct sna *sna) { }
#endif

886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
static void
sna_output_backlight_disable(struct sna_output *sna_output)
{
	xf86OutputPtr output = sna_output->base;

	xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
		   "Failed to set backlight %s for output %s, disabling\n",
		   sna_output->backlight.iface, output->name);
	backlight_disable(&sna_output->backlight);
	if (output->randr_output) {
		RRDeleteOutputProperty(output->randr_output, backlight_atom);
		RRDeleteOutputProperty(output->randr_output, backlight_deprecated_atom);
	}
}

901
static int
902
sna_output_backlight_set(struct sna_output *sna_output, int level)
903
{
904
	int ret = 0;
905

906
	DBG(("%s(%s) level=%d, max=%d\n", __FUNCTION__,
907
	     sna_output->base->name, level, sna_output->backlight.max));
908

909
	if (backlight_set(&sna_output->backlight, level)) {
910
		sna_output_backlight_disable(sna_output);
911
		ret = -1;
912
	}
913
914
915
916
917

	/* Consume the uevent notification now so that we don't misconstrue
	 * the change latter when we wake up and the output is in a different
	 * state.
	 */
918
	sna_backlight_drain_uevents(to_sna(sna_output->base->scrn));
919
	return ret;
920
921
}

922
923
924
925
926
927
static bool
has_native_backlight(struct sna_output *sna_output)
{
	return sna_output->backlight.type == BL_RAW;
}

928
929
930
static void
sna_output_backlight_off(struct sna_output *sna_output)
{
931
932
933
934
935
936
937
	/* Trust the kernel to turn the native backlight off. However, we
	 * do explicitly turn the backlight back on (when we wake the output)
	 * just in case a third party turns it off!
	 */
	if (has_native_backlight(sna_output))
		return;

Chris Wilson's avatar
Chris Wilson committed
938
	DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name));
939
940
941
942
943
944
945
	backlight_off(&sna_output->backlight);
	sna_output_backlight_set(sna_output, 0);
}

static void
sna_output_backlight_on(struct sna_output *sna_output)
{
Chris Wilson's avatar
Chris Wilson committed
946
	DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name));
947
948
	sna_output_backlight_set(sna_output,
				 sna_output->backlight_active_level);
949
950
	if (backlight_on(&sna_output->backlight) < 0)
		sna_output_backlight_disable(sna_output);
951
952
}

953
954
955
956
static int
sna_output_backlight_get(xf86OutputPtr output)
{
	struct sna_output *sna_output = output->driver_private;
957
958
959
	int level = backlight_get(&sna_output->backlight);
	DBG(("%s(%s) level=%d, max=%d\n", __FUNCTION__,
	     output->name, level, sna_output->backlight.max));
960
961
962
	return level;
}

963
964
965
966
static char *
has_user_backlight_override(xf86OutputPtr output)
{
	struct sna *sna = to_sna(output->scrn);
967
	const char *str;
968
969
970
971
972

	str = xf86GetOptValString(sna->Options, OPTION_BACKLIGHT);
	if (str == NULL)
		return NULL;

Chris Wilson's avatar
Chris Wilson committed
973
	DBG(("%s(%s) requested %s\n", __FUNCTION__, output->name, str));
974
	if (*str == '\0')
Chris Wilson's avatar
Chris Wilson committed
975
		return (char *)str;
976

977
	if (!backlight_exists(str)) {
978
		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
979
			   "Unrecognised backlight control interface '%s'\n",
980
981
982
983
			   str);
		return NULL;
	}

984
	return strdup(str);
985
986
}

987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
static int get_device_minor(int fd)
{
	struct stat st;

	if (fstat(fd, &st) || !S_ISCHR(st.st_mode))
		return -1;

	return st.st_rdev & 0x63;
}

static const char * const sysfs_connector_types[] = {
	/* DRM_MODE_CONNECTOR_Unknown */	"Unknown",
	/* DRM_MODE_CONNECTOR_VGA */		"VGA",
	/* DRM_MODE_CONNECTOR_DVII */		"DVI-I",
	/* DRM_MODE_CONNECTOR_DVID */		"DVI-D",
	/* DRM_MODE_CONNECTOR_DVIA */		"DVI-A",
	/* DRM_MODE_CONNECTOR_Composite */	"Composite",
	/* DRM_MODE_CONNECTOR_SVIDEO */		"SVIDEO",
	/* DRM_MODE_CONNECTOR_LVDS */		"LVDS",
	/* DRM_MODE_CONNECTOR_Component */	"Component",
	/* DRM_MODE_CONNECTOR_9PinDIN */	"DIN",
	/* DRM_MODE_CONNECTOR_DisplayPort */	"DP",
	/* DRM_MODE_CONNECTOR_HDMIA */		"HDMI-A",
	/* DRM_MODE_CONNECTOR_HDMIB */		"HDMI-B",
	/* DRM_MODE_CONNECTOR_TV */		"TV",
	/* DRM_MODE_CONNECTOR_eDP */		"eDP",
	/* DRM_MODE_CONNECTOR_VIRTUAL */	"Virtual",
	/* DRM_MODE_CONNECTOR_DSI */		"DSI",
	/* DRM_MODE_CONNECTOR_DPI */		"DPI"
};

1018
static char *has_connector_backlight(xf86OutputPtr output)
1019
1020
1021
1022
1023
1024
1025
{
	struct sna_output *sna_output = output->driver_private;
	struct sna *sna = to_sna(output->scrn);
	char path[1024];
	DIR *dir;
	struct dirent *de;
	int minor, len;
1026
	char *str = NULL;
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042

	if (sna_output->connector_type >= ARRAY_SIZE(sysfs_connector_types))
		return NULL;

	minor = get_device_minor(sna->kgem.fd);
	if (minor < 0)
		return NULL;

	len = snprintf(path, sizeof(path),
		       "/sys/class/drm/card%d-%s-%d",
		       minor,
		       sysfs_connector_types[sna_output->connector_type],
		       sna_output->connector_type_id);
	DBG(("%s: lookup %s\n", __FUNCTION__, path));

	dir = opendir(path);
1043
1044
1045
	if (dir == NULL)
		return NULL;

1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
	while ((de = readdir(dir))) {
		struct stat st;

		if (*de->d_name == '.')
			continue;

		snprintf(path + len, sizeof(path) - len,
			 "/%s", de->d_name);

		if (stat(path, &st))
			continue;

		if (!S_ISDIR(st.st_mode))
			continue;

		DBG(("%s: testing %s as backlight\n",
		     __FUNCTION__, de->d_name));

		if (backlight_exists(de->d_name)) {
1065
			str = strdup(de->d_name); /* leak! */
1066
1067
1068
1069
1070
			break;
		}
	}

	closedir(dir);
1071
	return str;
1072
1073
}

1074
1075
1076
1077
static void
sna_output_backlight_init(xf86OutputPtr output)
{
	struct sna_output *sna_output = output->driver_private;
1078
	struct pci_device *pci;
1079
	MessageType from;
1080
1081
	char *best_iface;

1082
1083
1084
1085
#if !USE_BACKLIGHT
	return;
#endif

1086
1087
1088
1089
1090
1091
1092
	if (sna_output->is_panel) {
		from = X_CONFIG;
		best_iface = has_user_backlight_override(output);
		if (best_iface)
			goto done;
	}

1093
	best_iface = has_connector_backlight(output);
1094
1095
1096
	if (best_iface)
		goto done;

1097
1098
1099
	if (!sna_output->is_panel)
		return;

1100
1101
	/* XXX detect right backlight for multi-GPU/panels */
	from = X_PROBED;
1102
1103
1104
	pci = xf86GetPciInfoForEntity(to_sna(output->scrn)->pEnt->index);
	if (pci != NULL)
		best_iface = backlight_find_for_device(pci);
1105
1106

done:
1107
1108
	DBG(("%s(%s) opening backlight %s\n", __FUNCTION__,
	     output->name, best_iface ?: "none"));
1109
1110
	sna_output->backlight_active_level =
		backlight_open(&sna_output->backlight, best_iface);
1111
1112
	DBG(("%s(%s): initial backlight value %d\n",
	     __FUNCTION__, output->name, sna_output->backlight_active_level));
1113
1114
1115
	if (sna_output->backlight_active_level < 0)
		return;

1116
1117
1118
1119
	switch (sna_output->backlight.type) {
	case BL_FIRMWARE: best_iface = (char *)"firmware"; break;
	case BL_PLATFORM: best_iface = (char *)"platform"; break;
	case BL_RAW: best_iface = (char *)"raw"; break;
1120
	default: best_iface = (char *)"unknown"; break;
1121
	}
1122
	xf86DrvMsg(output->scrn->scrnIndex, from,
1123
1124
		   "Found backlight control interface %s (type '%s') for output %s\n",
		   sna_output->backlight.iface, best_iface, output->name);
1125
1126
}

1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
#if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(22, 0)
static inline int sigio_block(void)
{
	return 0;
}
static inline void sigio_unblock(int was_blocked)
{
	(void)was_blocked;
}
#elif XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
static inline int sigio_block(void)
{
	OsBlockSIGIO();
	return 0;
}
static inline void sigio_unblock(int was_blocked)
{
	OsReleaseSIGIO();
	(void)was_blocked;
}
#else
#include <xf86_OSproc.h>
static inline int sigio_block(void)
{
	return xf86BlockSIGIO();
}
static inline void sigio_unblock(int was_blocked)
{
	xf86UnblockSIGIO(was_blocked);
}
#endif

1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
static char *canonical_kmode_name(const struct drm_mode_modeinfo *kmode)
{
	char tmp[32], *buf;
	int len;

	len = sprintf(tmp, "%dx%d%s",
		      kmode->hdisplay, kmode->vdisplay,
		      kmode->flags & V_INTERLACE ? "i" : "");
	if ((unsigned)len >= sizeof(tmp))
		return NULL;

	buf = malloc(len + 1);
	if (buf == NULL)
		return NULL;

	return memcpy(buf, tmp, len + 1);
}

static char *get_kmode_name(const struct drm_mode_modeinfo *kmode)
{
	if (*kmode->name == '\0')
		return canonical_kmode_name(kmode);

	return strdup(kmode->name);
}

1185
static DisplayModePtr
1186
mode_from_kmode(ScrnInfoPtr scrn,
1187
1188
		const struct drm_mode_modeinfo *kmode,
		DisplayModePtr mode)
1189
{
1190
1191
1192
1193
1194
1195
	DBG(("kmode: %s, clock=%d, %d %d %d %d %d, %d %d %d %d %d, flags=%x, type=%x\n",
	     kmode->name, kmode->clock,
	     kmode->hdisplay, kmode->hsync_start, kmode->hsync_end, kmode->htotal, kmode->hskew,
	     kmode->vdisplay, kmode->vsync_start, kmode->vsync_end, kmode->vtotal, kmode->vscan,
	     kmode->flags, kmode->type));

1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
	mode->status = MODE_OK;

	mode->Clock = kmode->clock;

	mode->HDisplay = kmode->hdisplay;
	mode->HSyncStart = kmode->hsync_start;
	mode->HSyncEnd = kmode->hsync_end;
	mode->HTotal = kmode->htotal;
	mode->HSkew = kmode->hskew;

	mode->VDisplay = kmode->vdisplay;
	mode->VSyncStart = kmode->vsync_start;
	mode->VSyncEnd = kmode->vsync_end;
	mode->VTotal = kmode->vtotal;
	mode->VScan = kmode->vscan;

1212
	mode->VRefresh = kmode->vrefresh;
1213
	mode->Flags = kmode->flags;
1214
	mode->name = get_kmode_name(kmode);
1215
1216
1217
1218
1219
1220

	if (kmode->type & DRM_MODE_TYPE_DRIVER)
		mode->type = M_T_DRIVER;
	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
		mode->type |= M_T_PREFERRED;

1221
1222
1223
	if (mode->status == MODE_OK && kmode->flags & ~KNOWN_MODE_FLAGS)
		mode->status = MODE_BAD; /* unknown flags => unhandled */

1224
1225
	xf86SetModeCrtc(mode, scrn->adjustFlags);
	return mode;
1226
1227
1228
}

static void
1229
mode_to_kmode(struct drm_mode_modeinfo *kmode, DisplayModePtr mode)
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
{
	memset(kmode, 0, sizeof(*kmode));

	kmode->clock = mode->Clock;
	kmode->hdisplay = mode->HDisplay;
	kmode->hsync_start = mode->HSyncStart;
	kmode->hsync_end = mode->HSyncEnd;
	kmode->htotal = mode->HTotal;
	kmode->hskew = mode->HSkew;

	kmode->vdisplay = mode->VDisplay;
	kmode->vsync_start = mode->VSyncStart;
	kmode->vsync_end = mode->VSyncEnd;
	kmode->vtotal = mode->VTotal;
	kmode->vscan = mode->VScan;

1246
	kmode->vrefresh = mode->VRefresh;
1247
	kmode->flags = mode->Flags;
1248
1249
1250
1251
1252
	if (mode->name)
		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
}

1253
1254
1255
static void
sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
{
1256
	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1257
1258
	/* All attached outputs are valid, so update our timestamps */
	unsigned now = GetTimeInMillis();
1259
1260
	int i;

1261
	assert(to_sna_crtc(crtc));
1262
	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
1263

1264
1265
1266
1267
1268
1269
1270
	/* DPMS handling by the kernel is inconsistent, so after setting a
	 * mode on an output presume that we intend for it to be on, or that
	 * the kernel will force it on.
	 *
	 * So force DPMS to be on for all connected outputs, and restore
	 * the backlight.
	 */
1271
1272
	for (i = 0; i < config->num_output; i++) {
		xf86OutputPtr output = config->output[i];
1273
1274
1275
1276

		if (output->crtc != crtc)
			continue;

1277
		__sna_output_dpms(output, DPMSModeOn, false);
1278
1279
		if (to_sna_output(output)->last_detect)
			to_sna_output(output)->last_detect = now;
1280
	}
1281

1282
1283
1284
#if XF86_CRTC_VERSION >= 3
	crtc->active = TRUE;
#endif
1285
1286
}

1287
1288
1289
1290
1291
1292
static void
sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
{
	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
	int i;

1293
	assert(to_sna_crtc(crtc));
1294
	DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308

	/* DPMS handling by the kernel is inconsistent, so after setting a
	 * mode on an output presume that we intend for it to be on, or that
	 * the kernel will force it on.
	 *
	 * So force DPMS to be on for all connected outputs, and restore
	 * the backlight.
	 */
	for (i = 0; i < config->num_output; i++) {
		xf86OutputPtr output = config->output[i];

		if (output->crtc != crtc)
			continue;

1309
		__sna_output_dpms(output, DPMSModeOff, false);
1310
1311
1312
	}
}

1313
static unsigned
1314
rotation_reflect(unsigned rotation)
1315
{
1316
	unsigned other_bits;
1317

1318
1319
	/* paranoia for future extensions */
	other_bits = rotation & ~RR_Rotate_All;
1320

1321
1322
	/* flip the reflection to compensate for reflecting the rotation */
	other_bits ^= RR_Reflect_X | RR_Reflect_Y;
1323

1324
1325
1326
1327
1328
1329
1330
1331
	/* Reflect the screen by rotating the rotation bit,
	 * which has to have at least RR_Rotate_0 set. This allows
	 * us to reflect any of the rotation bits, not just 0.
	 */
	rotation &= RR_Rotate_All;
	assert(rotation);
	rotation <<= 2; /* RR_Rotate_0 -> RR_Rotate_180 etc */
	rotation |= rotation >> 4; /* RR_Rotate_270' to RR_Rotate_90 */
1332
1333
	rotation &= RR_Rotate_All;
	assert(rotation);
1334

1335
1336
	return rotation | other_bits;
}
1337

1338
1339
1340
1341
1342
1343
1344
1345
static unsigned
rotation_reduce(struct plane *p, unsigned rotation)
{
	/* If unsupported try exchanging rotation for a reflection */
	if (rotation & ~p->rotation.supported) {
		unsigned new_rotation = rotation_reflect(rotation);
		if ((new_rotation & p->rotation.supported) == new_rotation)
			rotation = new_rotation;
1346
1347
	}

Bob Paauwe's avatar