Linux Audio

Check our new training course

Linux kernel drivers training

May 6-19, 2025
Register
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Test cases for the drm_framebuffer functions
  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	struct drm_framebuffer *fb;
334
335	mock_drm_device.dev_private = &buffer_created;
336	fb = drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
337	return buffer_created;
338}
339
340int igt_check_drm_framebuffer_create(void *ignored)
341{
342	int i = 0;
343
344	for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) {
345		FAIL(createbuffer_tests[i].buffer_created !=
346				execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd),
347		     "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name);
348	}
349
350	return 0;
351}