• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2016 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  */
24 
25 #include "igt.h"
26 
27 IGT_TEST_DESCRIPTION("Test render compression (RC), in which the main surface "
28 		     "is complemented by a color control surface (CCS) that "
29 		     "the display uses to interpret the compressed data.");
30 
31 enum test_flags {
32 	TEST_CRC			= 1 << 1,
33 	TEST_ROTATE_180			= 1 << 2,
34 	TEST_BAD_PIXEL_FORMAT		= 1 << 3,
35 	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 	(TEST_BAD_PIXEL_FORMAT | TEST_NO_AUX_BUFFER | TEST_BAD_CCS_HANDLE | \
43 	 TEST_BAD_AUX_STRIDE)
44 
45 enum test_fb_flags {
46 	FB_COMPRESSED			= 1 << 0,
47 	FB_HAS_PLANE			= 1 << 1,
48 	FB_MISALIGN_AUX_STRIDE		= 1 << 2,
49 	FB_SMALL_AUX_STRIDE		= 1 << 3,
50 	FB_ZERO_AUX_STRIDE		= 1 << 4,
51 };
52 
53 typedef struct {
54 	int drm_fd;
55 	igt_display_t display;
56 	igt_output_t *output;
57 	enum pipe pipe;
58 	enum test_flags flags;
59 	igt_plane_t *plane;
60 	igt_pipe_crc_t *pipe_crc;
61 	uint64_t ccs_modifier;
62 } data_t;
63 
64 static const struct {
65 	double r;
66 	double g;
67 	double b;
68 } colors[2] = {
69 	{1.0, 0.0, 0.0},
70 	{0.0, 1.0, 0.0}
71 };
72 
73 static const uint64_t ccs_modifiers[] = {
74 	LOCAL_I915_FORMAT_MOD_Y_TILED_CCS,
75 	LOCAL_I915_FORMAT_MOD_Yf_TILED_CCS,
76 };
77 
78 /*
79  * Limit maximum used sprite plane width so this test will not mistakenly
80  * fail on hardware limitations which are not interesting to this test.
81  * On this test too wide sprite plane may fail during creation with dmesg
82  * comment saying:
83  * "Requested display configuration exceeds system watermark limitations"
84  */
85 #define MAX_SPRITE_PLANE_WIDTH 2000
86 
addfb_init(struct igt_fb * fb,struct drm_mode_fb_cmd2 * f)87 static void addfb_init(struct igt_fb *fb, struct drm_mode_fb_cmd2 *f)
88 {
89 	int i;
90 
91 	f->width = fb->width;
92 	f->height = fb->height;
93 	f->pixel_format = fb->drm_format;
94 	f->flags = LOCAL_DRM_MODE_FB_MODIFIERS;
95 
96 	for (i = 0; i < fb->num_planes; i++) {
97 		f->handles[i] = fb->gem_handle;
98 		f->modifier[i] = fb->modifier;
99 		f->pitches[i] = fb->strides[i];
100 		f->offsets[i] = fb->offsets[i];
101 	}
102 }
103 
generate_fb(data_t * data,struct igt_fb * fb,int width,int height,enum test_fb_flags fb_flags)104 static void generate_fb(data_t *data, struct igt_fb *fb,
105 			int width, int height,
106 			enum test_fb_flags fb_flags)
107 {
108 	struct drm_mode_fb_cmd2 f = {0};
109 	uint32_t format;
110 	uint64_t modifier;
111 	cairo_t *cr;
112 	int ret;
113 
114 	/* Use either compressed or Y-tiled to test. However, given the lack of
115 	 * available bandwidth, we use linear for the primary plane when
116 	 * testing sprites, since we cannot fit two CCS planes into the
117 	 * available FIFO configurations.
118 	 */
119 	if (fb_flags & FB_COMPRESSED)
120 		modifier = data->ccs_modifier;
121 	else if (!(fb_flags & FB_HAS_PLANE))
122 		modifier = LOCAL_I915_FORMAT_MOD_Y_TILED;
123 	else
124 		modifier = 0;
125 
126 	if (data->flags & TEST_BAD_PIXEL_FORMAT)
127 		format = DRM_FORMAT_RGB565;
128 	else
129 		format = DRM_FORMAT_XRGB8888;
130 
131 	igt_create_bo_for_fb(data->drm_fd, width, height, format, modifier, fb);
132 	igt_assert(fb->gem_handle > 0);
133 
134 	addfb_init(fb, &f);
135 
136 	if (fb_flags & FB_COMPRESSED) {
137 		if (fb_flags & FB_MISALIGN_AUX_STRIDE) {
138 			igt_skip_on_f(width <= 1024,
139 				      "FB already has the smallest possible stride\n");
140 			f.pitches[1] -= 64;
141 		}
142 
143 		if (fb_flags & FB_SMALL_AUX_STRIDE) {
144 			igt_skip_on_f(width <= 1024,
145 				      "FB already has the smallest possible stride\n");
146 			f.pitches[1] = ALIGN(f.pitches[1]/2, 128);
147 		}
148 
149 		if (fb_flags & FB_ZERO_AUX_STRIDE)
150 			f.pitches[1] = 0;
151 
152 		/* Put the CCS buffer on a different BO. */
153 		if (data->flags & TEST_BAD_CCS_HANDLE)
154 			f.handles[1] = gem_create(data->drm_fd, fb->size);
155 
156 		if (data->flags & TEST_NO_AUX_BUFFER) {
157 			f.handles[1] = 0;
158 			f.modifier[1] = 0;
159 			f.pitches[1] = 0;
160 			f.offsets[1] = 0;
161 		}
162 	}
163 
164 	if (!(data->flags & TEST_BAD_PIXEL_FORMAT)) {
165 		int c = !!data->plane;
166 
167 		cr = igt_get_cairo_ctx(data->drm_fd, fb);
168 		igt_paint_color(cr, 0, 0, width, height,
169 				colors[c].r, colors[c].g, colors[c].b);
170 		igt_put_cairo_ctx(data->drm_fd, fb, cr);
171 	}
172 
173 	ret = drmIoctl(data->drm_fd, LOCAL_DRM_IOCTL_MODE_ADDFB2, &f);
174 	if (data->flags & TEST_FAIL_ON_ADDFB2) {
175 		igt_assert_eq(ret, -1);
176 		igt_assert_eq(errno, EINVAL);
177 		return;
178 	} else
179 		igt_assert_eq(ret, 0);
180 
181 	fb->fb_id = f.fb_id;
182 }
183 
try_config(data_t * data,enum test_fb_flags fb_flags,igt_crc_t * crc)184 static bool try_config(data_t *data, enum test_fb_flags fb_flags,
185 		       igt_crc_t *crc)
186 {
187 	igt_display_t *display = &data->display;
188 	igt_plane_t *primary;
189 	drmModeModeInfo *drm_mode = igt_output_get_mode(data->output);
190 	enum igt_commit_style commit;
191 	struct igt_fb fb, fb_sprite;
192 	int ret;
193 
194 	if (data->display.is_atomic)
195 		commit = COMMIT_ATOMIC;
196 	else
197 		commit = COMMIT_UNIVERSAL;
198 
199 	primary = igt_output_get_plane_type(data->output,
200 					    DRM_PLANE_TYPE_PRIMARY);
201 	if (!igt_plane_has_format_mod(primary, DRM_FORMAT_XRGB8888,
202 				      data->ccs_modifier))
203 		return false;
204 
205 	if (data->plane && fb_flags & FB_COMPRESSED) {
206 		if (!igt_plane_has_format_mod(data->plane, DRM_FORMAT_XRGB8888,
207 					      data->ccs_modifier))
208 			return false;
209 
210 		generate_fb(data, &fb, min(MAX_SPRITE_PLANE_WIDTH, drm_mode->hdisplay),
211 			    drm_mode->vdisplay,
212 			    (fb_flags & ~FB_COMPRESSED) | FB_HAS_PLANE);
213 		generate_fb(data, &fb_sprite, 256, 256, fb_flags);
214 	} else {
215 		generate_fb(data, &fb, min(MAX_SPRITE_PLANE_WIDTH, drm_mode->hdisplay),
216 			    drm_mode->vdisplay, fb_flags);
217 	}
218 
219 	if (data->flags & TEST_FAIL_ON_ADDFB2)
220 		return true;
221 
222 	igt_plane_set_position(primary, 0, 0);
223 	igt_plane_set_size(primary, drm_mode->hdisplay, drm_mode->vdisplay);
224 	igt_plane_set_fb(primary, &fb);
225 
226 	if (data->plane && fb_flags & FB_COMPRESSED) {
227 		igt_plane_set_position(data->plane, 0, 0);
228 		igt_plane_set_size(data->plane, 256, 256);
229 		igt_plane_set_fb(data->plane, &fb_sprite);
230 	}
231 
232 	if (data->flags & TEST_ROTATE_180)
233 		igt_plane_set_rotation(primary, IGT_ROTATION_180);
234 	if (data->flags & TEST_BAD_ROTATION_90)
235 		igt_plane_set_rotation(primary, IGT_ROTATION_90);
236 
237 	ret = igt_display_try_commit2(display, commit);
238 	if (data->flags & TEST_BAD_ROTATION_90) {
239 		igt_assert_eq(ret, -EINVAL);
240 	} else {
241 		igt_assert_eq(ret, 0);
242 
243 		if (crc)
244 			igt_pipe_crc_collect_crc(data->pipe_crc, crc);
245 	}
246 
247 	igt_debug_wait_for_keypress("ccs");
248 
249 	if (data->plane && fb_flags & FB_COMPRESSED) {
250 		igt_plane_set_position(data->plane, 0, 0);
251 		igt_plane_set_size(data->plane, 0, 0);
252 		igt_plane_set_fb(data->plane, NULL);
253 		igt_remove_fb(display->drm_fd, &fb_sprite);
254 	}
255 
256 	igt_plane_set_fb(primary, NULL);
257 	igt_plane_set_rotation(primary, IGT_ROTATION_0);
258 	igt_display_commit2(display, commit);
259 
260 	if (data->flags & TEST_CRC)
261 		igt_remove_fb(data->drm_fd, &fb);
262 
263 	return true;
264 }
265 
test_ccs(data_t * data)266 static int test_ccs(data_t *data)
267 {	int valid_tests = 0;
268 	igt_crc_t crc, ref_crc;
269 	enum test_fb_flags fb_flags = 0;
270 
271 	if (data->flags & TEST_CRC) {
272 		data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
273 
274 		if (try_config(data, fb_flags | FB_COMPRESSED, &ref_crc) &&
275 		    try_config(data, fb_flags, &crc)) {
276 			igt_assert_crc_equal(&crc, &ref_crc);
277 			valid_tests++;
278 		}
279 
280 		igt_pipe_crc_free(data->pipe_crc);
281 		data->pipe_crc = NULL;
282 	}
283 
284 	if (data->flags & TEST_BAD_PIXEL_FORMAT ||
285 	    data->flags & TEST_BAD_ROTATION_90 ||
286 	    data->flags & TEST_NO_AUX_BUFFER ||
287 	    data->flags & TEST_BAD_CCS_HANDLE) {
288 		valid_tests += try_config(data, fb_flags | FB_COMPRESSED, NULL);
289 	}
290 
291 	if (data->flags & TEST_BAD_AUX_STRIDE) {
292 		valid_tests += try_config(data, fb_flags | FB_COMPRESSED | FB_MISALIGN_AUX_STRIDE , NULL);
293 		valid_tests += try_config(data, fb_flags | FB_COMPRESSED | FB_SMALL_AUX_STRIDE , NULL);
294 		valid_tests += try_config(data, fb_flags | FB_COMPRESSED | FB_ZERO_AUX_STRIDE , NULL);
295 	}
296 
297 	return valid_tests;
298 }
299 
__test_output(data_t * data)300 static int __test_output(data_t *data)
301 {
302 	igt_display_t *display = &data->display;
303 	int i, valid_tests = 0;
304 
305 	data->output = igt_get_single_output_for_pipe(display, data->pipe);
306 	igt_require(data->output);
307 
308 	igt_output_set_pipe(data->output, data->pipe);
309 
310 	for (i = 0; i < ARRAY_SIZE(ccs_modifiers); i++) {
311 		data->ccs_modifier = ccs_modifiers[i];
312 		valid_tests += test_ccs(data);
313 	}
314 
315 	igt_output_set_pipe(data->output, PIPE_NONE);
316 	igt_display_commit2(display, display->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
317 
318 	return valid_tests;
319 }
320 
test_output(data_t * data)321 static void test_output(data_t *data)
322 {
323 	int valid_tests = __test_output(data);
324 	igt_require_f(valid_tests > 0, "CCS not supported, skipping\n");
325 }
326 
327 static data_t data;
328 
329 igt_main
330 {
331 	enum pipe pipe;
332 
333 	igt_fixture {
334 		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
335 
336 		igt_require(intel_gen(intel_get_drm_devid(data.drm_fd)) >= 9);
337 		kmstest_set_vt_graphics_mode();
338 		igt_require_pipe_crc(data.drm_fd);
339 
340 		igt_display_require(&data.display, data.drm_fd);
341 	}
342 
for_each_pipe_static(pipe)343 	for_each_pipe_static(pipe) {
344 		const char *pipe_name = kmstest_pipe_name(pipe);
345 
346 		data.pipe = pipe;
347 
348 		data.flags = TEST_BAD_PIXEL_FORMAT;
349 		igt_subtest_f("pipe-%s-bad-pixel-format", pipe_name)
350 			test_output(&data);
351 
352 		data.flags = TEST_BAD_ROTATION_90;
353 		igt_subtest_f("pipe-%s-bad-rotation-90", pipe_name)
354 			test_output(&data);
355 
356 		data.flags = TEST_CRC;
357 		igt_subtest_f("pipe-%s-crc-primary-basic", pipe_name)
358 			test_output(&data);
359 
360 		data.flags = TEST_CRC | TEST_ROTATE_180;
361 		igt_subtest_f("pipe-%s-crc-primary-rotation-180", pipe_name)
362 			test_output(&data);
363 
364 		data.flags = TEST_CRC;
365 		igt_subtest_f("pipe-%s-crc-sprite-planes-basic", pipe_name) {
366 			int valid_tests = 0;
367 
368 			igt_display_require_output_on_pipe(&data.display, data.pipe);
369 
370 			for_each_plane_on_pipe(&data.display, data.pipe, data.plane) {
371 				if (data.plane->type == DRM_PLANE_TYPE_PRIMARY)
372 					continue;
373 				valid_tests += __test_output(&data);
374 			}
375 
376 			igt_require_f(valid_tests > 0,
377 				      "CCS not supported, skipping\n");
378 		}
379 
380 		data.plane = NULL;
381 
382 		data.flags = TEST_NO_AUX_BUFFER;
383 		igt_subtest_f("pipe-%s-missing-ccs-buffer", pipe_name)
384 			test_output(&data);
385 
386 		data.flags = TEST_BAD_CCS_HANDLE;
387 		igt_subtest_f("pipe-%s-ccs-on-another-bo", pipe_name)
388 			test_output(&data);
389 
390 		data.flags = TEST_BAD_AUX_STRIDE;
391 		igt_subtest_f("pipe-%s-bad-aux-stride", pipe_name)
392 			test_output(&data);
393 	}
394 
395 	igt_fixture
396 		igt_display_fini(&data.display);
397 }
398