1
2
3
4
5
6#include <linux/kernel.h>
7
8#include <drm/drm_device.h>
9#include <drm/drm_mode.h>
10#include <drm/drm_fourcc.h>
11
12#include "../drm_crtc_internal.h"
13
14#include "test-drm_modeset_common.h"
15
16#define MIN_WIDTH 4
17#define MAX_WIDTH 4096
18#define MIN_HEIGHT 4
19#define MAX_HEIGHT 4096
20
21struct drm_framebuffer_test {
22 int buffer_created;
23 struct drm_mode_fb_cmd2 cmd;
24 const char *name;
25};
26
27static struct drm_framebuffer_test createbuffer_tests[] = {
28{ .buffer_created = 1, .name = "ABGR8888 normal sizes",
29 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888,
30 .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
31 }
32},
33{ .buffer_created = 1, .name = "ABGR8888 max sizes",
34 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
35 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
36 }
37},
38{ .buffer_created = 1, .name = "ABGR8888 pitch greater than min required",
39 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
40 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH + 1, 0, 0 },
41 }
42},
43{ .buffer_created = 0, .name = "ABGR8888 pitch less than min required",
44 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
45 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH - 1, 0, 0 },
46 }
47},
48{ .buffer_created = 0, .name = "ABGR8888 Invalid width",
49 .cmd = { .width = MAX_WIDTH + 1, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
50 .handles = { 1, 0, 0 }, .pitches = { 4 * (MAX_WIDTH + 1), 0, 0 },
51 }
52},
53{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer handle",
54 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
55 .handles = { 0, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
56 }
57},
58{ .buffer_created = 0, .name = "No pixel format",
59 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = 0,
60 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
61 }
62},
63{ .buffer_created = 0, .name = "ABGR8888 Width 0",
64 .cmd = { .width = 0, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
65 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
66 }
67},
68{ .buffer_created = 0, .name = "ABGR8888 Height 0",
69 .cmd = { .width = MAX_WIDTH, .height = 0, .pixel_format = DRM_FORMAT_ABGR8888,
70 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
71 }
72},
73{ .buffer_created = 0, .name = "ABGR8888 Out of bound height * pitch combination",
74 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
75 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX - 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
76 }
77},
78{ .buffer_created = 1, .name = "ABGR8888 Large buffer offset",
79 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
80 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
81 }
82},
83{ .buffer_created = 1, .name = "ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers",
84 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
85 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
86 .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
87 }
88},
89{ .buffer_created = 1, .name = "ABGR8888 Valid buffer modifier",
90 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
91 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
92 .flags = DRM_MODE_FB_MODIFIERS, .modifier = { AFBC_FORMAT_MOD_YTR, 0, 0 },
93 }
94},
95{ .buffer_created = 0, .name = "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)",
96 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
97 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
98 .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
99 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
100 }
101},
102{ .buffer_created = 1, .name = "ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS",
103 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
104 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
105 .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
106 }
107},
108{ .buffer_created = 0, .name = "ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS",
109 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
110 .handles = { 1, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
111 .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
112 }
113},
114{ .buffer_created = 1, .name = "NV12 Normal sizes",
115 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
116 .handles = { 1, 1, 0 }, .pitches = { 600, 600, 0 },
117 }
118},
119{ .buffer_created = 1, .name = "NV12 Max sizes",
120 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
121 .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
122 }
123},
124{ .buffer_created = 0, .name = "NV12 Invalid pitch",
125 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
126 .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH - 1, 0 },
127 }
128},
129{ .buffer_created = 0, .name = "NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag",
130 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
131 .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
132 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
133 }
134},
135{ .buffer_created = 0, .name = "NV12 different modifier per-plane",
136 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
137 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
138 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
139 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
140 }
141},
142{ .buffer_created = 1, .name = "NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE",
143 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
144 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
145 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
146 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
147 }
148},
149{ .buffer_created = 0, .name = "NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS",
150 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
151 .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
152 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
153 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
154 }
155},
156{ .buffer_created = 0, .name = "NV12 Modifier for inexistent plane",
157 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
158 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
159 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
160 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE },
161 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
162 }
163},
164{ .buffer_created = 0, .name = "NV12 Handle for inexistent plane",
165 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
166 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
167 }
168},
169{ .buffer_created = 1, .name = "NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS",
170 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
171 .handles = { 1, 1, 1 }, .pitches = { 600, 600, 600 },
172 }
173},
174{ .buffer_created = 1, .name = "YVU420 Normal sizes",
175 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
176 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
177 .pitches = { 600, 300, 300 },
178 }
179},
180{ .buffer_created = 1, .name = "YVU420 DRM_MODE_FB_MODIFIERS set without modifier",
181 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
182 .handles = { 1, 1, 1 }, .pitches = { 600, 300, 300 },
183 }
184},
185{ .buffer_created = 1, .name = "YVU420 Max sizes",
186 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
187 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2),
188 DIV_ROUND_UP(MAX_WIDTH, 2) },
189 }
190},
191{ .buffer_created = 0, .name = "YVU420 Invalid pitch",
192 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
193 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) - 1,
194 DIV_ROUND_UP(MAX_WIDTH, 2) },
195 }
196},
197{ .buffer_created = 1, .name = "YVU420 Different pitches",
198 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
199 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1,
200 DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
201 }
202},
203{ .buffer_created = 1, .name = "YVU420 Different buffer offsets/pitches",
204 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
205 .handles = { 1, 1, 1 }, .offsets = { MAX_WIDTH, MAX_WIDTH + MAX_WIDTH * MAX_HEIGHT,
206 MAX_WIDTH + 2 * MAX_WIDTH * MAX_HEIGHT },
207 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1, DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
208 }
209},
210{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS",
211 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
212 .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
213 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
214 }
215},
216{ .buffer_created = 0, .name = "YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS",
217 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
218 .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
219 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
220 }
221},
222{ .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS",
223 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
224 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
225 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
226 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
227 }
228},
229{ .buffer_created = 1, .name = "YVU420 Valid modifier",
230 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
231 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
232 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE },
233 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
234 }
235},
236{ .buffer_created = 0, .name = "YVU420 Different modifiers per plane",
237 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
238 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
239 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR,
240 AFBC_FORMAT_MOD_SPARSE },
241 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
242 }
243},
244{ .buffer_created = 0, .name = "YVU420 Modifier for inexistent plane",
245 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
246 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
247 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE,
248 AFBC_FORMAT_MOD_SPARSE },
249 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
250 }
251},
252{ .buffer_created = 1, .name = "X0L2 Normal sizes",
253 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_X0L2,
254 .handles = { 1, 0, 0 }, .pitches = { 1200, 0, 0 }
255 }
256},
257{ .buffer_created = 1, .name = "X0L2 Max sizes",
258 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
259 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH, 0, 0 }
260 }
261},
262{ .buffer_created = 0, .name = "X0L2 Invalid pitch",
263 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
264 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH - 1, 0, 0 }
265 }
266},
267{ .buffer_created = 1, .name = "X0L2 Pitch greater than minimum required",
268 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
269 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
270 }
271},
272{ .buffer_created = 0, .name = "X0L2 Handle for inexistent plane",
273 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
274 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
275 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
276 }
277},
278{ .buffer_created = 1, .name = "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set",
279 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
280 .handles = { 1, 0, 0 }, .offsets = { 0, 0, 3 },
281 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
282 }
283},
284{ .buffer_created = 0, .name = "X0L2 Modifier without DRM_MODE_FB_MODIFIERS set",
285 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
286 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
287 .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
288 }
289},
290{ .buffer_created = 1, .name = "X0L2 Valid modifier",
291 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
292 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
293 .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
294 }
295},
296{ .buffer_created = 0, .name = "X0L2 Modifier for inexistent plane",
297 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT,
298 .pixel_format = DRM_FORMAT_X0L2, .handles = { 1, 0, 0 },
299 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
300 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
301 .flags = DRM_MODE_FB_MODIFIERS,
302 }
303},
304};
305
306static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
307 struct drm_file *file_priv,
308 const struct drm_mode_fb_cmd2 *mode_cmd)
309{
310 int *buffer_created = dev->dev_private;
311 *buffer_created = 1;
312 return ERR_PTR(-EINVAL);
313}
314
315static struct drm_mode_config_funcs mock_config_funcs = {
316 .fb_create = fb_create_mock,
317};
318
319static struct drm_device mock_drm_device = {
320 .mode_config = {
321 .min_width = MIN_WIDTH,
322 .max_width = MAX_WIDTH,
323 .min_height = MIN_HEIGHT,
324 .max_height = MAX_HEIGHT,
325 .allow_fb_modifiers = true,
326 .funcs = &mock_config_funcs,
327 },
328};
329
330static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r)
331{
332 int buffer_created = 0;
333
334 mock_drm_device.dev_private = &buffer_created;
335 drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
336 return buffer_created;
337}
338
339int igt_check_drm_framebuffer_create(void *ignored)
340{
341 int i = 0;
342
343 for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) {
344 FAIL(createbuffer_tests[i].buffer_created !=
345 execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd),
346 "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name);
347 }
348
349 return 0;
350}
351