1 /* 2 * DRM based mode setting test program 3 * Copyright 2008 Tungsten Graphics 4 * Jakob Bornecrantz <jakob@tungstengraphics.com> 5 * Copyright 2008 Intel Corporation 6 * Jesse Barnes <jesse.barnes@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 { 119 unsigned int virtual_height, xsub, ysub; 120 struct bo *bo; 121 unsigned int bpp; 122 bool is_planar; 123 void *planes[3] = { 0, }; 124 void *virtual; 125 int ret; 126 127 switch (format) { 128 case DRM_FORMAT_C1: 129 bpp = 1; 130 break; 131 132 case DRM_FORMAT_C2: 133 bpp = 2; 134 break; 135 136 case DRM_FORMAT_C4: 137 bpp = 4; 138 break; 139 140 case DRM_FORMAT_C8: 141 case DRM_FORMAT_NV12: 142 case DRM_FORMAT_NV21: 143 case DRM_FORMAT_NV16: 144 case DRM_FORMAT_NV61: 145 case DRM_FORMAT_NV24: 146 case DRM_FORMAT_NV42: 147 case DRM_FORMAT_YUV420: 148 case DRM_FORMAT_YVU420: 149 case DRM_FORMAT_YUV422: 150 case DRM_FORMAT_YVU422: 151 case DRM_FORMAT_YUV444: 152 case DRM_FORMAT_YVU444: 153 bpp = 8; 154 break; 155 156 case DRM_FORMAT_NV15: 157 case DRM_FORMAT_NV20: 158 case DRM_FORMAT_NV30: 159 bpp = 10; 160 break; 161 162 case DRM_FORMAT_ARGB4444: 163 case DRM_FORMAT_XRGB4444: 164 case DRM_FORMAT_ABGR4444: 165 case DRM_FORMAT_XBGR4444: 166 case DRM_FORMAT_RGBA4444: 167 case DRM_FORMAT_RGBX4444: 168 case DRM_FORMAT_BGRA4444: 169 case DRM_FORMAT_BGRX4444: 170 case DRM_FORMAT_ARGB1555: 171 case DRM_FORMAT_XRGB1555: 172 case DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN: 173 case DRM_FORMAT_ABGR1555: 174 case DRM_FORMAT_XBGR1555: 175 case DRM_FORMAT_RGBA5551: 176 case DRM_FORMAT_RGBX5551: 177 case DRM_FORMAT_BGRA5551: 178 case DRM_FORMAT_BGRX5551: 179 case DRM_FORMAT_RGB565: 180 case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: 181 case DRM_FORMAT_BGR565: 182 case DRM_FORMAT_UYVY: 183 case DRM_FORMAT_VYUY: 184 case DRM_FORMAT_YUYV: 185 case DRM_FORMAT_YVYU: 186 bpp = 16; 187 break; 188 189 case DRM_FORMAT_BGR888: 190 case DRM_FORMAT_RGB888: 191 bpp = 24; 192 break; 193 194 case DRM_FORMAT_ARGB8888: 195 case DRM_FORMAT_XRGB8888: 196 case DRM_FORMAT_ABGR8888: 197 case DRM_FORMAT_XBGR8888: 198 case DRM_FORMAT_RGBA8888: 199 case DRM_FORMAT_RGBX8888: 200 case DRM_FORMAT_BGRA8888: 201 case DRM_FORMAT_BGRX8888: 202 case DRM_FORMAT_ARGB2101010: 203 case DRM_FORMAT_XRGB2101010: 204 case DRM_FORMAT_ABGR2101010: 205 case DRM_FORMAT_XBGR2101010: 206 case DRM_FORMAT_RGBA1010102: 207 case DRM_FORMAT_RGBX1010102: 208 case DRM_FORMAT_BGRA1010102: 209 case DRM_FORMAT_BGRX1010102: 210 bpp = 32; 211 break; 212 213 case DRM_FORMAT_XRGB16161616F: 214 case DRM_FORMAT_XBGR16161616F: 215 case DRM_FORMAT_ARGB16161616F: 216 case DRM_FORMAT_ABGR16161616F: 217 bpp = 64; 218 break; 219 220 default: 221 fprintf(stderr, "unsupported format 0x%08x\n", format); 222 return NULL; 223 } 224 225 switch (format) { 226 case DRM_FORMAT_NV12: 227 case DRM_FORMAT_NV21: 228 case DRM_FORMAT_NV15: 229 case DRM_FORMAT_YUV420: 230 case DRM_FORMAT_YVU420: 231 is_planar = true; 232 xsub = 2; 233 ysub = 2; 234 break; 235 236 case DRM_FORMAT_NV16: 237 case DRM_FORMAT_NV61: 238 case DRM_FORMAT_NV20: 239 case DRM_FORMAT_YUV422: 240 case DRM_FORMAT_YVU422: 241 is_planar = true; 242 xsub = 2; 243 ysub = 1; 244 break; 245 246 case DRM_FORMAT_NV24: 247 case DRM_FORMAT_NV42: 248 case DRM_FORMAT_NV30: 249 case DRM_FORMAT_YUV444: 250 case DRM_FORMAT_YVU444: 251 is_planar = true; 252 xsub = 1; 253 ysub = 1; 254 break; 255 256 default: 257 is_planar = false; 258 xsub = 1; 259 ysub = 1; 260 break; 261 } 262 263 virtual_height = height; 264 if (is_planar) 265 virtual_height += height * 2 / xsub / ysub; 266 267 bo = bo_create_dumb(fd, width, virtual_height, bpp); 268 if (!bo) 269 return NULL; 270 271 ret = bo_map(bo, &virtual); 272 if (ret) { 273 fprintf(stderr, "failed to map buffer: %s\n", 274 strerror(-errno)); 275 bo_destroy(bo); 276 return NULL; 277 } 278 279 /* just testing a limited # of formats to test single 280 * and multi-planar path.. would be nice to add more.. 281 */ 282 switch (format) { 283 case DRM_FORMAT_UYVY: 284 case DRM_FORMAT_VYUY: 285 case DRM_FORMAT_YUYV: 286 case DRM_FORMAT_YVYU: 287 offsets[0] = 0; 288 handles[0] = bo->handle; 289 pitches[0] = bo->pitch; 290 291 planes[0] = virtual; 292 break; 293 294 case DRM_FORMAT_NV12: 295 case DRM_FORMAT_NV21: 296 case DRM_FORMAT_NV16: 297 case DRM_FORMAT_NV61: 298 case DRM_FORMAT_NV15: 299 case DRM_FORMAT_NV24: 300 case DRM_FORMAT_NV42: 301 case DRM_FORMAT_NV20: 302 case DRM_FORMAT_NV30: 303 offsets[0] = 0; 304 handles[0] = bo->handle; 305 pitches[0] = bo->pitch; 306 pitches[1] = pitches[0] * 2 / xsub; 307 offsets[1] = pitches[0] * height; 308 handles[1] = bo->handle; 309 310 planes[0] = virtual; 311 planes[1] = virtual + offsets[1]; 312 break; 313 314 case DRM_FORMAT_YUV420: 315 case DRM_FORMAT_YVU420: 316 case DRM_FORMAT_YUV422: 317 case DRM_FORMAT_YVU422: 318 case DRM_FORMAT_YUV444: 319 case DRM_FORMAT_YVU444: 320 offsets[0] = 0; 321 handles[0] = bo->handle; 322 pitches[0] = bo->pitch; 323 pitches[1] = pitches[0] / xsub; 324 offsets[1] = pitches[0] * height; 325 handles[1] = bo->handle; 326 pitches[2] = pitches[1]; 327 offsets[2] = offsets[1] + pitches[1] * height / ysub; 328 handles[2] = bo->handle; 329 330 planes[0] = virtual; 331 planes[1] = virtual + offsets[1]; 332 planes[2] = virtual + offsets[2]; 333 break; 334 335 case DRM_FORMAT_C1: 336 case DRM_FORMAT_C2: 337 case DRM_FORMAT_C4: 338 case DRM_FORMAT_C8: 339 case DRM_FORMAT_ARGB4444: 340 case DRM_FORMAT_XRGB4444: 341 case DRM_FORMAT_ABGR4444: 342 case DRM_FORMAT_XBGR4444: 343 case DRM_FORMAT_RGBA4444: 344 case DRM_FORMAT_RGBX4444: 345 case DRM_FORMAT_BGRA4444: 346 case DRM_FORMAT_BGRX4444: 347 case DRM_FORMAT_ARGB1555: 348 case DRM_FORMAT_XRGB1555: 349 case DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN: 350 case DRM_FORMAT_ABGR1555: 351 case DRM_FORMAT_XBGR1555: 352 case DRM_FORMAT_RGBA5551: 353 case DRM_FORMAT_RGBX5551: 354 case DRM_FORMAT_BGRA5551: 355 case DRM_FORMAT_BGRX5551: 356 case DRM_FORMAT_RGB565: 357 case DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN: 358 case DRM_FORMAT_BGR565: 359 case DRM_FORMAT_BGR888: 360 case DRM_FORMAT_RGB888: 361 case DRM_FORMAT_ARGB8888: 362 case DRM_FORMAT_XRGB8888: 363 case DRM_FORMAT_ABGR8888: 364 case DRM_FORMAT_XBGR8888: 365 case DRM_FORMAT_RGBA8888: 366 case DRM_FORMAT_RGBX8888: 367 case DRM_FORMAT_BGRA8888: 368 case DRM_FORMAT_BGRX8888: 369 case DRM_FORMAT_ARGB2101010: 370 case DRM_FORMAT_XRGB2101010: 371 case DRM_FORMAT_ABGR2101010: 372 case DRM_FORMAT_XBGR2101010: 373 case DRM_FORMAT_RGBA1010102: 374 case DRM_FORMAT_RGBX1010102: 375 case DRM_FORMAT_BGRA1010102: 376 case DRM_FORMAT_BGRX1010102: 377 case DRM_FORMAT_XRGB16161616F: 378 case DRM_FORMAT_XBGR16161616F: 379 case DRM_FORMAT_ARGB16161616F: 380 case DRM_FORMAT_ABGR16161616F: 381 offsets[0] = 0; 382 handles[0] = bo->handle; 383 pitches[0] = bo->pitch; 384 385 planes[0] = virtual; 386 break; 387 } 388 389 util_fill_pattern(format, pattern, planes, width, height, pitches[0]); 390 bo_unmap(bo); 391 392 return bo; 393 } 394 395 void bo_destroy(struct bo *bo) 396 { 397 int ret; 398 399 ret = drmModeDestroyDumbBuffer(bo->fd, bo->handle); 400 if (ret) 401 fprintf(stderr, "failed to destroy dumb buffer: %s\n", 402 strerror(errno)); 403 404 free(bo); 405 } 406 407 void bo_dump(struct bo *bo, const char *filename) 408 { 409 FILE *fp; 410 411 if (!bo || !filename) 412 return; 413 414 fp = fopen(filename, "wb"); 415 if (fp) { 416 void *addr; 417 418 bo_map(bo, &addr); 419 printf("Dumping buffer %p to file %s.\n", bo->ptr, filename); 420 fwrite(bo->ptr, 1, bo->size, fp); 421 bo_unmap(bo); 422 fclose(fp); 423 } 424 } 425