1 // SPDX-License-Identifier: GPL-2.0
3 * Test cases for the drm_framebuffer functions
6 #include <linux/kernel.h>
8 #include <drm/drm_device.h>
9 #include <drm/drm_mode.h>
10 #include <drm/drm_fourcc.h>
11 #include <drm/drm_print.h>
13 #include "../drm_crtc_internal.h"
15 #include "test-drm_modeset_common.h"
18 #define MAX_WIDTH 4096
20 #define MAX_HEIGHT 4096
22 struct drm_framebuffer_test {
24 struct drm_mode_fb_cmd2 cmd;
28 static struct drm_framebuffer_test createbuffer_tests[] = {
29 { .buffer_created = 1, .name = "ABGR8888 normal sizes",
30 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888,
31 .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
34 { .buffer_created = 1, .name = "ABGR8888 max sizes",
35 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
36 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
39 { .buffer_created = 1, .name = "ABGR8888 pitch greater than min required",
40 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
41 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH + 1, 0, 0 },
44 { .buffer_created = 0, .name = "ABGR8888 pitch less than min required",
45 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
46 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH - 1, 0, 0 },
49 { .buffer_created = 0, .name = "ABGR8888 Invalid width",
50 .cmd = { .width = MAX_WIDTH + 1, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
51 .handles = { 1, 0, 0 }, .pitches = { 4 * (MAX_WIDTH + 1), 0, 0 },
54 { .buffer_created = 0, .name = "ABGR8888 Invalid buffer handle",
55 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
56 .handles = { 0, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
59 { .buffer_created = 0, .name = "No pixel format",
60 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = 0,
61 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
64 { .buffer_created = 0, .name = "ABGR8888 Width 0",
65 .cmd = { .width = 0, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
66 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
69 { .buffer_created = 0, .name = "ABGR8888 Height 0",
70 .cmd = { .width = MAX_WIDTH, .height = 0, .pixel_format = DRM_FORMAT_ABGR8888,
71 .handles = { 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
74 { .buffer_created = 0, .name = "ABGR8888 Out of bound height * pitch combination",
75 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
76 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX - 1, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
79 { .buffer_created = 1, .name = "ABGR8888 Large buffer offset",
80 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
81 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
84 { .buffer_created = 1, .name = "ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers",
85 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
86 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
87 .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
90 { .buffer_created = 1, .name = "ABGR8888 Valid buffer modifier",
91 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
92 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 }, .pitches = { 4 * MAX_WIDTH, 0, 0 },
93 .flags = DRM_MODE_FB_MODIFIERS, .modifier = { AFBC_FORMAT_MOD_YTR, 0, 0 },
96 { .buffer_created = 0, .name = "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)",
97 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
98 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
99 .pitches = { 4 * MAX_WIDTH, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
100 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
103 { .buffer_created = 1, .name = "ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS",
104 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
105 .handles = { 1, 0, 0 }, .offsets = { UINT_MAX / 2, 0, 0 },
106 .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
109 { .buffer_created = 0, .name = "ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS",
110 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_ABGR8888,
111 .handles = { 1, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
112 .pitches = { 4 * MAX_WIDTH, 4 * MAX_WIDTH, 0 },
115 { .buffer_created = 1, .name = "NV12 Normal sizes",
116 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
117 .handles = { 1, 1, 0 }, .pitches = { 600, 600, 0 },
120 { .buffer_created = 1, .name = "NV12 Max sizes",
121 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
122 .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
125 { .buffer_created = 0, .name = "NV12 Invalid pitch",
126 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
127 .handles = { 1, 1, 0 }, .pitches = { MAX_WIDTH, MAX_WIDTH - 1, 0 },
130 { .buffer_created = 0, .name = "NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag",
131 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
132 .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
133 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
136 { .buffer_created = 0, .name = "NV12 different modifier per-plane",
137 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
138 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
139 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0, 0 },
140 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
143 { .buffer_created = 1, .name = "NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE",
144 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
145 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
146 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
147 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
150 { .buffer_created = 0, .name = "NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS",
151 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
152 .handles = { 1, 1, 0 }, .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
153 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, 0 },
154 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
157 { .buffer_created = 0, .name = "NV12 Modifier for inexistent plane",
158 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
159 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
160 .modifier = { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE,
161 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE },
162 .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
165 { .buffer_created = 0, .name = "NV12 Handle for inexistent plane",
166 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_NV12,
167 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS, .pitches = { MAX_WIDTH, MAX_WIDTH, 0 },
170 { .buffer_created = 1, .name = "NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS",
171 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_NV12,
172 .handles = { 1, 1, 1 }, .pitches = { 600, 600, 600 },
175 { .buffer_created = 1, .name = "YVU420 Normal sizes",
176 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
177 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
178 .pitches = { 600, 300, 300 },
181 { .buffer_created = 1, .name = "YVU420 DRM_MODE_FB_MODIFIERS set without modifier",
182 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_YVU420,
183 .handles = { 1, 1, 1 }, .pitches = { 600, 300, 300 },
186 { .buffer_created = 1, .name = "YVU420 Max sizes",
187 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
188 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2),
189 DIV_ROUND_UP(MAX_WIDTH, 2) },
192 { .buffer_created = 0, .name = "YVU420 Invalid pitch",
193 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
194 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) - 1,
195 DIV_ROUND_UP(MAX_WIDTH, 2) },
198 { .buffer_created = 1, .name = "YVU420 Different pitches",
199 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
200 .handles = { 1, 1, 1 }, .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1,
201 DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
204 { .buffer_created = 1, .name = "YVU420 Different buffer offsets/pitches",
205 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
206 .handles = { 1, 1, 1 }, .offsets = { MAX_WIDTH, MAX_WIDTH + MAX_WIDTH * MAX_HEIGHT,
207 MAX_WIDTH + 2 * MAX_WIDTH * MAX_HEIGHT },
208 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2) + 1, DIV_ROUND_UP(MAX_WIDTH, 2) + 7 },
211 { .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS",
212 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
213 .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
214 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
217 { .buffer_created = 0, .name = "YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS",
218 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
219 .handles = { 1, 1, 1 }, .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
220 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
223 { .buffer_created = 0, .name = "YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS",
224 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
225 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
226 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
227 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
230 { .buffer_created = 1, .name = "YVU420 Valid modifier",
231 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
232 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
233 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE },
234 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
237 { .buffer_created = 0, .name = "YVU420 Different modifiers per plane",
238 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
239 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
240 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR,
241 AFBC_FORMAT_MOD_SPARSE },
242 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
245 { .buffer_created = 0, .name = "YVU420 Modifier for inexistent plane",
246 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_YVU420,
247 .handles = { 1, 1, 1 }, .flags = DRM_MODE_FB_MODIFIERS,
248 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE,
249 AFBC_FORMAT_MOD_SPARSE },
250 .pitches = { MAX_WIDTH, DIV_ROUND_UP(MAX_WIDTH, 2), DIV_ROUND_UP(MAX_WIDTH, 2) },
253 { .buffer_created = 1, .name = "X0L2 Normal sizes",
254 .cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_X0L2,
255 .handles = { 1, 0, 0 }, .pitches = { 1200, 0, 0 }
258 { .buffer_created = 1, .name = "X0L2 Max sizes",
259 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
260 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH, 0, 0 }
263 { .buffer_created = 0, .name = "X0L2 Invalid pitch",
264 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
265 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH - 1, 0, 0 }
268 { .buffer_created = 1, .name = "X0L2 Pitch greater than minimum required",
269 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
270 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
273 { .buffer_created = 0, .name = "X0L2 Handle for inexistent plane",
274 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
275 .handles = { 1, 1, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
276 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
279 { .buffer_created = 1, .name = "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set",
280 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
281 .handles = { 1, 0, 0 }, .offsets = { 0, 0, 3 },
282 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 }
285 { .buffer_created = 0, .name = "X0L2 Modifier without DRM_MODE_FB_MODIFIERS set",
286 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
287 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
288 .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 },
291 { .buffer_created = 1, .name = "X0L2 Valid modifier",
292 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT, .pixel_format = DRM_FORMAT_X0L2,
293 .handles = { 1, 0, 0 }, .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
294 .modifier = { AFBC_FORMAT_MOD_SPARSE, 0, 0 }, .flags = DRM_MODE_FB_MODIFIERS,
297 { .buffer_created = 0, .name = "X0L2 Modifier for inexistent plane",
298 .cmd = { .width = MAX_WIDTH, .height = MAX_HEIGHT,
299 .pixel_format = DRM_FORMAT_X0L2, .handles = { 1, 0, 0 },
300 .pitches = { 2 * MAX_WIDTH + 1, 0, 0 },
301 .modifier = { AFBC_FORMAT_MOD_SPARSE, AFBC_FORMAT_MOD_SPARSE, 0 },
302 .flags = DRM_MODE_FB_MODIFIERS,
307 static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
308 struct drm_file *file_priv,
309 const struct drm_mode_fb_cmd2 *mode_cmd)
311 int *buffer_created = dev->dev_private;
313 return ERR_PTR(-EINVAL);
316 static struct drm_mode_config_funcs mock_config_funcs = {
317 .fb_create = fb_create_mock,
320 static struct drm_device mock_drm_device = {
322 .min_width = MIN_WIDTH,
323 .max_width = MAX_WIDTH,
324 .min_height = MIN_HEIGHT,
325 .max_height = MAX_HEIGHT,
326 .funcs = &mock_config_funcs,
330 static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r)
332 int buffer_created = 0;
334 mock_drm_device.dev_private = &buffer_created;
335 drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
336 return buffer_created;
339 int igt_check_drm_framebuffer_create(void *ignored)
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);