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