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