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 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")) 127 config->mb_types |= MB_TYPE_I; 128 else if (strcmp(token, "p")) 129 config->mb_types |= MB_TYPE_P; 130 else if (strcmp(token, "b")) 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 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