blob: 283acf8c8a7ee7ba689121f42e150ffa2f582237 [file] [log] [blame]
Mika Kahola019fa3c2017-04-11 11:16:02 +03001/*
2 * Copyright © 2017 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#include "drmtest.h"
27
28IGT_TEST_DESCRIPTION("Test atomic mode setting concurrently with multiple planes and screen resolution");
29
30#define SIZE_PLANE 256
31#define SIZE_CURSOR 128
32#define LOOP_FOREVER -1
33
34typedef struct {
35 int drm_fd;
36 igt_display_t display;
37 igt_plane_t **plane;
38 struct igt_fb *fb;
39} data_t;
40
41/* Command line parameters. */
42struct {
43 int iterations;
44 bool user_seed;
45 int seed;
46 bool run;
47} opt = {
48 .iterations = 1,
49 .user_seed = false,
50 .seed = 1,
51 .run = true,
52};
53
54/*
55 * Common code across all tests, acting on data_t
56 */
57static void test_init(data_t *data, enum pipe pipe, int n_planes,
58 igt_output_t *output)
59{
60 drmModeModeInfo *mode;
61 igt_plane_t *primary;
62 int ret;
63
64 data->plane = calloc(n_planes, sizeof(data->plane));
65 igt_assert_f(data->plane != NULL, "Failed to allocate memory for planes\n");
66
67 data->fb = calloc(n_planes, sizeof(struct igt_fb));
68 igt_assert_f(data->fb != NULL, "Failed to allocate memory for FBs\n");
69
70 igt_output_set_pipe(output, pipe);
71
72 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
73 data->plane[primary->index] = primary;
74
75 mode = igt_output_get_mode(output);
76
77 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
78 DRM_FORMAT_XRGB8888,
79 LOCAL_I915_FORMAT_MOD_X_TILED,
80 0.0f, 0.0f, 1.0f,
81 &data->fb[primary->index]);
82
83 igt_plane_set_fb(data->plane[primary->index], &data->fb[primary->index]);
84
85 ret = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
86 igt_skip_on(ret != 0);
87}
88
89static void test_fini(data_t *data, enum pipe pipe, int n_planes,
90 igt_output_t *output)
91{
92 int i;
93
Mika Kahola019fa3c2017-04-11 11:16:02 +030094 for (i = 0; i < n_planes; i++) {
95 igt_plane_t *plane = data->plane[i];
96
97 if (!plane)
98 continue;
99
100 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
101 continue;
102
103 igt_plane_set_fb(plane, NULL);
104
105 data->plane[i] = NULL;
106 }
107
108 /* reset the constraint on the pipe */
109 igt_output_set_pipe(output, PIPE_ANY);
110
111 free(data->plane);
112 data->plane = NULL;
113
114 free(data->fb);
115 data->fb = NULL;
116}
117
118static void
119create_fb_for_mode_position(data_t *data, drmModeModeInfo *mode,
120 int *rect_x, int *rect_y,
121 int *rect_w, int *rect_h,
122 uint64_t tiling, int max_planes,
123 igt_output_t *output)
124{
125 unsigned int fb_id;
126 cairo_t *cr;
127 igt_plane_t *primary;
128
129 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
130
131 fb_id = igt_create_fb(data->drm_fd,
132 mode->hdisplay, mode->vdisplay,
133 DRM_FORMAT_XRGB8888,
134 tiling,
135 &data->fb[primary->index]);
136 igt_assert(fb_id);
137
138 cr = igt_get_cairo_ctx(data->drm_fd, &data->fb[primary->index]);
139 igt_paint_color(cr, rect_x[0], rect_y[0],
140 mode->hdisplay, mode->vdisplay,
141 0.0f, 0.0f, 1.0f);
142
143 for (int i = 0; i < max_planes; i++) {
144 if (data->plane[i]->type == DRM_PLANE_TYPE_PRIMARY)
145 continue;
146
147 igt_paint_color(cr, rect_x[i], rect_y[i],
148 rect_w[i], rect_h[i], 0.0, 0.0, 0.0);
149 }
150
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100151 igt_put_cairo_ctx(data->drm_fd, &data->fb[primary->index], cr);
Mika Kahola019fa3c2017-04-11 11:16:02 +0300152}
153
154static void
155prepare_planes(data_t *data, enum pipe pipe, int max_planes,
156 igt_output_t *output)
157{
158 drmModeModeInfo *mode;
159 igt_pipe_t *p;
160 igt_plane_t *primary;
161 int *x;
162 int *y;
163 int *size;
164 int i;
165
166 igt_output_set_pipe(output, pipe);
167
168 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
169 p = primary->pipe;
170
171 x = malloc(p->n_planes * sizeof(*x));
172 igt_assert_f(x, "Failed to allocate %ld bytes for variable x\n", (long int) (p->n_planes * sizeof(*x)));
173
174 y = malloc(p->n_planes * sizeof(*y));
175 igt_assert_f(y, "Failed to allocate %ld bytes for variable y\n", (long int) (p->n_planes * sizeof(*y)));
176
177 size = malloc(p->n_planes * sizeof(*size));
178 igt_assert_f(size, "Failed to allocate %ld bytes for variable size\n", (long int) (p->n_planes * sizeof(*size)));
179
180 mode = igt_output_get_mode(output);
181
182 /* planes with random positions */
183 x[primary->index] = 0;
184 y[primary->index] = 0;
185 for (i = 0; i < max_planes; i++) {
186 igt_plane_t *plane = igt_output_get_plane(output, i);
187
188 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
189 continue;
190 else if (plane->type == DRM_PLANE_TYPE_CURSOR)
191 size[i] = SIZE_CURSOR;
192 else
193 size[i] = SIZE_PLANE;
194
195 x[i] = rand() % (mode->hdisplay - size[i]);
196 y[i] = rand() % (mode->vdisplay - size[i]);
197
198 data->plane[i] = plane;
199
200 igt_create_color_fb(data->drm_fd,
201 size[i], size[i],
202 data->plane[i]->type == DRM_PLANE_TYPE_CURSOR ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_XRGB8888,
203 data->plane[i]->type == DRM_PLANE_TYPE_CURSOR ? LOCAL_DRM_FORMAT_MOD_NONE : LOCAL_I915_FORMAT_MOD_X_TILED,
204 0.0f, 0.0f, 1.0f,
205 &data->fb[i]);
206
207 igt_plane_set_position(data->plane[i], x[i], y[i]);
208 igt_plane_set_fb(data->plane[i], &data->fb[i]);
209 }
210
211 /* primary plane */
212 data->plane[primary->index] = primary;
213 create_fb_for_mode_position(data, mode, x, y, size, size,
214 LOCAL_I915_FORMAT_MOD_X_TILED,
215 max_planes, output);
216
217 igt_plane_set_fb(data->plane[primary->index], &data->fb[primary->index]);
218}
219
220static void
221test_plane_position_with_output(data_t *data, enum pipe pipe, igt_output_t *output)
222{
223 int i;
224 int iterations = opt.iterations < 1 ? 1 : opt.iterations;
225 bool loop_forever = opt.iterations == LOOP_FOREVER ? true : false;
226 int max_planes = data->display.pipes[pipe].n_planes;
227
Maarten Lankhorst65c7f9d2017-10-19 13:05:26 +0200228 igt_pipe_refresh(&data->display, pipe, true);
229
Mika Kahola019fa3c2017-04-11 11:16:02 +0300230 i = 0;
231 while (i < iterations || loop_forever) {
232 prepare_planes(data, pipe, max_planes, output);
233 igt_display_commit2(&data->display, COMMIT_ATOMIC);
234
235 i++;
236 }
237}
238
Maarten Lankhorst65c7f9d2017-10-19 13:05:26 +0200239static drmModeModeInfo std_1024_mode = {
240 .clock = 65000,
241 .hdisplay = 1024,
242 .hsync_start = 1048,
243 .hsync_end = 1184,
244 .htotal = 1344,
245 .hskew = 0,
246 .vdisplay = 768,
247 .vsync_start = 771,
248 .vsync_end = 777,
249 .vtotal = 806,
250 .vscan = 0,
251 .vrefresh = 60,
252 .flags = 0xA,
253 .type = 0x40,
254 .name = "Custom 1024x768",
255};
256
Mika Kahola019fa3c2017-04-11 11:16:02 +0300257static drmModeModeInfo *
258get_lowres_mode(data_t *data, drmModeModeInfo *mode_default,
259 igt_output_t *output)
260{
Mika Kahola019fa3c2017-04-11 11:16:02 +0300261 drmModeModeInfo *mode = &std_1024_mode;
262 drmModeConnector *connector = output->config.connector;
263 int limit = mode_default->vdisplay - SIZE_PLANE;
264 bool found;
265
266 if (!connector)
267 return mode;
268
269 found = false;
270 for (int i = 0; i < connector->count_modes; i++) {
271 mode = &connector->modes[i];
272
273 if (mode->vdisplay < limit) {
274 found = true;
275 break;
276 }
277 }
278
279 if (!found)
280 mode = &std_1024_mode;
281
282 return mode;
283}
284
285static void
286test_resolution_with_output(data_t *data, enum pipe pipe, igt_output_t *output)
287{
288 drmModeModeInfo *mode_hi, *mode_lo;
289 int iterations = opt.iterations < 1 ? 1 : opt.iterations;
290 bool loop_forever = opt.iterations == LOOP_FOREVER ? true : false;
291 int i;
292
293 i = 0;
294 while (i < iterations || loop_forever) {
Mika Kahola019fa3c2017-04-11 11:16:02 +0300295 mode_hi = igt_output_get_mode(output);
296 mode_lo = get_lowres_mode(data, mode_hi, output);
297
298 /* switch to lower resolution */
299 igt_output_override_mode(output, mode_lo);
Mika Kahola019fa3c2017-04-11 11:16:02 +0300300 igt_display_commit2(&data->display, COMMIT_ATOMIC);
301
302 /* switch back to higher resolution */
303 igt_output_override_mode(output, NULL);
Mika Kahola019fa3c2017-04-11 11:16:02 +0300304 igt_display_commit2(&data->display, COMMIT_ATOMIC);
305
306 i++;
307 }
308}
309
310static void
311run_test(data_t *data, enum pipe pipe, igt_output_t *output)
312{
313 int connected_outs;
314 int n_planes = data->display.pipes[pipe].n_planes;
315
316 if (!opt.user_seed)
317 opt.seed = time(NULL);
318
319 connected_outs = 0;
320 for_each_valid_output_on_pipe(&data->display, pipe, output) {
321 igt_info("Testing resolution with connector %s using pipe %s with seed %d\n",
322 igt_output_name(output), kmstest_pipe_name(pipe), opt.seed);
323
324 test_init(data, pipe, n_planes, output);
325
326 igt_fork(child, 1) {
327 test_plane_position_with_output(data, pipe, output);
328 }
329
330 test_resolution_with_output(data, pipe, output);
331
332 igt_waitchildren();
333
334 test_fini(data, pipe, n_planes, output);
335
336 connected_outs++;
337 }
338
339 igt_skip_on(connected_outs == 0);
340}
341
342static void
343run_tests_for_pipe(data_t *data, enum pipe pipe)
344{
345 igt_output_t *output;
346
347 igt_fixture {
348 int valid_tests = 0;
349
Mika Kahola019fa3c2017-04-11 11:16:02 +0300350 igt_skip_on(pipe >= data->display.n_pipes);
Leo (Sunpeng) Li597cae92017-06-09 17:08:53 -0400351 igt_require(data->display.pipes[pipe].n_planes > 0);
Mika Kahola019fa3c2017-04-11 11:16:02 +0300352
353 for_each_valid_output_on_pipe(&data->display, pipe, output)
354 valid_tests++;
355
356 igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
357 }
358
359 igt_subtest_f("pipe-%s", kmstest_pipe_name(pipe))
360 for_each_valid_output_on_pipe(&data->display, pipe, output)
361 run_test(data, pipe, output);
362}
363
364static int opt_handler(int option, int option_index, void *input)
365{
366 switch (option) {
367 case 'i':
368 opt.iterations = strtol(optarg, NULL, 0);
369
370 if (opt.iterations < LOOP_FOREVER || opt.iterations == 0) {
371 igt_info("incorrect number of iterations\n");
372 igt_assert(false);
373 }
374
375 break;
376 case 's':
377 opt.user_seed = true;
378 opt.seed = strtol(optarg, NULL, 0);
379 break;
380 default:
381 igt_assert(false);
382 }
383
384 return 0;
385}
386
387const char *help_str =
388 " --iterations Number of iterations for test coverage. -1 loop forever, default 1 iteration\n"
389 " --seed Seed for random number generator\n";
390
391static data_t data;
392
393int main(int argc, char *argv[])
394{
395 struct option long_options[] = {
396 { "iterations", required_argument, NULL, 'i'},
397 { "seed", required_argument, NULL, 's'},
398 { 0, 0, 0, 0 }
399 };
Daniel Vetter229d7d22017-08-14 11:32:05 +0200400 enum pipe pipe;
Mika Kahola019fa3c2017-04-11 11:16:02 +0300401
402 igt_subtest_init_parse_opts(&argc, argv, "", long_options, help_str,
403 opt_handler, NULL);
404
405 igt_skip_on_simulation();
406
407 igt_fixture {
408 data.drm_fd = drm_open_driver_master(DRIVER_ANY);
409 kmstest_set_vt_graphics_mode();
410 igt_display_init(&data.display, data.drm_fd);
411 igt_require(data.display.n_pipes > 0);
412 igt_require(data.display.is_atomic);
413 }
414
Daniel Vetter229d7d22017-08-14 11:32:05 +0200415 for_each_pipe_static(pipe) {
Mika Kahola019fa3c2017-04-11 11:16:02 +0300416 igt_subtest_group
417 run_tests_for_pipe(&data, pipe);
418 }
419
420 igt_fixture {
421 igt_display_fini(&data.display);
422 close(data.drm_fd);
423 }
424
425 igt_exit();
426}