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