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#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <assert.h>
32#include <errno.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <stdint.h>
36#include <string.h>
37#include <sys/ioctl.h>
38
39#include "drm.h"
40#include "drm_fourcc.h"
41
42#include "libdrm.h"
43#include "xf86drm.h"
44
45#include "buffers.h"
46
47#ifdef HAVE_CAIRO
48#include <math.h>
49#include <cairo.h>
50#endif
51
52#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
53
54struct bo
55{
56	int fd;
57	void *ptr;
58	size_t size;
59	size_t offset;
60	size_t pitch;
61	unsigned handle;
62};
63
64/* -----------------------------------------------------------------------------
65 * Formats
66 */
67
68struct color_component {
69	unsigned int length;
70	unsigned int offset;
71};
72
73struct rgb_info {
74	struct color_component red;
75	struct color_component green;
76	struct color_component blue;
77	struct color_component alpha;
78};
79
80enum yuv_order {
81	YUV_YCbCr = 1,
82	YUV_YCrCb = 2,
83	YUV_YC = 4,
84	YUV_CY = 8,
85};
86
87struct yuv_info {
88	enum yuv_order order;
89	unsigned int xsub;
90	unsigned int ysub;
91	unsigned int chroma_stride;
92};
93
94struct format_info {
95	unsigned int format;
96	const char *name;
97	const struct rgb_info rgb;
98	const struct yuv_info yuv;
99};
100
101#define MAKE_RGB_INFO(rl, ro, bl, bo, gl, go, al, ao) \
102	.rgb = { { (rl), (ro) }, { (bl), (bo) }, { (gl), (go) }, { (al), (ao) } }
103
104#define MAKE_YUV_INFO(order, xsub, ysub, chroma_stride) \
105	.yuv = { (order), (xsub), (ysub), (chroma_stride) }
106
107static const struct format_info format_info[] = {
108	/* YUV packed */
109	{ DRM_FORMAT_UYVY, "UYVY", MAKE_YUV_INFO(YUV_YCbCr | YUV_CY, 2, 2, 2) },
110	{ DRM_FORMAT_VYUY, "VYUY", MAKE_YUV_INFO(YUV_YCrCb | YUV_CY, 2, 2, 2) },
111	{ DRM_FORMAT_YUYV, "YUYV", MAKE_YUV_INFO(YUV_YCbCr | YUV_YC, 2, 2, 2) },
112	{ DRM_FORMAT_YVYU, "YVYU", MAKE_YUV_INFO(YUV_YCrCb | YUV_YC, 2, 2, 2) },
113	/* YUV semi-planar */
114	{ DRM_FORMAT_NV12, "NV12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 2) },
115	{ DRM_FORMAT_NV21, "NV21", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 2) },
116	{ DRM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) },
117	{ DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) },
118	/* YUV planar */
119	{ DRM_FORMAT_YUV420, "YU12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 1) },
120	{ DRM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) },
121	/* RGB16 */
122	{ DRM_FORMAT_ARGB4444, "AR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) },
123	{ DRM_FORMAT_XRGB4444, "XR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 0, 0) },
124	{ DRM_FORMAT_ABGR4444, "AB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 4, 12) },
125	{ DRM_FORMAT_XBGR4444, "XB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 0, 0) },
126	{ DRM_FORMAT_RGBA4444, "RA12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 4, 0) },
127	{ DRM_FORMAT_RGBX4444, "RX12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 0, 0) },
128	{ DRM_FORMAT_BGRA4444, "BA12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 4, 0) },
129	{ DRM_FORMAT_BGRX4444, "BX12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 0, 0) },
130	{ DRM_FORMAT_ARGB1555, "AR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) },
131	{ DRM_FORMAT_XRGB1555, "XR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 0, 0) },
132	{ DRM_FORMAT_ABGR1555, "AB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 1, 15) },
133	{ DRM_FORMAT_XBGR1555, "XB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 0, 0) },
134	{ DRM_FORMAT_RGBA5551, "RA15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 1, 0) },
135	{ DRM_FORMAT_RGBX5551, "RX15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 0, 0) },
136	{ DRM_FORMAT_BGRA5551, "BA15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 1, 0) },
137	{ DRM_FORMAT_BGRX5551, "BX15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 0, 0) },
138	{ DRM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) },
139	{ DRM_FORMAT_BGR565, "BG16", MAKE_RGB_INFO(5, 0, 6, 5, 5, 11, 0, 0) },
140	/* RGB24 */
141	{ DRM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
142	{ DRM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
143	/* RGB32 */
144	{ DRM_FORMAT_ARGB8888, "AR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) },
145	{ DRM_FORMAT_XRGB8888, "XR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
146	{ DRM_FORMAT_ABGR8888, "AB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 8, 24) },
147	{ DRM_FORMAT_XBGR8888, "XB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
148	{ DRM_FORMAT_RGBA8888, "RA24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 8, 0) },
149	{ DRM_FORMAT_RGBX8888, "RX24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 0, 0) },
150	{ DRM_FORMAT_BGRA8888, "BA24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) },
151	{ DRM_FORMAT_BGRX8888, "BX24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 0, 0) },
152	{ DRM_FORMAT_ARGB2101010, "AR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 2, 30) },
153	{ DRM_FORMAT_XRGB2101010, "XR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 0, 0) },
154	{ DRM_FORMAT_ABGR2101010, "AB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 2, 30) },
155	{ DRM_FORMAT_XBGR2101010, "XB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 0, 0) },
156	{ DRM_FORMAT_RGBA1010102, "RA30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 2, 0) },
157	{ DRM_FORMAT_RGBX1010102, "RX30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 0, 0) },
158	{ DRM_FORMAT_BGRA1010102, "BA30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 2, 0) },
159	{ DRM_FORMAT_BGRX1010102, "BX30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 0, 0) },
160};
161
162unsigned int format_fourcc(const char *name)
163{
164	unsigned int i;
165	for (i = 0; i < ARRAY_SIZE(format_info); i++) {
166		if (!strcmp(format_info[i].name, name))
167			return format_info[i].format;
168	}
169	return 0;
170}
171
172/* -----------------------------------------------------------------------------
173 * Test patterns
174 */
175
176struct color_rgb24 {
177	unsigned int value:24;
178} __attribute__((__packed__));
179
180struct color_yuv {
181	unsigned char y;
182	unsigned char u;
183	unsigned char v;
184};
185
186#define MAKE_YUV_601_Y(r, g, b) \
187	((( 66 * (r) + 129 * (g) +  25 * (b) + 128) >> 8) + 16)
188#define MAKE_YUV_601_U(r, g, b) \
189	(((-38 * (r) -  74 * (g) + 112 * (b) + 128) >> 8) + 128)
190#define MAKE_YUV_601_V(r, g, b) \
191	(((112 * (r) -  94 * (g) -  18 * (b) + 128) >> 8) + 128)
192
193#define MAKE_YUV_601(r, g, b) \
194	{ .y = MAKE_YUV_601_Y(r, g, b), \
195	  .u = MAKE_YUV_601_U(r, g, b), \
196	  .v = MAKE_YUV_601_V(r, g, b) }
197
198#define MAKE_RGBA(rgb, r, g, b, a) \
199	((((r) >> (8 - (rgb)->red.length)) << (rgb)->red.offset) | \
200	 (((g) >> (8 - (rgb)->green.length)) << (rgb)->green.offset) | \
201	 (((b) >> (8 - (rgb)->blue.length)) << (rgb)->blue.offset) | \
202	 (((a) >> (8 - (rgb)->alpha.length)) << (rgb)->alpha.offset))
203
204#define MAKE_RGB24(rgb, r, g, b) \
205	{ .value = MAKE_RGBA(rgb, r, g, b, 0) }
206
207static void
208fill_smpte_yuv_planar(const struct yuv_info *yuv,
209		      unsigned char *y_mem, unsigned char *u_mem,
210		      unsigned char *v_mem, unsigned int width,
211		      unsigned int height, unsigned int stride)
212{
213	const struct color_yuv colors_top[] = {
214		MAKE_YUV_601(191, 192, 192),	/* grey */
215		MAKE_YUV_601(192, 192, 0),	/* yellow */
216		MAKE_YUV_601(0, 192, 192),	/* cyan */
217		MAKE_YUV_601(0, 192, 0),	/* green */
218		MAKE_YUV_601(192, 0, 192),	/* magenta */
219		MAKE_YUV_601(192, 0, 0),	/* red */
220		MAKE_YUV_601(0, 0, 192),	/* blue */
221	};
222	const struct color_yuv colors_middle[] = {
223		MAKE_YUV_601(0, 0, 192),	/* blue */
224		MAKE_YUV_601(19, 19, 19),	/* black */
225		MAKE_YUV_601(192, 0, 192),	/* magenta */
226		MAKE_YUV_601(19, 19, 19),	/* black */
227		MAKE_YUV_601(0, 192, 192),	/* cyan */
228		MAKE_YUV_601(19, 19, 19),	/* black */
229		MAKE_YUV_601(192, 192, 192),	/* grey */
230	};
231	const struct color_yuv colors_bottom[] = {
232		MAKE_YUV_601(0, 33, 76),	/* in-phase */
233		MAKE_YUV_601(255, 255, 255),	/* super white */
234		MAKE_YUV_601(50, 0, 106),	/* quadrature */
235		MAKE_YUV_601(19, 19, 19),	/* black */
236		MAKE_YUV_601(9, 9, 9),		/* 3.5% */
237		MAKE_YUV_601(19, 19, 19),	/* 7.5% */
238		MAKE_YUV_601(29, 29, 29),	/* 11.5% */
239		MAKE_YUV_601(19, 19, 19),	/* black */
240	};
241	unsigned int cs = yuv->chroma_stride;
242	unsigned int xsub = yuv->xsub;
243	unsigned int ysub = yuv->ysub;
244	unsigned int x;
245	unsigned int y;
246
247	/* Luma */
248	for (y = 0; y < height * 6 / 9; ++y) {
249		for (x = 0; x < width; ++x)
250			y_mem[x] = colors_top[x * 7 / width].y;
251		y_mem += stride;
252	}
253
254	for (; y < height * 7 / 9; ++y) {
255		for (x = 0; x < width; ++x)
256			y_mem[x] = colors_middle[x * 7 / width].y;
257		y_mem += stride;
258	}
259
260	for (; y < height; ++y) {
261		for (x = 0; x < width * 5 / 7; ++x)
262			y_mem[x] = colors_bottom[x * 4 / (width * 5 / 7)].y;
263		for (; x < width * 6 / 7; ++x)
264			y_mem[x] = colors_bottom[(x - width * 5 / 7) * 3
265						 / (width / 7) + 4].y;
266		for (; x < width; ++x)
267			y_mem[x] = colors_bottom[7].y;
268		y_mem += stride;
269	}
270
271	/* Chroma */
272	for (y = 0; y < height / ysub * 6 / 9; ++y) {
273		for (x = 0; x < width; x += xsub) {
274			u_mem[x*cs/xsub] = colors_top[x * 7 / width].u;
275			v_mem[x*cs/xsub] = colors_top[x * 7 / width].v;
276		}
277		u_mem += stride * cs / xsub;
278		v_mem += stride * cs / xsub;
279	}
280
281	for (; y < height / ysub * 7 / 9; ++y) {
282		for (x = 0; x < width; x += xsub) {
283			u_mem[x*cs/xsub] = colors_middle[x * 7 / width].u;
284			v_mem[x*cs/xsub] = colors_middle[x * 7 / width].v;
285		}
286		u_mem += stride * cs / xsub;
287		v_mem += stride * cs / xsub;
288	}
289
290	for (; y < height / ysub; ++y) {
291		for (x = 0; x < width * 5 / 7; x += xsub) {
292			u_mem[x*cs/xsub] =
293				colors_bottom[x * 4 / (width * 5 / 7)].u;
294			v_mem[x*cs/xsub] =
295				colors_bottom[x * 4 / (width * 5 / 7)].v;
296		}
297		for (; x < width * 6 / 7; x += xsub) {
298			u_mem[x*cs/xsub] = colors_bottom[(x - width * 5 / 7) *
299							 3 / (width / 7) + 4].u;
300			v_mem[x*cs/xsub] = colors_bottom[(x - width * 5 / 7) *
301							 3 / (width / 7) + 4].v;
302		}
303		for (; x < width; x += xsub) {
304			u_mem[x*cs/xsub] = colors_bottom[7].u;
305			v_mem[x*cs/xsub] = colors_bottom[7].v;
306		}
307		u_mem += stride * cs / xsub;
308		v_mem += stride * cs / xsub;
309	}
310}
311
312static void
313fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
314		      unsigned int width, unsigned int height,
315		      unsigned int stride)
316{
317	const struct color_yuv colors_top[] = {
318		MAKE_YUV_601(191, 192, 192),	/* grey */
319		MAKE_YUV_601(192, 192, 0),	/* yellow */
320		MAKE_YUV_601(0, 192, 192),	/* cyan */
321		MAKE_YUV_601(0, 192, 0),	/* green */
322		MAKE_YUV_601(192, 0, 192),	/* magenta */
323		MAKE_YUV_601(192, 0, 0),	/* red */
324		MAKE_YUV_601(0, 0, 192),	/* blue */
325	};
326	const struct color_yuv colors_middle[] = {
327		MAKE_YUV_601(0, 0, 192),	/* blue */
328		MAKE_YUV_601(19, 19, 19),	/* black */
329		MAKE_YUV_601(192, 0, 192),	/* magenta */
330		MAKE_YUV_601(19, 19, 19),	/* black */
331		MAKE_YUV_601(0, 192, 192),	/* cyan */
332		MAKE_YUV_601(19, 19, 19),	/* black */
333		MAKE_YUV_601(192, 192, 192),	/* grey */
334	};
335	const struct color_yuv colors_bottom[] = {
336		MAKE_YUV_601(0, 33, 76),	/* in-phase */
337		MAKE_YUV_601(255, 255, 255),	/* super white */
338		MAKE_YUV_601(50, 0, 106),	/* quadrature */
339		MAKE_YUV_601(19, 19, 19),	/* black */
340		MAKE_YUV_601(9, 9, 9),		/* 3.5% */
341		MAKE_YUV_601(19, 19, 19),	/* 7.5% */
342		MAKE_YUV_601(29, 29, 29),	/* 11.5% */
343		MAKE_YUV_601(19, 19, 19),	/* black */
344	};
345	unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1;
346	unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1;
347	unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0;
348	unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0;
349	unsigned int x;
350	unsigned int y;
351
352	/* Luma */
353	for (y = 0; y < height * 6 / 9; ++y) {
354		for (x = 0; x < width; ++x)
355			y_mem[2*x] = colors_top[x * 7 / width].y;
356		y_mem += stride;
357	}
358
359	for (; y < height * 7 / 9; ++y) {
360		for (x = 0; x < width; ++x)
361			y_mem[2*x] = colors_middle[x * 7 / width].y;
362		y_mem += stride;
363	}
364
365	for (; y < height; ++y) {
366		for (x = 0; x < width * 5 / 7; ++x)
367			y_mem[2*x] = colors_bottom[x * 4 / (width * 5 / 7)].y;
368		for (; x < width * 6 / 7; ++x)
369			y_mem[2*x] = colors_bottom[(x - width * 5 / 7) * 3
370						   / (width / 7) + 4].y;
371		for (; x < width; ++x)
372			y_mem[2*x] = colors_bottom[7].y;
373		y_mem += stride;
374	}
375
376	/* Chroma */
377	for (y = 0; y < height * 6 / 9; ++y) {
378		for (x = 0; x < width; x += 2) {
379			c_mem[2*x+u] = colors_top[x * 7 / width].u;
380			c_mem[2*x+v] = colors_top[x * 7 / width].v;
381		}
382		c_mem += stride;
383	}
384
385	for (; y < height * 7 / 9; ++y) {
386		for (x = 0; x < width; x += 2) {
387			c_mem[2*x+u] = colors_middle[x * 7 / width].u;
388			c_mem[2*x+v] = colors_middle[x * 7 / width].v;
389		}
390		c_mem += stride;
391	}
392
393	for (; y < height; ++y) {
394		for (x = 0; x < width * 5 / 7; x += 2) {
395			c_mem[2*x+u] = colors_bottom[x * 4 / (width * 5 / 7)].u;
396			c_mem[2*x+v] = colors_bottom[x * 4 / (width * 5 / 7)].v;
397		}
398		for (; x < width * 6 / 7; x += 2) {
399			c_mem[2*x+u] = colors_bottom[(x - width * 5 / 7) *
400						     3 / (width / 7) + 4].u;
401			c_mem[2*x+v] = colors_bottom[(x - width * 5 / 7) *
402						     3 / (width / 7) + 4].v;
403		}
404		for (; x < width; x += 2) {
405			c_mem[2*x+u] = colors_bottom[7].u;
406			c_mem[2*x+v] = colors_bottom[7].v;
407		}
408		c_mem += stride;
409	}
410}
411
412static void
413fill_smpte_rgb16(const struct rgb_info *rgb, unsigned char *mem,
414		 unsigned int width, unsigned int height, unsigned int stride)
415{
416	const uint16_t colors_top[] = {
417		MAKE_RGBA(rgb, 192, 192, 192, 255),	/* grey */
418		MAKE_RGBA(rgb, 192, 192, 0, 255),	/* yellow */
419		MAKE_RGBA(rgb, 0, 192, 192, 255),	/* cyan */
420		MAKE_RGBA(rgb, 0, 192, 0, 255),		/* green */
421		MAKE_RGBA(rgb, 192, 0, 192, 255),	/* magenta */
422		MAKE_RGBA(rgb, 192, 0, 0, 255),		/* red */
423		MAKE_RGBA(rgb, 0, 0, 192, 255),		/* blue */
424	};
425	const uint16_t colors_middle[] = {
426		MAKE_RGBA(rgb, 0, 0, 192, 255),		/* blue */
427		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
428		MAKE_RGBA(rgb, 192, 0, 192, 255),	/* magenta */
429		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
430		MAKE_RGBA(rgb, 0, 192, 192, 255),	/* cyan */
431		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
432		MAKE_RGBA(rgb, 192, 192, 192, 255),	/* grey */
433	};
434	const uint16_t colors_bottom[] = {
435		MAKE_RGBA(rgb, 0, 33, 76, 255),		/* in-phase */
436		MAKE_RGBA(rgb, 255, 255, 255, 255),	/* super white */
437		MAKE_RGBA(rgb, 50, 0, 106, 255),	/* quadrature */
438		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
439		MAKE_RGBA(rgb, 9, 9, 9, 255),		/* 3.5% */
440		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* 7.5% */
441		MAKE_RGBA(rgb, 29, 29, 29, 255),	/* 11.5% */
442		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
443	};
444	unsigned int x;
445	unsigned int y;
446
447	for (y = 0; y < height * 6 / 9; ++y) {
448		for (x = 0; x < width; ++x)
449			((uint16_t *)mem)[x] = colors_top[x * 7 / width];
450		mem += stride;
451	}
452
453	for (; y < height * 7 / 9; ++y) {
454		for (x = 0; x < width; ++x)
455			((uint16_t *)mem)[x] = colors_middle[x * 7 / width];
456		mem += stride;
457	}
458
459	for (; y < height; ++y) {
460		for (x = 0; x < width * 5 / 7; ++x)
461			((uint16_t *)mem)[x] =
462				colors_bottom[x * 4 / (width * 5 / 7)];
463		for (; x < width * 6 / 7; ++x)
464			((uint16_t *)mem)[x] =
465				colors_bottom[(x - width * 5 / 7) * 3
466					      / (width / 7) + 4];
467		for (; x < width; ++x)
468			((uint16_t *)mem)[x] = colors_bottom[7];
469		mem += stride;
470	}
471}
472
473static void
474fill_smpte_rgb24(const struct rgb_info *rgb, void *mem,
475		 unsigned int width, unsigned int height, unsigned int stride)
476{
477	const struct color_rgb24 colors_top[] = {
478		MAKE_RGB24(rgb, 192, 192, 192),	/* grey */
479		MAKE_RGB24(rgb, 192, 192, 0),	/* yellow */
480		MAKE_RGB24(rgb, 0, 192, 192),	/* cyan */
481		MAKE_RGB24(rgb, 0, 192, 0),	/* green */
482		MAKE_RGB24(rgb, 192, 0, 192),	/* magenta */
483		MAKE_RGB24(rgb, 192, 0, 0),	/* red */
484		MAKE_RGB24(rgb, 0, 0, 192),	/* blue */
485	};
486	const struct color_rgb24 colors_middle[] = {
487		MAKE_RGB24(rgb, 0, 0, 192),	/* blue */
488		MAKE_RGB24(rgb, 19, 19, 19),	/* black */
489		MAKE_RGB24(rgb, 192, 0, 192),	/* magenta */
490		MAKE_RGB24(rgb, 19, 19, 19),	/* black */
491		MAKE_RGB24(rgb, 0, 192, 192),	/* cyan */
492		MAKE_RGB24(rgb, 19, 19, 19),	/* black */
493		MAKE_RGB24(rgb, 192, 192, 192),	/* grey */
494	};
495	const struct color_rgb24 colors_bottom[] = {
496		MAKE_RGB24(rgb, 0, 33, 76),	/* in-phase */
497		MAKE_RGB24(rgb, 255, 255, 255),	/* super white */
498		MAKE_RGB24(rgb, 50, 0, 106),	/* quadrature */
499		MAKE_RGB24(rgb, 19, 19, 19),	/* black */
500		MAKE_RGB24(rgb, 9, 9, 9),	/* 3.5% */
501		MAKE_RGB24(rgb, 19, 19, 19),	/* 7.5% */
502		MAKE_RGB24(rgb, 29, 29, 29),	/* 11.5% */
503		MAKE_RGB24(rgb, 19, 19, 19),	/* black */
504	};
505	unsigned int x;
506	unsigned int y;
507
508	for (y = 0; y < height * 6 / 9; ++y) {
509		for (x = 0; x < width; ++x)
510			((struct color_rgb24 *)mem)[x] =
511				colors_top[x * 7 / width];
512		mem += stride;
513	}
514
515	for (; y < height * 7 / 9; ++y) {
516		for (x = 0; x < width; ++x)
517			((struct color_rgb24 *)mem)[x] =
518				colors_middle[x * 7 / width];
519		mem += stride;
520	}
521
522	for (; y < height; ++y) {
523		for (x = 0; x < width * 5 / 7; ++x)
524			((struct color_rgb24 *)mem)[x] =
525				colors_bottom[x * 4 / (width * 5 / 7)];
526		for (; x < width * 6 / 7; ++x)
527			((struct color_rgb24 *)mem)[x] =
528				colors_bottom[(x - width * 5 / 7) * 3
529					      / (width / 7) + 4];
530		for (; x < width; ++x)
531			((struct color_rgb24 *)mem)[x] = colors_bottom[7];
532		mem += stride;
533	}
534}
535
536static void
537fill_smpte_rgb32(const struct rgb_info *rgb, unsigned char *mem,
538		 unsigned int width, unsigned int height, unsigned int stride)
539{
540	const uint32_t colors_top[] = {
541		MAKE_RGBA(rgb, 192, 192, 192, 255),	/* grey */
542		MAKE_RGBA(rgb, 192, 192, 0, 255),	/* yellow */
543		MAKE_RGBA(rgb, 0, 192, 192, 255),	/* cyan */
544		MAKE_RGBA(rgb, 0, 192, 0, 255),		/* green */
545		MAKE_RGBA(rgb, 192, 0, 192, 255),	/* magenta */
546		MAKE_RGBA(rgb, 192, 0, 0, 255),		/* red */
547		MAKE_RGBA(rgb, 0, 0, 192, 255),		/* blue */
548	};
549	const uint32_t colors_middle[] = {
550		MAKE_RGBA(rgb, 0, 0, 192, 255),		/* blue */
551		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
552		MAKE_RGBA(rgb, 192, 0, 192, 255),	/* magenta */
553		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
554		MAKE_RGBA(rgb, 0, 192, 192, 255),	/* cyan */
555		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
556		MAKE_RGBA(rgb, 192, 192, 192, 255),	/* grey */
557	};
558	const uint32_t colors_bottom[] = {
559		MAKE_RGBA(rgb, 0, 33, 76, 255),		/* in-phase */
560		MAKE_RGBA(rgb, 255, 255, 255, 255),	/* super white */
561		MAKE_RGBA(rgb, 50, 0, 106, 255),	/* quadrature */
562		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
563		MAKE_RGBA(rgb, 9, 9, 9, 255),		/* 3.5% */
564		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* 7.5% */
565		MAKE_RGBA(rgb, 29, 29, 29, 255),	/* 11.5% */
566		MAKE_RGBA(rgb, 19, 19, 19, 255),	/* black */
567	};
568	unsigned int x;
569	unsigned int y;
570
571	for (y = 0; y < height * 6 / 9; ++y) {
572		for (x = 0; x < width; ++x)
573			((uint32_t *)mem)[x] = colors_top[x * 7 / width];
574		mem += stride;
575	}
576
577	for (; y < height * 7 / 9; ++y) {
578		for (x = 0; x < width; ++x)
579			((uint32_t *)mem)[x] = colors_middle[x * 7 / width];
580		mem += stride;
581	}
582
583	for (; y < height; ++y) {
584		for (x = 0; x < width * 5 / 7; ++x)
585			((uint32_t *)mem)[x] =
586				colors_bottom[x * 4 / (width * 5 / 7)];
587		for (; x < width * 6 / 7; ++x)
588			((uint32_t *)mem)[x] =
589				colors_bottom[(x - width * 5 / 7) * 3
590					      / (width / 7) + 4];
591		for (; x < width; ++x)
592			((uint32_t *)mem)[x] = colors_bottom[7];
593		mem += stride;
594	}
595}
596
597static void
598fill_smpte(const struct format_info *info, void *planes[3], unsigned int width,
599	   unsigned int height, unsigned int stride)
600{
601	unsigned char *u, *v;
602
603	switch (info->format) {
604	case DRM_FORMAT_UYVY:
605	case DRM_FORMAT_VYUY:
606	case DRM_FORMAT_YUYV:
607	case DRM_FORMAT_YVYU:
608		return fill_smpte_yuv_packed(&info->yuv, planes[0], width,
609					     height, stride);
610
611	case DRM_FORMAT_NV12:
612	case DRM_FORMAT_NV21:
613	case DRM_FORMAT_NV16:
614	case DRM_FORMAT_NV61:
615		u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1;
616		v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1;
617		return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v,
618					     width, height, stride);
619
620	case DRM_FORMAT_YUV420:
621		return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1],
622					     planes[2], width, height, stride);
623
624	case DRM_FORMAT_YVU420:
625		return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[2],
626					     planes[1], width, height, stride);
627
628	case DRM_FORMAT_ARGB4444:
629	case DRM_FORMAT_XRGB4444:
630	case DRM_FORMAT_ABGR4444:
631	case DRM_FORMAT_XBGR4444:
632	case DRM_FORMAT_RGBA4444:
633	case DRM_FORMAT_RGBX4444:
634	case DRM_FORMAT_BGRA4444:
635	case DRM_FORMAT_BGRX4444:
636	case DRM_FORMAT_RGB565:
637	case DRM_FORMAT_BGR565:
638	case DRM_FORMAT_ARGB1555:
639	case DRM_FORMAT_XRGB1555:
640	case DRM_FORMAT_ABGR1555:
641	case DRM_FORMAT_XBGR1555:
642	case DRM_FORMAT_RGBA5551:
643	case DRM_FORMAT_RGBX5551:
644	case DRM_FORMAT_BGRA5551:
645	case DRM_FORMAT_BGRX5551:
646		return fill_smpte_rgb16(&info->rgb, planes[0],
647					width, height, stride);
648
649	case DRM_FORMAT_BGR888:
650	case DRM_FORMAT_RGB888:
651		return fill_smpte_rgb24(&info->rgb, planes[0],
652					width, height, stride);
653	case DRM_FORMAT_ARGB8888:
654	case DRM_FORMAT_XRGB8888:
655	case DRM_FORMAT_ABGR8888:
656	case DRM_FORMAT_XBGR8888:
657	case DRM_FORMAT_RGBA8888:
658	case DRM_FORMAT_RGBX8888:
659	case DRM_FORMAT_BGRA8888:
660	case DRM_FORMAT_BGRX8888:
661	case DRM_FORMAT_ARGB2101010:
662	case DRM_FORMAT_XRGB2101010:
663	case DRM_FORMAT_ABGR2101010:
664	case DRM_FORMAT_XBGR2101010:
665	case DRM_FORMAT_RGBA1010102:
666	case DRM_FORMAT_RGBX1010102:
667	case DRM_FORMAT_BGRA1010102:
668	case DRM_FORMAT_BGRX1010102:
669		return fill_smpte_rgb32(&info->rgb, planes[0],
670					width, height, stride);
671	}
672}
673
674/* swap these for big endian.. */
675#define RED   2
676#define GREEN 1
677#define BLUE  0
678
679static void
680make_pwetty(void *data, int width, int height, int stride, uint32_t format)
681{
682#ifdef HAVE_CAIRO
683	cairo_surface_t *surface;
684	cairo_t *cr;
685	int x, y;
686	cairo_format_t cairo_format;
687
688	/* we can ignore the order of R,G,B channels */
689	switch (format) {
690	case DRM_FORMAT_XRGB8888:
691	case DRM_FORMAT_ARGB8888:
692	case DRM_FORMAT_XBGR8888:
693	case DRM_FORMAT_ABGR8888:
694		cairo_format = CAIRO_FORMAT_ARGB32;
695		break;
696	case DRM_FORMAT_RGB565:
697	case DRM_FORMAT_BGR565:
698		cairo_format = CAIRO_FORMAT_RGB16_565;
699		break;
700	default:
701		return;
702	}
703
704	surface = cairo_image_surface_create_for_data(data,
705						      cairo_format,
706						      width, height,
707						      stride);
708	cr = cairo_create(surface);
709	cairo_surface_destroy(surface);
710
711	cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
712	for (x = 0; x < width; x += 250)
713		for (y = 0; y < height; y += 250) {
714			char buf[64];
715
716			cairo_move_to(cr, x, y - 20);
717			cairo_line_to(cr, x, y + 20);
718			cairo_move_to(cr, x - 20, y);
719			cairo_line_to(cr, x + 20, y);
720			cairo_new_sub_path(cr);
721			cairo_arc(cr, x, y, 10, 0, M_PI * 2);
722			cairo_set_line_width(cr, 4);
723			cairo_set_source_rgb(cr, 0, 0, 0);
724			cairo_stroke_preserve(cr);
725			cairo_set_source_rgb(cr, 1, 1, 1);
726			cairo_set_line_width(cr, 2);
727			cairo_stroke(cr);
728
729			snprintf(buf, sizeof buf, "%d, %d", x, y);
730			cairo_move_to(cr, x + 20, y + 20);
731			cairo_text_path(cr, buf);
732			cairo_set_source_rgb(cr, 0, 0, 0);
733			cairo_stroke_preserve(cr);
734			cairo_set_source_rgb(cr, 1, 1, 1);
735			cairo_fill(cr);
736		}
737
738	cairo_destroy(cr);
739#endif
740}
741
742static void
743fill_tiles_yuv_planar(const struct format_info *info,
744		      unsigned char *y_mem, unsigned char *u_mem,
745		      unsigned char *v_mem, unsigned int width,
746		      unsigned int height, unsigned int stride)
747{
748	const struct yuv_info *yuv = &info->yuv;
749	unsigned int cs = yuv->chroma_stride;
750	unsigned int xsub = yuv->xsub;
751	unsigned int ysub = yuv->ysub;
752	unsigned int x;
753	unsigned int y;
754
755	for (y = 0; y < height; ++y) {
756		for (x = 0; x < width; ++x) {
757			div_t d = div(x+y, width);
758			uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
759				       + 0x000a1120 * (d.rem >> 6);
760			struct color_yuv color =
761				MAKE_YUV_601((rgb32 >> 16) & 0xff,
762					     (rgb32 >> 8) & 0xff, rgb32 & 0xff);
763
764			y_mem[x] = color.y;
765			u_mem[x/xsub*cs] = color.u;
766			v_mem[x/xsub*cs] = color.v;
767		}
768
769		y_mem += stride;
770		if ((y + 1) % ysub == 0) {
771			u_mem += stride * cs / xsub;
772			v_mem += stride * cs / xsub;
773		}
774	}
775}
776
777static void
778fill_tiles_yuv_packed(const struct format_info *info, unsigned char *mem,
779		      unsigned int width, unsigned int height,
780		      unsigned int stride)
781{
782	const struct yuv_info *yuv = &info->yuv;
783	unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1;
784	unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1;
785	unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0;
786	unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0;
787	unsigned int x;
788	unsigned int y;
789
790	for (y = 0; y < height; ++y) {
791		for (x = 0; x < width; x += 2) {
792			div_t d = div(x+y, width);
793			uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
794				       + 0x000a1120 * (d.rem >> 6);
795			struct color_yuv color =
796				MAKE_YUV_601((rgb32 >> 16) & 0xff,
797					     (rgb32 >> 8) & 0xff, rgb32 & 0xff);
798
799			y_mem[2*x] = color.y;
800			c_mem[2*x+u] = color.u;
801			y_mem[2*x+2] = color.y;
802			c_mem[2*x+v] = color.v;
803		}
804
805		y_mem += stride;
806		c_mem += stride;
807	}
808}
809
810static void
811fill_tiles_rgb16(const struct format_info *info, unsigned char *mem,
812		 unsigned int width, unsigned int height, unsigned int stride)
813{
814	const struct rgb_info *rgb = &info->rgb;
815	unsigned char *mem_base = mem;
816	unsigned int x, y;
817
818	for (y = 0; y < height; ++y) {
819		for (x = 0; x < width; ++x) {
820			div_t d = div(x+y, width);
821			uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
822				       + 0x000a1120 * (d.rem >> 6);
823			uint16_t color =
824				MAKE_RGBA(rgb, (rgb32 >> 16) & 0xff,
825					  (rgb32 >> 8) & 0xff, rgb32 & 0xff,
826					  255);
827
828			((uint16_t *)mem)[x] = color;
829		}
830		mem += stride;
831	}
832
833	make_pwetty(mem_base, width, height, stride, info->format);
834}
835
836static void
837fill_tiles_rgb24(const struct format_info *info, unsigned char *mem,
838		 unsigned int width, unsigned int height, unsigned int stride)
839{
840	const struct rgb_info *rgb = &info->rgb;
841	unsigned int x, y;
842
843	for (y = 0; y < height; ++y) {
844		for (x = 0; x < width; ++x) {
845			div_t d = div(x+y, width);
846			uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
847				       + 0x000a1120 * (d.rem >> 6);
848			struct color_rgb24 color =
849				MAKE_RGB24(rgb, (rgb32 >> 16) & 0xff,
850					   (rgb32 >> 8) & 0xff, rgb32 & 0xff);
851
852			((struct color_rgb24 *)mem)[x] = color;
853		}
854		mem += stride;
855	}
856}
857
858static void
859fill_tiles_rgb32(const struct format_info *info, unsigned char *mem,
860		 unsigned int width, unsigned int height, unsigned int stride)
861{
862	const struct rgb_info *rgb = &info->rgb;
863	unsigned char *mem_base = mem;
864	unsigned int x, y;
865
866	for (y = 0; y < height; ++y) {
867		for (x = 0; x < width; ++x) {
868			div_t d = div(x+y, width);
869			uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
870				       + 0x000a1120 * (d.rem >> 6);
871			uint32_t alpha = ((y < height/2) && (x < width/2)) ? 127 : 255;
872			uint32_t color =
873				MAKE_RGBA(rgb, (rgb32 >> 16) & 0xff,
874					  (rgb32 >> 8) & 0xff, rgb32 & 0xff,
875					  alpha);
876
877			((uint32_t *)mem)[x] = color;
878		}
879		mem += stride;
880	}
881
882	make_pwetty(mem_base, width, height, stride, info->format);
883}
884
885static void
886fill_tiles(const struct format_info *info, void *planes[3], unsigned int width,
887	   unsigned int height, unsigned int stride)
888{
889	unsigned char *u, *v;
890
891	switch (info->format) {
892	case DRM_FORMAT_UYVY:
893	case DRM_FORMAT_VYUY:
894	case DRM_FORMAT_YUYV:
895	case DRM_FORMAT_YVYU:
896		return fill_tiles_yuv_packed(info, planes[0],
897					     width, height, stride);
898
899	case DRM_FORMAT_NV12:
900	case DRM_FORMAT_NV21:
901	case DRM_FORMAT_NV16:
902	case DRM_FORMAT_NV61:
903		u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1;
904		v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1;
905		return fill_tiles_yuv_planar(info, planes[0], u, v,
906					     width, height, stride);
907
908	case DRM_FORMAT_YUV420:
909		return fill_tiles_yuv_planar(info, planes[0], planes[1],
910					     planes[2], width, height, stride);
911
912	case DRM_FORMAT_YVU420:
913		return fill_tiles_yuv_planar(info, planes[0], planes[2],
914					     planes[1], width, height, stride);
915
916	case DRM_FORMAT_ARGB4444:
917	case DRM_FORMAT_XRGB4444:
918	case DRM_FORMAT_ABGR4444:
919	case DRM_FORMAT_XBGR4444:
920	case DRM_FORMAT_RGBA4444:
921	case DRM_FORMAT_RGBX4444:
922	case DRM_FORMAT_BGRA4444:
923	case DRM_FORMAT_BGRX4444:
924	case DRM_FORMAT_RGB565:
925	case DRM_FORMAT_BGR565:
926	case DRM_FORMAT_ARGB1555:
927	case DRM_FORMAT_XRGB1555:
928	case DRM_FORMAT_ABGR1555:
929	case DRM_FORMAT_XBGR1555:
930	case DRM_FORMAT_RGBA5551:
931	case DRM_FORMAT_RGBX5551:
932	case DRM_FORMAT_BGRA5551:
933	case DRM_FORMAT_BGRX5551:
934		return fill_tiles_rgb16(info, planes[0],
935					width, height, stride);
936
937	case DRM_FORMAT_BGR888:
938	case DRM_FORMAT_RGB888:
939		return fill_tiles_rgb24(info, planes[0],
940					width, height, stride);
941	case DRM_FORMAT_ARGB8888:
942	case DRM_FORMAT_XRGB8888:
943	case DRM_FORMAT_ABGR8888:
944	case DRM_FORMAT_XBGR8888:
945	case DRM_FORMAT_RGBA8888:
946	case DRM_FORMAT_RGBX8888:
947	case DRM_FORMAT_BGRA8888:
948	case DRM_FORMAT_BGRX8888:
949	case DRM_FORMAT_ARGB2101010:
950	case DRM_FORMAT_XRGB2101010:
951	case DRM_FORMAT_ABGR2101010:
952	case DRM_FORMAT_XBGR2101010:
953	case DRM_FORMAT_RGBA1010102:
954	case DRM_FORMAT_RGBX1010102:
955	case DRM_FORMAT_BGRA1010102:
956	case DRM_FORMAT_BGRX1010102:
957		return fill_tiles_rgb32(info, planes[0],
958					width, height, stride);
959	}
960}
961
962static void
963fill_plain(const struct format_info *info, void *planes[3], unsigned int width,
964	   unsigned int height, unsigned int stride)
965{
966	memset(planes[0], 0x77, stride * height);
967}
968
969/*
970 * fill_pattern - Fill a buffer with a test pattern
971 * @format: Pixel format
972 * @pattern: Test pattern
973 * @buffer: Buffer memory
974 * @width: Width in pixels
975 * @height: Height in pixels
976 * @stride: Line stride (pitch) in bytes
977 *
978 * Fill the buffer with the test pattern specified by the pattern parameter.
979 * Supported formats vary depending on the selected pattern.
980 */
981static void
982fill_pattern(unsigned int format, enum fill_pattern pattern, void *planes[3],
983	     unsigned int width, unsigned int height, unsigned int stride)
984{
985	const struct format_info *info = NULL;
986	unsigned int i;
987
988	for (i = 0; i < ARRAY_SIZE(format_info); ++i) {
989		if (format_info[i].format == format) {
990			info = &format_info[i];
991			break;
992		}
993	}
994
995	if (info == NULL)
996		return;
997
998	switch (pattern) {
999	case PATTERN_TILES:
1000		return fill_tiles(info, planes, width, height, stride);
1001
1002	case PATTERN_SMPTE:
1003		return fill_smpte(info, planes, width, height, stride);
1004
1005	case PATTERN_PLAIN:
1006		return fill_plain(info, planes, width, height, stride);
1007
1008	default:
1009		printf("Error: unsupported test pattern %u.\n", pattern);
1010		break;
1011	}
1012}
1013
1014/* -----------------------------------------------------------------------------
1015 * Buffers management
1016 */
1017
1018static struct bo *
1019bo_create_dumb(int fd, unsigned int width, unsigned int height, unsigned int bpp)
1020{
1021	struct drm_mode_create_dumb arg;
1022	struct bo *bo;
1023	int ret;
1024
1025	bo = malloc(sizeof(*bo));
1026	if (bo == NULL) {
1027		fprintf(stderr, "failed to allocate buffer object\n");
1028		return NULL;
1029	}
1030
1031	memset(&arg, 0, sizeof(arg));
1032	arg.bpp = bpp;
1033	arg.width = width;
1034	arg.height = height;
1035
1036	ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
1037	if (ret) {
1038		fprintf(stderr, "failed to create dumb buffer: %s\n",
1039			strerror(errno));
1040		free(bo);
1041		return NULL;
1042	}
1043
1044	bo->fd = fd;
1045	bo->handle = arg.handle;
1046	bo->size = arg.size;
1047	bo->pitch = arg.pitch;
1048
1049	return bo;
1050}
1051
1052static int bo_map(struct bo *bo, void **out)
1053{
1054	struct drm_mode_map_dumb arg;
1055	void *map;
1056	int ret;
1057
1058	memset(&arg, 0, sizeof(arg));
1059	arg.handle = bo->handle;
1060
1061	ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
1062	if (ret)
1063		return ret;
1064
1065	map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
1066		       bo->fd, arg.offset);
1067	if (map == MAP_FAILED)
1068		return -EINVAL;
1069
1070	bo->ptr = map;
1071	*out = map;
1072
1073	return 0;
1074}
1075
1076static void bo_unmap(struct bo *bo)
1077{
1078	if (!bo->ptr)
1079		return;
1080
1081	drm_munmap(bo->ptr, bo->size);
1082	bo->ptr = NULL;
1083}
1084
1085struct bo *
1086bo_create(int fd, unsigned int format,
1087	  unsigned int width, unsigned int height,
1088	  unsigned int handles[4], unsigned int pitches[4],
1089	  unsigned int offsets[4], enum fill_pattern pattern)
1090{
1091	unsigned int virtual_height;
1092	struct bo *bo;
1093	unsigned int bpp;
1094	void *planes[3] = { 0, };
1095	void *virtual;
1096	int ret;
1097
1098	switch (format) {
1099	case DRM_FORMAT_NV12:
1100	case DRM_FORMAT_NV21:
1101	case DRM_FORMAT_NV16:
1102	case DRM_FORMAT_NV61:
1103	case DRM_FORMAT_YUV420:
1104	case DRM_FORMAT_YVU420:
1105		bpp = 8;
1106		break;
1107
1108	case DRM_FORMAT_ARGB4444:
1109	case DRM_FORMAT_XRGB4444:
1110	case DRM_FORMAT_ABGR4444:
1111	case DRM_FORMAT_XBGR4444:
1112	case DRM_FORMAT_RGBA4444:
1113	case DRM_FORMAT_RGBX4444:
1114	case DRM_FORMAT_BGRA4444:
1115	case DRM_FORMAT_BGRX4444:
1116	case DRM_FORMAT_ARGB1555:
1117	case DRM_FORMAT_XRGB1555:
1118	case DRM_FORMAT_ABGR1555:
1119	case DRM_FORMAT_XBGR1555:
1120	case DRM_FORMAT_RGBA5551:
1121	case DRM_FORMAT_RGBX5551:
1122	case DRM_FORMAT_BGRA5551:
1123	case DRM_FORMAT_BGRX5551:
1124	case DRM_FORMAT_RGB565:
1125	case DRM_FORMAT_BGR565:
1126	case DRM_FORMAT_UYVY:
1127	case DRM_FORMAT_VYUY:
1128	case DRM_FORMAT_YUYV:
1129	case DRM_FORMAT_YVYU:
1130		bpp = 16;
1131		break;
1132
1133	case DRM_FORMAT_BGR888:
1134	case DRM_FORMAT_RGB888:
1135		bpp = 24;
1136		break;
1137
1138	case DRM_FORMAT_ARGB8888:
1139	case DRM_FORMAT_XRGB8888:
1140	case DRM_FORMAT_ABGR8888:
1141	case DRM_FORMAT_XBGR8888:
1142	case DRM_FORMAT_RGBA8888:
1143	case DRM_FORMAT_RGBX8888:
1144	case DRM_FORMAT_BGRA8888:
1145	case DRM_FORMAT_BGRX8888:
1146	case DRM_FORMAT_ARGB2101010:
1147	case DRM_FORMAT_XRGB2101010:
1148	case DRM_FORMAT_ABGR2101010:
1149	case DRM_FORMAT_XBGR2101010:
1150	case DRM_FORMAT_RGBA1010102:
1151	case DRM_FORMAT_RGBX1010102:
1152	case DRM_FORMAT_BGRA1010102:
1153	case DRM_FORMAT_BGRX1010102:
1154		bpp = 32;
1155		break;
1156
1157	default:
1158		fprintf(stderr, "unsupported format 0x%08x\n",  format);
1159		return NULL;
1160	}
1161
1162	switch (format) {
1163	case DRM_FORMAT_NV12:
1164	case DRM_FORMAT_NV21:
1165		virtual_height = height * 3 / 2;
1166		break;
1167
1168	case DRM_FORMAT_NV16:
1169	case DRM_FORMAT_NV61:
1170		virtual_height = height * 2;
1171		break;
1172
1173	default:
1174		virtual_height = height;
1175		break;
1176	}
1177
1178	bo = bo_create_dumb(fd, width, virtual_height, bpp);
1179	if (!bo)
1180		return NULL;
1181
1182	ret = bo_map(bo, &virtual);
1183	if (ret) {
1184		fprintf(stderr, "failed to map buffer: %s\n",
1185			strerror(-errno));
1186		bo_destroy(bo);
1187		return NULL;
1188	}
1189
1190	/* just testing a limited # of formats to test single
1191	 * and multi-planar path.. would be nice to add more..
1192	 */
1193	switch (format) {
1194	case DRM_FORMAT_UYVY:
1195	case DRM_FORMAT_VYUY:
1196	case DRM_FORMAT_YUYV:
1197	case DRM_FORMAT_YVYU:
1198		offsets[0] = 0;
1199		handles[0] = bo->handle;
1200		pitches[0] = bo->pitch;
1201
1202		planes[0] = virtual;
1203		break;
1204
1205	case DRM_FORMAT_NV12:
1206	case DRM_FORMAT_NV21:
1207	case DRM_FORMAT_NV16:
1208	case DRM_FORMAT_NV61:
1209		offsets[0] = 0;
1210		handles[0] = bo->handle;
1211		pitches[0] = bo->pitch;
1212		pitches[1] = pitches[0];
1213		offsets[1] = pitches[0] * height;
1214		handles[1] = bo->handle;
1215
1216		planes[0] = virtual;
1217		planes[1] = virtual + offsets[1];
1218		break;
1219
1220	case DRM_FORMAT_YUV420:
1221	case DRM_FORMAT_YVU420:
1222		offsets[0] = 0;
1223		handles[0] = bo->handle;
1224		pitches[0] = bo->pitch;
1225		pitches[1] = pitches[0] / 2;
1226		offsets[1] = pitches[0] * height;
1227		handles[1] = bo->handle;
1228		pitches[2] = pitches[1];
1229		offsets[2] = offsets[1] + pitches[1] * height / 2;
1230		handles[2] = bo->handle;
1231
1232		planes[0] = virtual;
1233		planes[1] = virtual + offsets[1];
1234		planes[2] = virtual + offsets[2];
1235		break;
1236
1237	case DRM_FORMAT_ARGB4444:
1238	case DRM_FORMAT_XRGB4444:
1239	case DRM_FORMAT_ABGR4444:
1240	case DRM_FORMAT_XBGR4444:
1241	case DRM_FORMAT_RGBA4444:
1242	case DRM_FORMAT_RGBX4444:
1243	case DRM_FORMAT_BGRA4444:
1244	case DRM_FORMAT_BGRX4444:
1245	case DRM_FORMAT_ARGB1555:
1246	case DRM_FORMAT_XRGB1555:
1247	case DRM_FORMAT_ABGR1555:
1248	case DRM_FORMAT_XBGR1555:
1249	case DRM_FORMAT_RGBA5551:
1250	case DRM_FORMAT_RGBX5551:
1251	case DRM_FORMAT_BGRA5551:
1252	case DRM_FORMAT_BGRX5551:
1253	case DRM_FORMAT_RGB565:
1254	case DRM_FORMAT_BGR565:
1255	case DRM_FORMAT_BGR888:
1256	case DRM_FORMAT_RGB888:
1257	case DRM_FORMAT_ARGB8888:
1258	case DRM_FORMAT_XRGB8888:
1259	case DRM_FORMAT_ABGR8888:
1260	case DRM_FORMAT_XBGR8888:
1261	case DRM_FORMAT_RGBA8888:
1262	case DRM_FORMAT_RGBX8888:
1263	case DRM_FORMAT_BGRA8888:
1264	case DRM_FORMAT_BGRX8888:
1265	case DRM_FORMAT_ARGB2101010:
1266	case DRM_FORMAT_XRGB2101010:
1267	case DRM_FORMAT_ABGR2101010:
1268	case DRM_FORMAT_XBGR2101010:
1269	case DRM_FORMAT_RGBA1010102:
1270	case DRM_FORMAT_RGBX1010102:
1271	case DRM_FORMAT_BGRA1010102:
1272	case DRM_FORMAT_BGRX1010102:
1273		offsets[0] = 0;
1274		handles[0] = bo->handle;
1275		pitches[0] = bo->pitch;
1276
1277		planes[0] = virtual;
1278		break;
1279	}
1280
1281	fill_pattern(format, pattern, planes, width, height, pitches[0]);
1282	bo_unmap(bo);
1283
1284	return bo;
1285}
1286
1287void bo_destroy(struct bo *bo)
1288{
1289	struct drm_mode_destroy_dumb arg;
1290	int ret;
1291
1292	memset(&arg, 0, sizeof(arg));
1293	arg.handle = bo->handle;
1294
1295	ret = drmIoctl(bo->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
1296	if (ret)
1297		fprintf(stderr, "failed to destroy dumb buffer: %s\n",
1298			strerror(errno));
1299
1300	free(bo);
1301}
1302