1 /**************************************************************************
2  *
3  * Copyright 2009 Younes Manton.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 /* Force assertions, even on release builds. */
29 #undef NDEBUG
30 #include <assert.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <sys/time.h>
35 #include "testlib.h"
36 
37 #define MACROBLOCK_WIDTH		16
38 #define MACROBLOCK_HEIGHT		16
39 #define BLOCKS_PER_MACROBLOCK		6
40 
41 #define DEFAULT_INPUT_WIDTH		720
42 #define DEFAULT_INPUT_HEIGHT		480
43 #define DEFAULT_REPS			100
44 
45 #define PIPELINE_STEP_MC		1
46 #define PIPELINE_STEP_CSC		2
47 #define PIPELINE_STEP_SWAP		4
48 
49 #define MB_TYPE_I			1
50 #define MB_TYPE_P			2
51 #define MB_TYPE_B			4
52 
53 struct Config
54 {
55 	unsigned int input_width;
56 	unsigned int input_height;
57 	unsigned int output_width;
58 	unsigned int output_height;
59 	unsigned int pipeline;
60 	unsigned int mb_types;
61 	unsigned int reps;
62 };
63 
64 void ParseArgs(int argc, char **argv, struct Config *config);
65 
ParseArgs(int argc,char ** argv,struct Config * config)66 void ParseArgs(int argc, char **argv, struct Config *config)
67 {
68 	int fail = 0;
69 	int i;
70 
71 	config->input_width = DEFAULT_INPUT_WIDTH;
72 	config->input_height = DEFAULT_INPUT_HEIGHT;
73 	config->output_width = 0;
74 	config->output_height = 0;
75 	config->pipeline = 0;
76 	config->mb_types = 0;
77 	config->reps = DEFAULT_REPS;
78 
79 	for (i = 1; i < argc && !fail; ++i)
80 	{
81 		if (!strcmp(argv[i], "-iw"))
82 		{
83 			if (sscanf(argv[++i], "%u", &config->input_width) != 1)
84 				fail = 1;
85 		}
86 		else if (!strcmp(argv[i], "-ih"))
87 		{
88 			if (sscanf(argv[++i], "%u", &config->input_height) != 1)
89 				fail = 1;
90 		}
91 		else if (!strcmp(argv[i], "-ow"))
92 		{
93 			if (sscanf(argv[++i], "%u", &config->output_width) != 1)
94 				fail = 1;
95 		}
96 		else if (!strcmp(argv[i], "-oh"))
97 		{
98 			if (sscanf(argv[++i], "%u", &config->output_height) != 1)
99 				fail = 1;
100 		}
101 		else if (!strcmp(argv[i], "-p"))
102 		{
103 			char *token = strtok(argv[++i], ",");
104 
105 			while (token && !fail)
106 			{
107 				if (!strcmp(token, "mc"))
108 					config->pipeline |= PIPELINE_STEP_MC;
109 				else if (!strcmp(token, "csc"))
110 					config->pipeline |= PIPELINE_STEP_CSC;
111 				else if (!strcmp(token, "swp"))
112 					config->pipeline |= PIPELINE_STEP_SWAP;
113 				else
114 					fail = 1;
115 
116 				if (!fail)
117 					token = strtok(NULL, ",");
118 			}
119 		}
120 		else if (!strcmp(argv[i], "-mb"))
121 		{
122 			char *token = strtok(argv[++i], ",");
123 
124 			while (token && !fail)
125 			{
126 				if (strcmp(token, "i") == 0)
127 					config->mb_types |= MB_TYPE_I;
128 				else if (strcmp(token, "p") == 0)
129 					config->mb_types |= MB_TYPE_P;
130 				else if (strcmp(token, "b") == 0)
131 					config->mb_types |= MB_TYPE_B;
132 				else
133 					fail = 1;
134 
135 				if (!fail)
136 					token = strtok(NULL, ",");
137 			}
138 		}
139 		else if (!strcmp(argv[i], "-r"))
140 		{
141 			if (sscanf(argv[++i], "%u", &config->reps) != 1)
142 				fail = 1;
143 		}
144 		else
145 			fail = 1;
146 	}
147 
148 	if (fail)
149 	{
150 		fprintf(
151 			stderr,
152 			"Bad argument.\n"
153 			"\n"
154 			"Usage: %s [options]\n"
155 			"\t-iw <width>\tInput width\n"
156 			"\t-ih <height>\tInput height\n"
157 			"\t-ow <width>\tOutput width\n"
158 			"\t-oh <height>\tOutput height\n"
159 			"\t-p <pipeline>\tPipeline to test\n"
160 			"\t-mb <mb type>\tMacroBlock types to use\n"
161 			"\t-r <reps>\tRepetitions\n\n"
162 			"\tPipeline steps: mc,csc,swap\n"
163 			"\tMB types: i,p,b\n",
164 			argv[0]
165 		);
166 		exit(1);
167 	}
168 
169 	if (config->output_width == 0)
170 		config->output_width = config->input_width;
171 	if (config->output_height == 0)
172 		config->output_height = config->input_height;
173 	if (!config->pipeline)
174 		config->pipeline = PIPELINE_STEP_MC | PIPELINE_STEP_CSC | PIPELINE_STEP_SWAP;
175 	if (!config->mb_types)
176 		config->mb_types = MB_TYPE_I | MB_TYPE_P | MB_TYPE_B;
177 }
178 
main(int argc,char ** argv)179 int main(int argc, char **argv)
180 {
181 	struct Config		config;
182 	Display			*display;
183 	Window			root, window;
184 	const unsigned int	mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
185 	XvPortID		port_num;
186 	int			surface_type_id;
187 	unsigned int		is_overlay, intra_unsigned;
188 	int			colorkey;
189 	XvMCContext		context;
190 	XvMCSurface		surface;
191 	XvMCBlockArray		block_array;
192 	XvMCMacroBlockArray	mb_array;
193 	unsigned int		mbw, mbh;
194 	unsigned int		mbx, mby;
195 	unsigned int		reps;
196 	struct timeval		start, stop, diff;
197 	double			diff_secs;
198 
199 	ParseArgs(argc, argv, &config);
200 
201 	mbw = align(config.input_width, MACROBLOCK_WIDTH) / MACROBLOCK_WIDTH;
202 	mbh = align(config.input_height, MACROBLOCK_HEIGHT) / MACROBLOCK_HEIGHT;
203 
204 	display = XOpenDisplay(NULL);
205 
206 	if (!GetPort
207 	(
208 		display,
209 		config.input_width,
210 		config.input_height,
211 		XVMC_CHROMA_FORMAT_420,
212 		mc_types,
213 		2,
214 		&port_num,
215 		&surface_type_id,
216 		&is_overlay,
217 		&intra_unsigned
218 	))
219 	{
220 		XCloseDisplay(display);
221 		fprintf(stderr, "Error, unable to find a good port.\n");
222 		exit(1);
223 	}
224 
225 	if (is_overlay)
226 	{
227 		Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
228 		XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
229 	}
230 	else
231 	{
232 		colorkey = 0;
233 	}
234 
235 	root = XDefaultRootWindow(display);
236 	window = XCreateSimpleWindow(display, root, 0, 0, config.output_width, config.output_height, 0, 0, colorkey);
237 
238 	assert(XvMCCreateContext(display, port_num, surface_type_id, config.input_width, config.input_height, XVMC_DIRECT, &context) == Success);
239 	assert(XvMCCreateSurface(display, &context, &surface) == Success);
240 	assert(XvMCCreateBlocks(display, &context, mbw * mbh * BLOCKS_PER_MACROBLOCK, &block_array) == Success);
241 	assert(XvMCCreateMacroBlocks(display, &context, mbw * mbh, &mb_array) == Success);
242 
243 	for (mby = 0; mby < mbh; ++mby)
244 		for (mbx = 0; mbx < mbw; ++mbx)
245 		{
246 			mb_array.macro_blocks[mby * mbw + mbx].x = mbx;
247 			mb_array.macro_blocks[mby * mbw + mbx].y = mby;
248 			mb_array.macro_blocks[mby * mbw + mbx].macroblock_type = XVMC_MB_TYPE_INTRA;
249 			/*mb->motion_type = ;*/
250 			/*mb->motion_vertical_field_select = ;*/
251 			mb_array.macro_blocks[mby * mbw + mbx].dct_type = XVMC_DCT_TYPE_FRAME;
252 			/*mb->PMV[0][0][0] = ;
253 			mb->PMV[0][0][1] = ;
254 			mb->PMV[0][1][0] = ;
255 			mb->PMV[0][1][1] = ;
256 			mb->PMV[1][0][0] = ;
257 			mb->PMV[1][0][1] = ;
258 			mb->PMV[1][1][0] = ;
259 			mb->PMV[1][1][1] = ;*/
260 			mb_array.macro_blocks[mby * mbw + mbx].index = (mby * mbw + mbx) * BLOCKS_PER_MACROBLOCK;
261 			mb_array.macro_blocks[mby * mbw + mbx].coded_block_pattern = 0x3F;
262 		}
263 
264 	XSelectInput(display, window, ExposureMask | KeyPressMask);
265 	XMapWindow(display, window);
266 	XSync(display, 0);
267 
268 	gettimeofday(&start, NULL);
269 
270 	for (reps = 0; reps < config.reps; ++reps)
271 	{
272 		if (config.pipeline & PIPELINE_STEP_MC)
273 		{
274 			assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, mbw * mbh, 0, &mb_array, &block_array) == Success);
275 			assert(XvMCFlushSurface(display, &surface) == Success);
276 		}
277 		if (config.pipeline & PIPELINE_STEP_CSC)
278 			assert(XvMCPutSurface(display, &surface, window, 0, 0, config.input_width, config.input_height, 0, 0, config.output_width, config.output_height, XVMC_FRAME_PICTURE) == Success);
279 	}
280 
281 	gettimeofday(&stop, NULL);
282 
283 	timeval_subtract(&diff, &stop, &start);
284 	diff_secs = (double)diff.tv_sec + (double)diff.tv_usec / 1000000.0;
285 
286 	printf("XvMC Benchmark\n");
287 	printf("Input: %u,%u\nOutput: %u,%u\n", config.input_width, config.input_height, config.output_width, config.output_height);
288 	printf("Pipeline: ");
289 	if (config.pipeline & PIPELINE_STEP_MC)
290 		printf("|mc|");
291 	if (config.pipeline & PIPELINE_STEP_CSC)
292 		printf("|csc|");
293 	if (config.pipeline & PIPELINE_STEP_SWAP)
294 		printf("|swap|");
295 	printf("\n");
296 	printf("Reps: %u\n", config.reps);
297 	printf("Total time: %.2lf (%.2lf reps / sec)\n", diff_secs, config.reps / diff_secs);
298 
299 	assert(XvMCDestroyBlocks(display, &block_array) == Success);
300 	assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success);
301 	assert(XvMCDestroySurface(display, &surface) == Success);
302 	assert(XvMCDestroyContext(display, &context) == Success);
303 
304 	XvUngrabPort(display, port_num, CurrentTime);
305 	XDestroyWindow(display, window);
306 	XCloseDisplay(display);
307 
308 	return 0;
309 }
310