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 #include "drmtest.h"
27 #include <errno.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <time.h>
32
33 IGT_TEST_DESCRIPTION("Test atomic mode setting with a plane by switching between high and low resolutions");
34
35 #define MAX_CRCS 1
36 #define SIZE 256
37 #define LOOP_FOREVER -1
38
39 typedef struct {
40 int drm_fd;
41 igt_display_t display;
42 struct igt_fb fb_primary;
43 struct igt_fb fb_plane;
44 } data_t;
45
46 static drmModeModeInfo
get_lowres_mode(int drmfd,igt_output_t * output,drmModeModeInfo * mode_default)47 get_lowres_mode(int drmfd, igt_output_t *output, drmModeModeInfo *mode_default)
48 {
49 drmModeModeInfo mode;
50 bool found = false;
51 int limit = mode_default->vdisplay - SIZE;
52 int j;
53
54 for (j = 0; j < output->config.connector->count_modes; j++) {
55 mode = output->config.connector->modes[j];
56 if (mode.vdisplay < limit) {
57 found = true;
58 break;
59 }
60 }
61
62 if (!found)
63 return *igt_std_1024_mode_get();
64
65 return mode;
66 }
67
68 static void
check_mode(drmModeModeInfo * mode1,drmModeModeInfo * mode2)69 check_mode(drmModeModeInfo *mode1, drmModeModeInfo *mode2)
70 {
71 igt_assert_eq(mode1->hdisplay, mode2->hdisplay);
72 igt_assert_eq(mode1->vdisplay, mode2->vdisplay);
73 igt_assert_eq(mode1->vrefresh, mode2->vrefresh);
74 }
75
76 /*
77 * Return false if test on this plane should be skipped
78 */
79 static bool
setup_plane(data_t * data,igt_plane_t * plane,drmModeModeInfo * mode,uint64_t modifier)80 setup_plane(data_t *data, igt_plane_t *plane, drmModeModeInfo *mode,
81 uint64_t modifier)
82 {
83 uint64_t plane_modifier;
84 uint32_t plane_format;
85 int size, x, y;
86
87 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
88 return false;
89
90 if (plane->type == DRM_PLANE_TYPE_CURSOR)
91 size = 64;
92 else
93 size = SIZE;
94
95 x = 0;
96 y = mode->vdisplay - size;
97
98 if (plane->type == DRM_PLANE_TYPE_CURSOR) {
99 plane_format = DRM_FORMAT_ARGB8888;
100 plane_modifier = LOCAL_DRM_FORMAT_MOD_NONE;
101 } else {
102 plane_format = DRM_FORMAT_XRGB8888;
103 plane_modifier = modifier;
104 }
105
106 if (!igt_plane_has_format_mod(plane, plane_format, plane_modifier))
107 return false;
108
109 igt_create_color_fb(data->drm_fd, size, size, plane_format,
110 plane_modifier, 1.0, 1.0, 0.0, &data->fb_plane);
111 igt_plane_set_position(plane, x, y);
112 igt_plane_set_fb(plane, &data->fb_plane);
113
114 return true;
115 }
116
117 static igt_plane_t *
primary_plane_get(igt_display_t * display,enum pipe pipe)118 primary_plane_get(igt_display_t *display, enum pipe pipe)
119 {
120 unsigned plane_primary_id = display->pipes[pipe].plane_primary;
121 return &display->pipes[pipe].planes[plane_primary_id];
122 }
123
124 static unsigned
test_planes_on_pipe_with_output(data_t * data,enum pipe pipe,igt_output_t * output,uint64_t modifier)125 test_planes_on_pipe_with_output(data_t *data, enum pipe pipe,
126 igt_output_t *output, uint64_t modifier)
127 {
128 drmModeModeInfo *mode, mode_lowres;
129 igt_pipe_crc_t *pipe_crc;
130 unsigned tested = 0;
131 igt_plane_t *plane;
132
133 igt_info("Testing connector %s using pipe %s\n",
134 igt_output_name(output), kmstest_pipe_name(pipe));
135
136 igt_output_set_pipe(output, pipe);
137 mode = igt_output_get_mode(output);
138 mode_lowres = get_lowres_mode(data->drm_fd, output, mode);
139
140 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
141 DRM_FORMAT_XRGB8888, modifier, 0.0, 0.0, 1.0,
142 &data->fb_primary);
143 igt_plane_set_fb(primary_plane_get(&data->display, pipe),
144 &data->fb_primary);
145
146 pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe,
147 INTEL_PIPE_CRC_SOURCE_AUTO);
148
149 /* yellow sprite plane in lower left corner */
150 for_each_plane_on_pipe(&data->display, pipe, plane) {
151 igt_crc_t crc_hires1, crc_hires2;
152 int r;
153
154 if (!setup_plane(data, plane, mode, modifier))
155 continue;
156
157 r = igt_display_try_commit2(&data->display, COMMIT_ATOMIC);
158 if (r) {
159 igt_debug("Commit failed %i", r);
160 continue;
161 }
162
163 igt_pipe_crc_start(pipe_crc);
164 igt_pipe_crc_get_single(pipe_crc, &crc_hires1);
165
166 igt_assert_plane_visible(data->drm_fd, pipe, plane->index,
167 true);
168
169 /* switch to lower resolution */
170 igt_output_override_mode(output, &mode_lowres);
171 igt_output_set_pipe(output, pipe);
172 check_mode(&mode_lowres, igt_output_get_mode(output));
173
174 igt_display_commit2(&data->display, COMMIT_ATOMIC);
175
176 igt_assert_plane_visible(data->drm_fd, pipe, plane->index,
177 false);
178
179 /* switch back to higher resolution */
180 igt_output_override_mode(output, NULL);
181 igt_output_set_pipe(output, pipe);
182 check_mode(mode, igt_output_get_mode(output));
183
184 igt_display_commit2(&data->display, COMMIT_ATOMIC);
185
186 igt_pipe_crc_get_current(data->drm_fd, pipe_crc, &crc_hires2);
187
188 igt_assert_plane_visible(data->drm_fd, pipe, plane->index,
189 true);
190
191 igt_assert_crc_equal(&crc_hires1, &crc_hires2);
192
193 igt_pipe_crc_stop(pipe_crc);
194
195 igt_plane_set_fb(plane, NULL);
196 igt_remove_fb(data->drm_fd, &data->fb_plane);
197 tested++;
198 }
199
200 igt_pipe_crc_free(pipe_crc);
201
202 igt_plane_set_fb(primary_plane_get(&data->display, pipe), NULL);
203 igt_remove_fb(data->drm_fd, &data->fb_primary);
204 igt_output_set_pipe(output, PIPE_NONE);
205
206 return tested;
207 }
208
209 static void
test_planes_on_pipe(data_t * data,enum pipe pipe,uint64_t modifier)210 test_planes_on_pipe(data_t *data, enum pipe pipe, uint64_t modifier)
211 {
212 igt_output_t *output;
213 unsigned tested = 0;
214
215 igt_skip_on(pipe >= data->display.n_pipes);
216 igt_display_require_output_on_pipe(&data->display, pipe);
217 igt_skip_on(!igt_display_has_format_mod(&data->display,
218 DRM_FORMAT_XRGB8888, modifier));
219
220 for_each_valid_output_on_pipe(&data->display, pipe, output)
221 tested += test_planes_on_pipe_with_output(data, pipe, output,
222 modifier);
223
224 igt_assert(tested > 0);
225 }
226
227 igt_main
228 {
229 data_t data = {};
230 enum pipe pipe;
231
232 igt_skip_on_simulation();
233
234 igt_fixture {
235 data.drm_fd = drm_open_driver_master(DRIVER_ANY);
236
237 kmstest_set_vt_graphics_mode();
238
239 igt_require_pipe_crc(data.drm_fd);
240 igt_display_require(&data.display, data.drm_fd);
241 igt_require(data.display.is_atomic);
242 }
243
for_each_pipe_static(pipe)244 for_each_pipe_static(pipe) {
245 igt_subtest_f("pipe-%s-tiling-none", kmstest_pipe_name(pipe))
246 test_planes_on_pipe(&data, pipe,
247 LOCAL_DRM_FORMAT_MOD_NONE);
248
249 igt_subtest_f("pipe-%s-tiling-x", kmstest_pipe_name(pipe))
250 test_planes_on_pipe(&data, pipe,
251 LOCAL_I915_FORMAT_MOD_X_TILED);
252
253 igt_subtest_f("pipe-%s-tiling-y", kmstest_pipe_name(pipe))
254 test_planes_on_pipe(&data, pipe,
255 LOCAL_I915_FORMAT_MOD_Y_TILED);
256
257 igt_subtest_f("pipe-%s-tiling-yf", kmstest_pipe_name(pipe))
258 test_planes_on_pipe(&data, pipe,
259 LOCAL_I915_FORMAT_MOD_Yf_TILED);
260 }
261
262 igt_fixture {
263 igt_display_fini(&data.display);
264 }
265 }
266