test-drm_framebuffer.c (14910B)
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#include <drm/drm_print.h> 12 13#include "../drm_crtc_internal.h" 14 15#include "test-drm_modeset_common.h" 16 17#define MIN_WIDTH 4 18#define MAX_WIDTH 4096 19#define MIN_HEIGHT 4 20#define MAX_HEIGHT 4096 21 22struct drm_framebuffer_test { 23 int buffer_created; 24 struct drm_mode_fb_cmd2 cmd; 25 const char *name; 26}; 27 28static 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 }, 32 } 33}, 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 }, 37 } 38}, 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 }, 42 } 43}, 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 }, 47 } 48}, 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 }, 52 } 53}, 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 }, 57 } 58}, 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 }, 62 } 63}, 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 }, 67 } 68}, 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 }, 72 } 73}, 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 }, 77 } 78}, 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 }, 82 } 83}, 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, 88 } 89}, 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 }, 94 } 95}, 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 }, 101 } 102}, 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 }, 107 } 108}, 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 }, 113 } 114}, 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 }, 118 } 119}, 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 }, 123 } 124}, 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 }, 128 } 129}, 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 }, 134 } 135}, 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 }, 141 } 142}, 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 }, 148 } 149}, 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 }, 155 } 156}, 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 }, 163 } 164}, 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 }, 168 } 169}, 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 }, 173 } 174}, 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 }, 179 } 180}, 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 }, 184 } 185}, 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) }, 190 } 191}, 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) }, 196 } 197}, 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 }, 202 } 203}, 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 }, 209 } 210}, 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) }, 215 } 216}, 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) }, 221 } 222}, 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) }, 228 } 229}, 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) }, 235 } 236}, 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) }, 243 } 244}, 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) }, 251 } 252}, 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 } 256 } 257}, 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 } 261 } 262}, 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 } 266 } 267}, 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 } 271 } 272}, 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 } 277 } 278}, 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 } 283 } 284}, 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 }, 289 } 290}, 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, 295 } 296}, 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, 303 } 304}, 305}; 306 307static 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) 310{ 311 int *buffer_created = dev->dev_private; 312 *buffer_created = 1; 313 return ERR_PTR(-EINVAL); 314} 315 316static struct drm_mode_config_funcs mock_config_funcs = { 317 .fb_create = fb_create_mock, 318}; 319 320static struct drm_device mock_drm_device = { 321 .mode_config = { 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, 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}