1 /* 2 * DRM based mode setting test program 3 * Copyright 2008 Tungsten Graphics 4 * Jakob Bornecrantz <jakob (at) tungstengraphics.com> 5 * Copyright 2008 Intel Corporation 6 * Jesse Barnes <jesse.barnes (at) intel.com> 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 24 * IN THE SOFTWARE. 25 */ 26 27 #include <assert.h> 28 #include <errno.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <stdint.h> 32 #include <string.h> 33 #include <sys/ioctl.h> 34 35 #include "drm.h" 36 #include "drm_fourcc.h" 37 38 #include "libdrm_macros.h" 39 #include "xf86drm.h" 40 #include "xf86drmMode.h" 41 42 #include "buffers.h" 43 44 struct bo 45 { 46 int fd; 47 void *ptr; 48 uint64_t size; 49 uint32_t pitch; 50 uint32_t handle; 51 }; 52 53 /* ----------------------------------------------------------------------------- 54 * Buffers management 55 */ 56 57 static struct bo * 58 bo_create_dumb(int fd, unsigned int width, unsigned int height, unsigned int bpp) 59 { 60 struct bo *bo; 61 int ret; 62 63 bo = calloc(1, sizeof(*bo)); 64 if (bo == NULL) { 65 fprintf(stderr, "failed to allocate buffer object\n"); 66 return NULL; 67 } 68 69 ret = drmModeCreateDumbBuffer(fd, width, height, bpp, 0, &bo->handle, 70 &bo->pitch, &bo->size); 71 if (ret) { 72 fprintf(stderr, "failed to create dumb buffer: %s\n", 73 strerror(errno)); 74 free(bo); 75 return NULL; 76 } 77 78 bo->fd = fd; 79 80 return bo; 81 } 82 83 static int bo_map(struct bo *bo, void **out) 84 { 85 void *map; 86 int ret; 87 uint64_t offset; 88 89 ret = drmModeMapDumbBuffer(bo->fd, bo->handle, &offset); 90 if (ret) 91 return ret; 92 93 map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 94 bo->fd, offset); 95 if (map == MAP_FAILED) 96 return -EINVAL; 97 98 bo->ptr = map; 99 *out = map; 100 101 return 0; 102 } 103 104 static void bo_unmap(struct bo *bo) 105 { 106 if (!bo->ptr) 107 return; 108 109 drm_munmap(bo->ptr, bo->size); 110 bo->ptr = NULL; 111 } 112 113 struct bo * 114 bo_create(int fd, unsigned int format, 115 unsigned int width, unsigned int height, 116 unsigned int handles[4], unsigned int pitches[4], 117 unsigned int offsets[4], enum util_fill_pattern pattern, 118 unsigned long seed) 119 { 120 unsigned int virtual_height, xsub, ysub; 121 struct bo *bo; 122 unsigned int bpp; 123 bool is_planar; 124 void *planes[3] = { 0, }; 125 void *virtual; 126 int ret; 127 128 switch (format) { 129 case DRM_FORMAT_C1: 130 bpp = 1; 131 break; 132 133 case DRM_FORMAT_C2: 134 bpp = 2; 135 break; 136 137 case DRM_FORMAT_C4: 138 bpp = 4; 139 break; 140 141 case DRM_FORMAT_C8: 142 case DRM_FORMAT_NV12: 143 case DRM_FORMAT_NV21: 144 case DRM_FORMAT_NV16: 145 case DRM_FORMAT_NV61: 146 case DRM_FORMAT_NV24: 147 case DRM_FORMAT_NV42: 148 case DRM_FORMAT_YUV420: 149 case DRM_FORMAT_YVU420: 150 case DRM_FORMAT_YUV422: 151 case DRM_FORMAT_YVU422: 152 case DRM_FORMAT_YUV444: 153 case DRM_FORMAT_YVU444: 154 bpp = 8; 155 break; 156 157 case DRM_FORMAT_NV15: 158 case DRM_FORMAT_NV20: 159 case DRM_FORMAT_NV30: 160 bpp = 10; 161 break; 162 163 case DRM_FORMAT_ARGB4444: 164 case DRM_FORMAT_XRGB4444: 165 case DRM_FORMAT_ABGR4444: 166 case DRM_FORMAT_XBGR4444: 167 case DRM_FORMAT_RGBA4444: 168 case DRM_FORMAT_RGBX4444: 169 case DRM_FORMAT_BGRA4444: 170 case DRM_FORMAT_BGRX4444: 171 case DRM_FORMAT_ARGB1555: 172 case DRM_FORMAT_XRGB1555: 173 case DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN: 174 case DRM_FORMAT_ABGR1555: 175 case DRM_FORMAT_XBGR1555: 176 case DRM_FORMAT_RGBA5551: 177 case DRM_FORMAT_RGBX5551: 178 case DRM_FORMAT_BGRA5551: 179 case DRM_FORMAT_BGRX5551: 180 case DRM_FORMAT_RGB565: 181 case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: 182 case DRM_FORMAT_BGR565: 183 case DRM_FORMAT_UYVY: 184 case DRM_FORMAT_VYUY: 185 case DRM_FORMAT_YUYV: 186 case DRM_FORMAT_YVYU: 187 bpp = 16; 188 break; 189 190 case DRM_FORMAT_BGR888: 191 case DRM_FORMAT_RGB888: 192 bpp = 24; 193 break; 194 195 case DRM_FORMAT_ARGB8888: 196 case DRM_FORMAT_XRGB8888: 197 case DRM_FORMAT_ABGR8888: 198 case DRM_FORMAT_XBGR8888: 199 case DRM_FORMAT_RGBA8888: 200 case DRM_FORMAT_RGBX8888: 201 case DRM_FORMAT_BGRA8888: 202 case DRM_FORMAT_BGRX8888: 203 case DRM_FORMAT_ARGB2101010: 204 case DRM_FORMAT_XRGB2101010: 205 case DRM_FORMAT_ABGR2101010: 206 case DRM_FORMAT_XBGR2101010: 207 case DRM_FORMAT_RGBA1010102: 208 case DRM_FORMAT_RGBX1010102: 209 case DRM_FORMAT_BGRA1010102: 210 case DRM_FORMAT_BGRX1010102: 211 bpp = 32; 212 break; 213 214 case DRM_FORMAT_XRGB16161616F: 215 case DRM_FORMAT_XBGR16161616F: 216 case DRM_FORMAT_ARGB16161616F: 217 case DRM_FORMAT_ABGR16161616F: 218 bpp = 64; 219 break; 220 221 default: 222 fprintf(stderr, "unsupported format 0x%08x\n", format); 223 return NULL; 224 } 225 226 switch (format) { 227 case DRM_FORMAT_NV12: 228 case DRM_FORMAT_NV21: 229 case DRM_FORMAT_NV15: 230 case DRM_FORMAT_YUV420: 231 case DRM_FORMAT_YVU420: 232 is_planar = true; 233 xsub = 2; 234 ysub = 2; 235 break; 236 237 case DRM_FORMAT_NV16: 238 case DRM_FORMAT_NV61: 239 case DRM_FORMAT_NV20: 240 case DRM_FORMAT_YUV422: 241 case DRM_FORMAT_YVU422: 242 is_planar = true; 243 xsub = 2; 244 ysub = 1; 245 break; 246 247 case DRM_FORMAT_NV24: 248 case DRM_FORMAT_NV42: 249 case DRM_FORMAT_NV30: 250 case DRM_FORMAT_YUV444: 251 case DRM_FORMAT_YVU444: 252 is_planar = true; 253 xsub = 1; 254 ysub = 1; 255 break; 256 257 default: 258 is_planar = false; 259 xsub = 1; 260 ysub = 1; 261 break; 262 } 263 264 virtual_height = height; 265 if (is_planar) 266 virtual_height += height * 2 / xsub / ysub; 267 268 bo = bo_create_dumb(fd, width, virtual_height, bpp); 269 if (!bo) 270 return NULL; 271 272 ret = bo_map(bo, &virtual); 273 if (ret) { 274 fprintf(stderr, "failed to map buffer: %s\n", 275 strerror(-errno)); 276 bo_destroy(bo); 277 return NULL; 278 } 279 280 /* just testing a limited # of formats to test single 281 * and multi-planar path.. would be nice to add more.. 282 */ 283 switch (format) { 284 case DRM_FORMAT_UYVY: 285 case DRM_FORMAT_VYUY: 286 case DRM_FORMAT_YUYV: 287 case DRM_FORMAT_YVYU: 288 offsets[0] = 0; 289 handles[0] = bo->handle; 290 pitches[0] = bo->pitch; 291 292 planes[0] = virtual; 293 break; 294 295 case DRM_FORMAT_NV12: 296 case DRM_FORMAT_NV21: 297 case DRM_FORMAT_NV16: 298 case DRM_FORMAT_NV61: 299 case DRM_FORMAT_NV15: 300 case DRM_FORMAT_NV24: 301 case DRM_FORMAT_NV42: 302 case DRM_FORMAT_NV20: 303 case DRM_FORMAT_NV30: 304 offsets[0] = 0; 305 handles[0] = bo->handle; 306 pitches[0] = bo->pitch; 307 pitches[1] = pitches[0] * 2 / xsub; 308 offsets[1] = pitches[0] * height; 309 handles[1] = bo->handle; 310 311 planes[0] = virtual; 312 planes[1] = virtual + offsets[1]; 313 break; 314 315 case DRM_FORMAT_YUV420: 316 case DRM_FORMAT_YVU420: 317 case DRM_FORMAT_YUV422: 318 case DRM_FORMAT_YVU422: 319 case DRM_FORMAT_YUV444: 320 case DRM_FORMAT_YVU444: 321 offsets[0] = 0; 322 handles[0] = bo->handle; 323 pitches[0] = bo->pitch; 324 pitches[1] = pitches[0] / xsub; 325 offsets[1] = pitches[0] * height; 326 handles[1] = bo->handle; 327 pitches[2] = pitches[1]; 328 offsets[2] = offsets[1] + pitches[1] * height / ysub; 329 handles[2] = bo->handle; 330 331 planes[0] = virtual; 332 planes[1] = virtual + offsets[1]; 333 planes[2] = virtual + offsets[2]; 334 break; 335 336 case DRM_FORMAT_C1: 337 case DRM_FORMAT_C2: 338 case DRM_FORMAT_C4: 339 case DRM_FORMAT_C8: 340 case DRM_FORMAT_ARGB4444: 341 case DRM_FORMAT_XRGB4444: 342 case DRM_FORMAT_ABGR4444: 343 case DRM_FORMAT_XBGR4444: 344 case DRM_FORMAT_RGBA4444: 345 case DRM_FORMAT_RGBX4444: 346 case DRM_FORMAT_BGRA4444: 347 case DRM_FORMAT_BGRX4444: 348 case DRM_FORMAT_ARGB1555: 349 case DRM_FORMAT_XRGB1555: 350 case DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN: 351 case DRM_FORMAT_ABGR1555: 352 case DRM_FORMAT_XBGR1555: 353 case DRM_FORMAT_RGBA5551: 354 case DRM_FORMAT_RGBX5551: 355 case DRM_FORMAT_BGRA5551: 356 case DRM_FORMAT_BGRX5551: 357 case DRM_FORMAT_RGB565: 358 case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: 359 case DRM_FORMAT_BGR565: 360 case DRM_FORMAT_BGR888: 361 case DRM_FORMAT_RGB888: 362 case DRM_FORMAT_ARGB8888: 363 case DRM_FORMAT_XRGB8888: 364 case DRM_FORMAT_ABGR8888: 365 case DRM_FORMAT_XBGR8888: 366 case DRM_FORMAT_RGBA8888: 367 case DRM_FORMAT_RGBX8888: 368 case DRM_FORMAT_BGRA8888: 369 case DRM_FORMAT_BGRX8888: 370 case DRM_FORMAT_ARGB2101010: 371 case DRM_FORMAT_XRGB2101010: 372 case DRM_FORMAT_ABGR2101010: 373 case DRM_FORMAT_XBGR2101010: 374 case DRM_FORMAT_RGBA1010102: 375 case DRM_FORMAT_RGBX1010102: 376 case DRM_FORMAT_BGRA1010102: 377 case DRM_FORMAT_BGRX1010102: 378 case DRM_FORMAT_XRGB16161616F: 379 case DRM_FORMAT_XBGR16161616F: 380 case DRM_FORMAT_ARGB16161616F: 381 case DRM_FORMAT_ABGR16161616F: 382 offsets[0] = 0; 383 handles[0] = bo->handle; 384 pitches[0] = bo->pitch; 385 386 planes[0] = virtual; 387 break; 388 } 389 390 util_fill_pattern(format, pattern, planes, width, height, pitches[0], seed); 391 bo_unmap(bo); 392 393 return bo; 394 } 395 396 void bo_destroy(struct bo *bo) 397 { 398 int ret; 399 400 ret = drmModeDestroyDumbBuffer(bo->fd, bo->handle); 401 if (ret) 402 fprintf(stderr, "failed to destroy dumb buffer: %s\n", 403 strerror(errno)); 404 405 free(bo); 406 } 407 408 void bo_dump(struct bo *bo, const char *filename) 409 { 410 FILE *fp; 411 412 if (!bo || !filename) 413 return; 414 415 fp = fopen(filename, "wb"); 416 if (fp) { 417 void *addr; 418 419 bo_map(bo, &addr); 420 printf("Dumping buffer %p to file %s.\n", bo->ptr, filename); 421 fwrite(bo->ptr, 1, bo->size, fp); 422 bo_unmap(bo); 423 fclose(fp); 424 } 425 } 426