kms_ccs.c 13.8 KB
Newer Older
1 2 3 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
/*
 * Copyright © 2016 Intel Corporation
 *
 * 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.
 *
 */

#include "igt.h"

IGT_TEST_DESCRIPTION("Test render compression (RC), in which the main surface "
		     "is complemented by a color control surface (CCS) that "
		     "the display uses to interpret the compressed data.");

enum test_flags {
	TEST_CRC			= 1 << 1,
	TEST_ROTATE_180			= 1 << 2,
	TEST_BAD_PIXEL_FORMAT		= 1 << 3,
	TEST_BAD_ROTATION_90		= 1 << 4,
36
	TEST_NO_AUX_BUFFER		= 1 << 5,
37
	TEST_BAD_CCS_HANDLE		= 1 << 6,
38
	TEST_BAD_AUX_STRIDE		= 1 << 7,
39 40
};

41
#define TEST_FAIL_ON_ADDFB2 \
42 43
	(TEST_BAD_PIXEL_FORMAT | TEST_NO_AUX_BUFFER | TEST_BAD_CCS_HANDLE | \
	 TEST_BAD_AUX_STRIDE)
44

45 46
enum test_fb_flags {
	FB_COMPRESSED			= 1 << 0,
47
	FB_HAS_PLANE			= 1 << 1,
48 49 50
	FB_MISALIGN_AUX_STRIDE		= 1 << 2,
	FB_SMALL_AUX_STRIDE		= 1 << 3,
	FB_ZERO_AUX_STRIDE		= 1 << 4,
51 52
};

53 54 55 56 57 58
typedef struct {
	int drm_fd;
	igt_display_t display;
	igt_output_t *output;
	enum pipe pipe;
	enum test_flags flags;
59
	igt_plane_t *plane;
60
	igt_pipe_crc_t *pipe_crc;
61
	uint64_t ccs_modifier;
62 63
} data_t;

64 65 66 67 68 69 70 71
static const struct {
	double r;
	double g;
	double b;
} colors[2] = {
	{1.0, 0.0, 0.0},
	{0.0, 1.0, 0.0}
};
72

73
static const uint64_t ccs_modifiers[] = {
74 75
	LOCAL_I915_FORMAT_MOD_Y_TILED_CCS,
	LOCAL_I915_FORMAT_MOD_Yf_TILED_CCS,
76 77
};

78 79 80 81 82 83 84 85 86
/*
 * Limit maximum used sprite plane width so this test will not mistakenly
 * fail on hardware limitations which are not interesting to this test.
 * On this test too wide sprite plane may fail during creation with dmesg
 * comment saying:
 * "Requested display configuration exceeds system watermark limitations"
 */
#define MAX_SPRITE_PLANE_WIDTH 2000

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
struct local_drm_format_modifier {
       /* Bitmask of formats in get_plane format list this info applies to. The
	* offset allows a sliding window of which 64 formats (bits).
	*
	* Some examples:
	* In today's world with < 65 formats, and formats 0, and 2 are
	* supported
	* 0x0000000000000005
	*		  ^-offset = 0, formats = 5
	*
	* If the number formats grew to 128, and formats 98-102 are
	* supported with the modifier:
	*
	* 0x0000003c00000000 0000000000000000
	*		  ^
	*		  |__offset = 64, formats = 0x3c00000000
	*
	*/
       uint64_t formats;
       uint32_t offset;
       uint32_t pad;

       /* This modifier can be used with the format for this plane. */
       uint64_t modifier;
};

struct local_drm_format_modifier_blob {
#define LOCAL_FORMAT_BLOB_CURRENT 1
	/* Version of this blob format */
	uint32_t version;

	/* Flags */
	uint32_t flags;

	/* Number of fourcc formats supported */
	uint32_t count_formats;

	/* Where in this blob the formats exist (in bytes) */
	uint32_t formats_offset;

	/* Number of drm_format_modifiers */
	uint32_t count_modifiers;

	/* Where in this blob the modifiers exist (in bytes) */
	uint32_t modifiers_offset;

	/* u32 formats[] */
	/* struct drm_format_modifier modifiers[] */
};

static inline uint32_t *
formats_ptr(struct local_drm_format_modifier_blob *blob)
{
	return (uint32_t *)(((char *)blob) + blob->formats_offset);
}

static inline struct local_drm_format_modifier *
modifiers_ptr(struct local_drm_format_modifier_blob *blob)
{
	return (struct local_drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
}

149 150
static bool plane_has_format_with_ccs(data_t *data, igt_plane_t *plane,
				      uint32_t format)
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
{
	drmModePropertyBlobPtr blob;
	struct local_drm_format_modifier_blob *blob_data;
	struct local_drm_format_modifier *modifiers, *last_mod;
	uint32_t *formats, *last_fmt;
	uint64_t blob_id;
	bool ret;
	int fmt_idx = -1;

	ret = kmstest_get_property(data->drm_fd, plane->drm_plane->plane_id,
				   DRM_MODE_OBJECT_PLANE, "IN_FORMATS",
				   NULL, &blob_id, NULL);
	igt_skip_on_f(ret == false, "IN_FORMATS not supported by kernel\n");
	igt_skip_on_f(blob_id == 0, "IN_FORMATS not supported by plane\n");
	blob = drmModeGetPropertyBlob(data->drm_fd, blob_id);
	igt_assert(blob);
	igt_assert_lte(sizeof(struct local_drm_format_modifier_blob),
		       blob->length);

	blob_data = (struct local_drm_format_modifier_blob *) blob->data;
	formats = formats_ptr(blob_data);
	last_fmt = &formats[blob_data->count_formats];
	igt_assert_lte(((char *) last_fmt - (char *) blob_data), blob->length);
	for (int i = 0; i < blob_data->count_formats; i++) {
		if (formats[i] == format) {
			fmt_idx = i;
			break;
		}
	}

181 182
	if (fmt_idx == -1)
		return false;
183 184 185 186 187

	modifiers = modifiers_ptr(blob_data);
	last_mod = &modifiers[blob_data->count_modifiers];
	igt_assert_lte(((char *) last_mod - (char *) blob_data), blob->length);
	for (int i = 0; i < blob_data->count_modifiers; i++) {
188
		if (modifiers[i].modifier != data->ccs_modifier)
189 190 191 192 193 194 195 196
			continue;

		if (modifiers[i].offset > fmt_idx ||
		    fmt_idx > modifiers[i].offset + 63)
			continue;

		if (modifiers[i].formats &
		    (1UL << (fmt_idx - modifiers[i].offset)))
197
			return true;
198 199
	}

200
	return false;
201
}
202

203
static void addfb_init(struct igt_fb *fb, struct drm_mode_fb_cmd2 *f)
204
{
205 206
	int i;

207 208 209 210
	f->width = fb->width;
	f->height = fb->height;
	f->pixel_format = fb->drm_format;
	f->flags = LOCAL_DRM_MODE_FB_MODIFIERS;
211

212 213 214 215 216
	for (i = 0; i < fb->num_planes; i++) {
		f->handles[i] = fb->gem_handle;
		f->modifier[i] = fb->modifier;
		f->pitches[i] = fb->strides[i];
		f->offsets[i] = fb->offsets[i];
217
	}
218 219
}

220 221 222
static void generate_fb(data_t *data, struct igt_fb *fb,
			int width, int height,
			enum test_fb_flags fb_flags)
223
{
224 225
	struct drm_mode_fb_cmd2 f = {0};
	uint32_t format;
226
	uint64_t modifier;
227
	cairo_t *cr;
228
	int ret;
229

230 231 232 233 234
	/* Use either compressed or Y-tiled to test. However, given the lack of
	 * available bandwidth, we use linear for the primary plane when
	 * testing sprites, since we cannot fit two CCS planes into the
	 * available FIFO configurations.
	 */
235
	if (fb_flags & FB_COMPRESSED)
236
		modifier = data->ccs_modifier;
237
	else if (!(fb_flags & FB_HAS_PLANE))
238
		modifier = LOCAL_I915_FORMAT_MOD_Y_TILED;
239 240
	else
		modifier = 0;
241 242

	if (data->flags & TEST_BAD_PIXEL_FORMAT)
243
		format = DRM_FORMAT_RGB565;
244
	else
245
		format = DRM_FORMAT_XRGB8888;
246

247 248
	igt_create_bo_for_fb(data->drm_fd, width, height, format, modifier, fb);
	igt_assert(fb->gem_handle > 0);
249

250
	addfb_init(fb, &f);
251

252
	if (fb_flags & FB_COMPRESSED) {
253 254 255
		if (fb_flags & FB_MISALIGN_AUX_STRIDE) {
			igt_skip_on_f(width <= 1024,
				      "FB already has the smallest possible stride\n");
256
			f.pitches[1] -= 64;
257
		}
258 259

		if (fb_flags & FB_SMALL_AUX_STRIDE) {
260 261
			igt_skip_on_f(width <= 1024,
				      "FB already has the smallest possible stride\n");
262
			f.pitches[1] = ALIGN(f.pitches[1]/2, 128);
263 264
		}

265 266
		if (fb_flags & FB_ZERO_AUX_STRIDE)
			f.pitches[1] = 0;
267

268 269 270
		/* Put the CCS buffer on a different BO. */
		if (data->flags & TEST_BAD_CCS_HANDLE)
			f.handles[1] = gem_create(data->drm_fd, fb->size);
271

272 273 274 275 276
		if (data->flags & TEST_NO_AUX_BUFFER) {
			f.handles[1] = 0;
			f.modifier[1] = 0;
			f.pitches[1] = 0;
			f.offsets[1] = 0;
277 278
		}
	}
279

280 281 282 283 284 285 286 287
	if (!(data->flags & TEST_BAD_PIXEL_FORMAT)) {
		int c = !!data->plane;

		cr = igt_get_cairo_ctx(data->drm_fd, fb);
		igt_paint_color(cr, 0, 0, width, height,
				colors[c].r, colors[c].g, colors[c].b);
		igt_put_cairo_ctx(data->drm_fd, fb, cr);
	}
288

289
	ret = drmIoctl(data->drm_fd, LOCAL_DRM_IOCTL_MODE_ADDFB2, &f);
290
	if (data->flags & TEST_FAIL_ON_ADDFB2) {
291 292 293 294 295 296 297
		igt_assert_eq(ret, -1);
		igt_assert_eq(errno, EINVAL);
		return;
	} else
		igt_assert_eq(ret, 0);

	fb->fb_id = f.fb_id;
298 299
}

300
static bool try_config(data_t *data, enum test_fb_flags fb_flags,
301
		       igt_crc_t *crc)
302 303 304 305 306
{
	igt_display_t *display = &data->display;
	igt_plane_t *primary;
	drmModeModeInfo *drm_mode = igt_output_get_mode(data->output);
	enum igt_commit_style commit;
307
	struct igt_fb fb, fb_sprite;
308
	int ret;
309

310 311 312 313
	if (data->display.is_atomic)
		commit = COMMIT_ATOMIC;
	else
		commit = COMMIT_UNIVERSAL;
314

315 316
	primary = igt_output_get_plane_type(data->output,
					    DRM_PLANE_TYPE_PRIMARY);
317 318
	if (!plane_has_format_with_ccs(data, primary, DRM_FORMAT_XRGB8888))
		return false;
319

320
	if (data->plane && fb_flags & FB_COMPRESSED) {
321 322
		if (!plane_has_format_with_ccs(data, data->plane, DRM_FORMAT_XRGB8888))
			return false;
323

324
		generate_fb(data, &fb, min(MAX_SPRITE_PLANE_WIDTH, drm_mode->hdisplay),
325 326
			    drm_mode->vdisplay,
			    (fb_flags & ~FB_COMPRESSED) | FB_HAS_PLANE);
327
		generate_fb(data, &fb_sprite, 256, 256, fb_flags);
328
	} else {
329
		generate_fb(data, &fb, min(MAX_SPRITE_PLANE_WIDTH, drm_mode->hdisplay),
330 331 332
			    drm_mode->vdisplay, fb_flags);
	}

333
	if (data->flags & TEST_FAIL_ON_ADDFB2)
334
		return true;
335

336 337
	igt_plane_set_position(primary, 0, 0);
	igt_plane_set_size(primary, drm_mode->hdisplay, drm_mode->vdisplay);
338
	igt_plane_set_fb(primary, &fb);
339

340 341 342
	if (data->plane && fb_flags & FB_COMPRESSED) {
		igt_plane_set_position(data->plane, 0, 0);
		igt_plane_set_size(data->plane, 256, 256);
343
		igt_plane_set_fb(data->plane, &fb_sprite);
344 345
	}

346 347 348 349 350 351
	if (data->flags & TEST_ROTATE_180)
		igt_plane_set_rotation(primary, IGT_ROTATION_180);
	if (data->flags & TEST_BAD_ROTATION_90)
		igt_plane_set_rotation(primary, IGT_ROTATION_90);

	ret = igt_display_try_commit2(display, commit);
352
	if (data->flags & TEST_BAD_ROTATION_90) {
353
		igt_assert_eq(ret, -EINVAL);
354
	} else {
355 356
		igt_assert_eq(ret, 0);

357 358 359 360
		if (crc)
			igt_pipe_crc_collect_crc(data->pipe_crc, crc);
	}

361
	igt_debug_wait_for_keypress("ccs");
362 363 364 365 366

	if (data->plane && fb_flags & FB_COMPRESSED) {
		igt_plane_set_position(data->plane, 0, 0);
		igt_plane_set_size(data->plane, 0, 0);
		igt_plane_set_fb(data->plane, NULL);
367
		igt_remove_fb(display->drm_fd, &fb_sprite);
368
	}
369 370 371 372 373 374 375

	igt_plane_set_fb(primary, NULL);
	igt_plane_set_rotation(primary, IGT_ROTATION_0);
	igt_display_commit2(display, commit);

	if (data->flags & TEST_CRC)
		igt_remove_fb(data->drm_fd, &fb);
376 377

	return true;
378 379
}

380 381
static int test_ccs(data_t *data)
{	int valid_tests = 0;
382
	igt_crc_t crc, ref_crc;
383
	enum test_fb_flags fb_flags = 0;
384 385

	if (data->flags & TEST_CRC) {
386
		data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
387

388 389 390 391 392
		if (try_config(data, fb_flags | FB_COMPRESSED, &ref_crc) &&
		    try_config(data, fb_flags, &crc)) {
			igt_assert_crc_equal(&crc, &ref_crc);
			valid_tests++;
		}
393

394 395
		igt_pipe_crc_free(data->pipe_crc);
		data->pipe_crc = NULL;
396 397 398
	}

	if (data->flags & TEST_BAD_PIXEL_FORMAT ||
399
	    data->flags & TEST_BAD_ROTATION_90 ||
400 401
	    data->flags & TEST_NO_AUX_BUFFER ||
	    data->flags & TEST_BAD_CCS_HANDLE) {
402
		valid_tests += try_config(data, fb_flags | FB_COMPRESSED, NULL);
403 404
	}

405
	if (data->flags & TEST_BAD_AUX_STRIDE) {
406 407 408
		valid_tests += try_config(data, fb_flags | FB_COMPRESSED | FB_MISALIGN_AUX_STRIDE , NULL);
		valid_tests += try_config(data, fb_flags | FB_COMPRESSED | FB_SMALL_AUX_STRIDE , NULL);
		valid_tests += try_config(data, fb_flags | FB_COMPRESSED | FB_ZERO_AUX_STRIDE , NULL);
409 410
	}

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
	return valid_tests;
}

static int test_output(data_t *data)
{
	igt_display_t *display = &data->display;
	int i, valid_tests = 0;

	igt_display_require_output_on_pipe(display, data->pipe);

	/* Sets data->output with a valid output. */
	for_each_valid_output_on_pipe(display, data->pipe, data->output) {
		break;
	}

	igt_output_set_pipe(data->output, data->pipe);

	for (i = 0; i < ARRAY_SIZE(ccs_modifiers); i++) {
		data->ccs_modifier = ccs_modifiers[i];
		valid_tests += test_ccs(data);
	}

	igt_output_set_pipe(data->output, PIPE_NONE);
434
	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
435 436

	return valid_tests;
437 438 439 440 441 442
}

static data_t data;

igt_main
{
443 444
	enum pipe pipe;

445 446 447 448 449
	igt_fixture {
		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);

		igt_require(intel_gen(intel_get_drm_devid(data.drm_fd)) >= 9);
		kmstest_set_vt_graphics_mode();
450
		igt_require_pipe_crc(data.drm_fd);
451

452
		igt_display_require(&data.display, data.drm_fd);
453 454
	}

455 456
	for_each_pipe_static(pipe) {
		const char *pipe_name = kmstest_pipe_name(pipe);
457

458 459
		data.pipe = pipe;

460
		data.flags = TEST_BAD_PIXEL_FORMAT;
461
		igt_subtest_f("pipe-%s-bad-pixel-format", pipe_name)
462
			igt_require(test_output(&data));
463 464

		data.flags = TEST_BAD_ROTATION_90;
465
		igt_subtest_f("pipe-%s-bad-rotation-90", pipe_name)
466
			igt_require(test_output(&data));
467 468

		data.flags = TEST_CRC;
469
		igt_subtest_f("pipe-%s-crc-primary-basic", pipe_name)
470
			igt_require(test_output(&data));
471 472 473

		data.flags = TEST_CRC | TEST_ROTATE_180;
		igt_subtest_f("pipe-%s-crc-primary-rotation-180", pipe_name)
474
			igt_require(test_output(&data));
475 476

		data.flags = TEST_CRC;
477
		igt_subtest_f("pipe-%s-crc-sprite-planes-basic", pipe_name) {
478
			int valid_tests = 0;
479 480 481

			igt_display_require_output_on_pipe(&data.display, data.pipe);

482 483 484
			for_each_plane_on_pipe(&data.display, data.pipe, data.plane) {
				if (data.plane->type == DRM_PLANE_TYPE_PRIMARY)
					continue;
485
				valid_tests += test_output(&data);
486
			}
487 488

			igt_require(valid_tests);
489 490 491
		}

		data.plane = NULL;
492 493 494

		data.flags = TEST_NO_AUX_BUFFER;
		igt_subtest_f("pipe-%s-missing-ccs-buffer", pipe_name)
495
			igt_require(test_output(&data));
496

497 498
		data.flags = TEST_BAD_CCS_HANDLE;
		igt_subtest_f("pipe-%s-ccs-on-another-bo", pipe_name)
499
			igt_require(test_output(&data));
500 501 502

		data.flags = TEST_BAD_AUX_STRIDE;
		igt_subtest_f("pipe-%s-bad-aux-stride", pipe_name)
503
			igt_require(test_output(&data));
504 505 506 507 508
	}

	igt_fixture
		igt_display_fini(&data.display);
}