Home | History | Annotate | Line # | Download | only in modetest
      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