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