1 // SPDX-License-Identifier: GPL-2.0
3 * Test cases for the drm_framebuffer functions
7 #include "../drm_crtc_internal.h"
9 #include "test-drm_modeset_common.h"
12 #define MAX_WIDTH 4096
14 #define MAX_HEIGHT 4096
16 struct drm_framebuffer_test
{
18 struct drm_mode_fb_cmd2 cmd
;
22 static struct drm_framebuffer_test createbuffer_tests
[] = {
23 { .buffer_created
= 1, .name
= "ABGR8888 normal sizes",
24 .cmd
= { .width
= 600, .height
= 600, .pixel_format
= DRM_FORMAT_ABGR8888
,
25 .handles
= { 1, 0, 0 }, .pitches
= { 4 * 600, 0, 0 },
28 { .buffer_created
= 1, .name
= "ABGR8888 max sizes",
29 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
30 .handles
= { 1, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
, 0, 0 },
33 { .buffer_created
= 1, .name
= "ABGR8888 pitch greater than min required",
34 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
35 .handles
= { 1, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
+ 1, 0, 0 },
38 { .buffer_created
= 0, .name
= "ABGR8888 pitch less 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 },
43 { .buffer_created
= 0, .name
= "ABGR8888 Invalid width",
44 .cmd
= { .width
= MAX_WIDTH
+ 1, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
45 .handles
= { 1, 0, 0 }, .pitches
= { 4 * (MAX_WIDTH
+ 1), 0, 0 },
48 { .buffer_created
= 0, .name
= "ABGR8888 Invalid buffer handle",
49 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
50 .handles
= { 0, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
, 0, 0 },
53 { .buffer_created
= 0, .name
= "No pixel format",
54 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= 0,
55 .handles
= { 1, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
, 0, 0 },
58 { .buffer_created
= 0, .name
= "ABGR8888 Width 0",
59 .cmd
= { .width
= 0, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
60 .handles
= { 1, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
, 0, 0 },
63 { .buffer_created
= 0, .name
= "ABGR8888 Height 0",
64 .cmd
= { .width
= MAX_WIDTH
, .height
= 0, .pixel_format
= DRM_FORMAT_ABGR8888
,
65 .handles
= { 1, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
, 0, 0 },
68 { .buffer_created
= 0, .name
= "ABGR8888 Out of bound height * pitch combination",
69 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
70 .handles
= { 1, 0, 0 }, .offsets
= { UINT_MAX
- 1, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
, 0, 0 },
73 { .buffer_created
= 1, .name
= "ABGR8888 Large buffer offset",
74 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
75 .handles
= { 1, 0, 0 }, .offsets
= { UINT_MAX
/ 2, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
, 0, 0 },
78 { .buffer_created
= 1, .name
= "ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers",
79 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
80 .handles
= { 1, 0, 0 }, .offsets
= { UINT_MAX
/ 2, 0, 0 },
81 .pitches
= { 4 * MAX_WIDTH
, 0, 0 }, .flags
= DRM_MODE_FB_MODIFIERS
,
84 { .buffer_created
= 1, .name
= "ABGR8888 Valid buffer modifier",
85 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
86 .handles
= { 1, 0, 0 }, .offsets
= { UINT_MAX
/ 2, 0, 0 }, .pitches
= { 4 * MAX_WIDTH
, 0, 0 },
87 .flags
= DRM_MODE_FB_MODIFIERS
, .modifier
= { AFBC_FORMAT_MOD_YTR
, 0, 0 },
90 { .buffer_created
= 0, .name
= "ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)",
91 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
92 .handles
= { 1, 0, 0 }, .offsets
= { UINT_MAX
/ 2, 0, 0 },
93 .pitches
= { 4 * MAX_WIDTH
, 0, 0 }, .flags
= DRM_MODE_FB_MODIFIERS
,
94 .modifier
= { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
, 0, 0 },
97 { .buffer_created
= 1, .name
= "ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS",
98 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
99 .handles
= { 1, 0, 0 }, .offsets
= { UINT_MAX
/ 2, 0, 0 },
100 .pitches
= { 4 * MAX_WIDTH
, 4 * MAX_WIDTH
, 0 },
103 { .buffer_created
= 0, .name
= "ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS",
104 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_ABGR8888
,
105 .handles
= { 1, 0, 0 }, .flags
= DRM_MODE_FB_MODIFIERS
,
106 .pitches
= { 4 * MAX_WIDTH
, 4 * MAX_WIDTH
, 0 },
109 { .buffer_created
= 1, .name
= "NV12 Normal sizes",
110 .cmd
= { .width
= 600, .height
= 600, .pixel_format
= DRM_FORMAT_NV12
,
111 .handles
= { 1, 1, 0 }, .pitches
= { 600, 600, 0 },
114 { .buffer_created
= 1, .name
= "NV12 Max sizes",
115 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_NV12
,
116 .handles
= { 1, 1, 0 }, .pitches
= { MAX_WIDTH
, MAX_WIDTH
, 0 },
119 { .buffer_created
= 0, .name
= "NV12 Invalid pitch",
120 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_NV12
,
121 .handles
= { 1, 1, 0 }, .pitches
= { MAX_WIDTH
, MAX_WIDTH
- 1, 0 },
124 { .buffer_created
= 0, .name
= "NV12 Invalid modifier/misssing DRM_MODE_FB_MODIFIERS flag",
125 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_NV12
,
126 .handles
= { 1, 1, 0 }, .modifier
= { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
, 0, 0 },
127 .pitches
= { MAX_WIDTH
, MAX_WIDTH
, 0 },
130 { .buffer_created
= 0, .name
= "NV12 different modifier per-plane",
131 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_NV12
,
132 .handles
= { 1, 1, 0 }, .flags
= DRM_MODE_FB_MODIFIERS
,
133 .modifier
= { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
, 0, 0 },
134 .pitches
= { MAX_WIDTH
, MAX_WIDTH
, 0 },
137 { .buffer_created
= 1, .name
= "NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE",
138 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_NV12
,
139 .handles
= { 1, 1, 0 }, .flags
= DRM_MODE_FB_MODIFIERS
,
140 .modifier
= { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
, 0 },
141 .pitches
= { MAX_WIDTH
, MAX_WIDTH
, 0 },
144 { .buffer_created
= 0, .name
= "NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS",
145 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_NV12
,
146 .handles
= { 1, 1, 0 }, .modifier
= { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
,
147 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
, 0 },
148 .pitches
= { MAX_WIDTH
, MAX_WIDTH
, 0 },
151 { .buffer_created
= 0, .name
= "NV12 Modifier for inexistent plane",
152 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_NV12
,
153 .handles
= { 1, 1, 0 }, .flags
= DRM_MODE_FB_MODIFIERS
,
154 .modifier
= { DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
, DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
,
155 DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
},
156 .pitches
= { MAX_WIDTH
, MAX_WIDTH
, 0 },
159 { .buffer_created
= 0, .name
= "NV12 Handle for inexistent plane",
160 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_NV12
,
161 .handles
= { 1, 1, 1 }, .flags
= DRM_MODE_FB_MODIFIERS
, .pitches
= { MAX_WIDTH
, MAX_WIDTH
, 0 },
164 { .buffer_created
= 1, .name
= "NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS",
165 .cmd
= { .width
= 600, .height
= 600, .pixel_format
= DRM_FORMAT_NV12
,
166 .handles
= { 1, 1, 1 }, .pitches
= { 600, 600, 600 },
169 { .buffer_created
= 1, .name
= "YVU420 Normal sizes",
170 .cmd
= { .width
= 600, .height
= 600, .pixel_format
= DRM_FORMAT_YVU420
,
171 .handles
= { 1, 1, 1 }, .flags
= DRM_MODE_FB_MODIFIERS
,
172 .pitches
= { 600, 300, 300 },
175 { .buffer_created
= 1, .name
= "YVU420 DRM_MODE_FB_MODIFIERS set without modifier",
176 .cmd
= { .width
= 600, .height
= 600, .pixel_format
= DRM_FORMAT_YVU420
,
177 .handles
= { 1, 1, 1 }, .pitches
= { 600, 300, 300 },
180 { .buffer_created
= 1, .name
= "YVU420 Max sizes",
181 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_YVU420
,
182 .handles
= { 1, 1, 1 }, .pitches
= { MAX_WIDTH
, DIV_ROUND_UP(MAX_WIDTH
, 2),
183 DIV_ROUND_UP(MAX_WIDTH
, 2) },
186 { .buffer_created
= 0, .name
= "YVU420 Invalid pitch",
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) - 1,
189 DIV_ROUND_UP(MAX_WIDTH
, 2) },
192 { .buffer_created
= 1, .name
= "YVU420 Different pitches",
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) + 7 },
198 { .buffer_created
= 1, .name
= "YVU420 Different buffer offsets/pitches",
199 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_YVU420
,
200 .handles
= { 1, 1, 1 }, .offsets
= { MAX_WIDTH
, MAX_WIDTH
+ MAX_WIDTH
* MAX_HEIGHT
,
201 MAX_WIDTH
+ 2 * MAX_WIDTH
* MAX_HEIGHT
},
202 .pitches
= { MAX_WIDTH
, DIV_ROUND_UP(MAX_WIDTH
, 2) + 1, DIV_ROUND_UP(MAX_WIDTH
, 2) + 7 },
205 { .buffer_created
= 0, .name
= "YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS",
206 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_YVU420
,
207 .handles
= { 1, 1, 1 }, .modifier
= { AFBC_FORMAT_MOD_SPARSE
, 0, 0 },
208 .pitches
= { MAX_WIDTH
, DIV_ROUND_UP(MAX_WIDTH
, 2), DIV_ROUND_UP(MAX_WIDTH
, 2) },
211 { .buffer_created
= 0, .name
= "YVU420 Modifier set just for planes 0, 1, 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
, AFBC_FORMAT_MOD_SPARSE
, 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 plane 0, 1, with DRM_MODE_FB_MODIFIERS",
218 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_YVU420
,
219 .handles
= { 1, 1, 1 }, .flags
= DRM_MODE_FB_MODIFIERS
,
220 .modifier
= { AFBC_FORMAT_MOD_SPARSE
, AFBC_FORMAT_MOD_SPARSE
, 0 },
221 .pitches
= { MAX_WIDTH
, DIV_ROUND_UP(MAX_WIDTH
, 2), DIV_ROUND_UP(MAX_WIDTH
, 2) },
224 { .buffer_created
= 1, .name
= "YVU420 Valid modifier",
225 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_YVU420
,
226 .handles
= { 1, 1, 1 }, .flags
= DRM_MODE_FB_MODIFIERS
,
227 .modifier
= { AFBC_FORMAT_MOD_SPARSE
, AFBC_FORMAT_MOD_SPARSE
, AFBC_FORMAT_MOD_SPARSE
},
228 .pitches
= { MAX_WIDTH
, DIV_ROUND_UP(MAX_WIDTH
, 2), DIV_ROUND_UP(MAX_WIDTH
, 2) },
231 { .buffer_created
= 0, .name
= "YVU420 Different modifiers per plane",
232 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_YVU420
,
233 .handles
= { 1, 1, 1 }, .flags
= DRM_MODE_FB_MODIFIERS
,
234 .modifier
= { AFBC_FORMAT_MOD_SPARSE
, AFBC_FORMAT_MOD_SPARSE
| AFBC_FORMAT_MOD_YTR
,
235 AFBC_FORMAT_MOD_SPARSE
},
236 .pitches
= { MAX_WIDTH
, DIV_ROUND_UP(MAX_WIDTH
, 2), DIV_ROUND_UP(MAX_WIDTH
, 2) },
239 { .buffer_created
= 0, .name
= "YVU420 Modifier for inexistent plane",
240 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_YVU420
,
241 .handles
= { 1, 1, 1 }, .flags
= DRM_MODE_FB_MODIFIERS
,
242 .modifier
= { AFBC_FORMAT_MOD_SPARSE
, AFBC_FORMAT_MOD_SPARSE
, AFBC_FORMAT_MOD_SPARSE
,
243 AFBC_FORMAT_MOD_SPARSE
},
244 .pitches
= { MAX_WIDTH
, DIV_ROUND_UP(MAX_WIDTH
, 2), DIV_ROUND_UP(MAX_WIDTH
, 2) },
247 { .buffer_created
= 1, .name
= "X0L2 Normal sizes",
248 .cmd
= { .width
= 600, .height
= 600, .pixel_format
= DRM_FORMAT_X0L2
,
249 .handles
= { 1, 0, 0 }, .pitches
= { 1200, 0, 0 }
252 { .buffer_created
= 1, .name
= "X0L2 Max sizes",
253 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_X0L2
,
254 .handles
= { 1, 0, 0 }, .pitches
= { 2 * MAX_WIDTH
, 0, 0 }
257 { .buffer_created
= 0, .name
= "X0L2 Invalid pitch",
258 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_X0L2
,
259 .handles
= { 1, 0, 0 }, .pitches
= { 2 * MAX_WIDTH
- 1, 0, 0 }
262 { .buffer_created
= 1, .name
= "X0L2 Pitch greater than minimum required",
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 }
267 { .buffer_created
= 0, .name
= "X0L2 Handle for inexistent plane",
268 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_X0L2
,
269 .handles
= { 1, 1, 0 }, .flags
= DRM_MODE_FB_MODIFIERS
,
270 .pitches
= { 2 * MAX_WIDTH
+ 1, 0, 0 }
273 { .buffer_created
= 1, .name
= "X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set",
274 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_X0L2
,
275 .handles
= { 1, 0, 0 }, .offsets
= { 0, 0, 3 },
276 .pitches
= { 2 * MAX_WIDTH
+ 1, 0, 0 }
279 { .buffer_created
= 0, .name
= "X0L2 Modifier without DRM_MODE_FB_MODIFIERS set",
280 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
, .pixel_format
= DRM_FORMAT_X0L2
,
281 .handles
= { 1, 0, 0 }, .pitches
= { 2 * MAX_WIDTH
+ 1, 0, 0 },
282 .modifier
= { AFBC_FORMAT_MOD_SPARSE
, 0, 0 },
285 { .buffer_created
= 1, .name
= "X0L2 Valid modifier",
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 }, .flags
= DRM_MODE_FB_MODIFIERS
,
291 { .buffer_created
= 0, .name
= "X0L2 Modifier for inexistent plane",
292 .cmd
= { .width
= MAX_WIDTH
, .height
= MAX_HEIGHT
,
293 .pixel_format
= DRM_FORMAT_X0L2
, .handles
= { 1, 0, 0 },
294 .pitches
= { 2 * MAX_WIDTH
+ 1, 0, 0 },
295 .modifier
= { AFBC_FORMAT_MOD_SPARSE
, AFBC_FORMAT_MOD_SPARSE
, 0 },
296 .flags
= DRM_MODE_FB_MODIFIERS
,
301 static struct drm_framebuffer
*fb_create_mock(struct drm_device
*dev
,
302 struct drm_file
*file_priv
,
303 const struct drm_mode_fb_cmd2
*mode_cmd
)
305 int *buffer_created
= dev
->dev_private
;
307 return ERR_PTR(-EINVAL
);
310 static struct drm_mode_config_funcs mock_config_funcs
= {
311 .fb_create
= fb_create_mock
,
314 static struct drm_device mock_drm_device
= {
316 .min_width
= MIN_WIDTH
,
317 .max_width
= MAX_WIDTH
,
318 .min_height
= MIN_HEIGHT
,
319 .max_height
= MAX_HEIGHT
,
320 .allow_fb_modifiers
= true,
321 .funcs
= &mock_config_funcs
,
325 static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2
*r
)
327 int buffer_created
= 0;
328 struct drm_framebuffer
*fb
;
330 mock_drm_device
.dev_private
= &buffer_created
;
331 fb
= drm_internal_framebuffer_create(&mock_drm_device
, r
, NULL
);
332 return buffer_created
;
335 int igt_check_drm_framebuffer_create(void *ignored
)
339 for (i
= 0; i
< ARRAY_SIZE(createbuffer_tests
); i
++) {
340 FAIL(createbuffer_tests
[i
].buffer_created
!=
341 execute_drm_mode_fb_cmd2(&createbuffer_tests
[i
].cmd
),
342 "Test %d: \"%s\" failed\n", i
, createbuffer_tests
[i
].name
);