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 TUNGSTEN GRAPHICS 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 #include <assert.h> 29 #include <stdio.h> 30 #include <string.h> 31 #include <error.h> 32 #include <sys/time.h> 33 #include "testlib.h" 34 35 #define MACROBLOCK_WIDTH 16 36 #define MACROBLOCK_HEIGHT 16 37 #define BLOCKS_PER_MACROBLOCK 6 38 39 #define DEFAULT_INPUT_WIDTH 720 40 #define DEFAULT_INPUT_HEIGHT 480 41 #define DEFAULT_REPS 100 42 43 #define PIPELINE_STEP_MC 1 44 #define PIPELINE_STEP_CSC 2 45 #define PIPELINE_STEP_SWAP 4 46 47 #define MB_TYPE_I 1 48 #define MB_TYPE_P 2 49 #define MB_TYPE_B 4 50 51 struct Config 52 { 53 unsigned int input_width; 54 unsigned int input_height; 55 unsigned int output_width; 56 unsigned int output_height; 57 unsigned int pipeline; 58 unsigned int mb_types; 59 unsigned int reps; 60 }; 61 62 void ParseArgs(int argc, char **argv, struct Config *config); 63 64 void ParseArgs(int argc, char **argv, struct Config *config) 65 { 66 int fail = 0; 67 int i; 68 69 config->input_width = DEFAULT_INPUT_WIDTH; 70 config->input_height = DEFAULT_INPUT_HEIGHT; 71 config->output_width = 0; 72 config->output_height = 0; 73 config->pipeline = 0; 74 config->mb_types = 0; 75 config->reps = DEFAULT_REPS; 76 77 for (i = 1; i < argc && !fail; ++i) 78 { 79 if (!strcmp(argv[i], "-iw")) 80 { 81 if (sscanf(argv[++i], "%u", &config->input_width) != 1) 82 fail = 1; 83 } 84 else if (!strcmp(argv[i], "-ih")) 85 { 86 if (sscanf(argv[++i], "%u", &config->input_height) != 1) 87 fail = 1; 88 } 89 else if (!strcmp(argv[i], "-ow")) 90 { 91 if (sscanf(argv[++i], "%u", &config->output_width) != 1) 92 fail = 1; 93 } 94 else if (!strcmp(argv[i], "-oh")) 95 { 96 if (sscanf(argv[++i], "%u", &config->output_height) != 1) 97 fail = 1; 98 } 99 else if (!strcmp(argv[i], "-p")) 100 { 101 char *token = strtok(argv[++i], ","); 102 103 while (token && !fail) 104 { 105 if (!strcmp(token, "mc")) 106 config->pipeline |= PIPELINE_STEP_MC; 107 else if (!strcmp(token, "csc")) 108 config->pipeline |= PIPELINE_STEP_CSC; 109 else if (!strcmp(token, "swp")) 110 config->pipeline |= PIPELINE_STEP_SWAP; 111 else 112 fail = 1; 113 114 if (!fail) 115 token = strtok(NULL, ","); 116 } 117 } 118 else if (!strcmp(argv[i], "-mb")) 119 { 120 char *token = strtok(argv[++i], ","); 121 122 while (token && !fail) 123 { 124 if (strcmp(token, "i")) 125 config->mb_types |= MB_TYPE_I; 126 else if (strcmp(token, "p")) 127 config->mb_types |= MB_TYPE_P; 128 else if (strcmp(token, "b")) 129 config->mb_types |= MB_TYPE_B; 130 else 131 fail = 1; 132 133 if (!fail) 134 token = strtok(NULL, ","); 135 } 136 } 137 else if (!strcmp(argv[i], "-r")) 138 { 139 if (sscanf(argv[++i], "%u", &config->reps) != 1) 140 fail = 1; 141 } 142 else 143 fail = 1; 144 } 145 146 if (fail) 147 error 148 ( 149 1, 0, 150 "Bad argument.\n" 151 "\n" 152 "Usage: %s [options]\n" 153 "\t-iw <width>\tInput width\n" 154 "\t-ih <height>\tInput height\n" 155 "\t-ow <width>\tOutput width\n" 156 "\t-oh <height>\tOutput height\n" 157 "\t-p <pipeline>\tPipeline to test\n" 158 "\t-mb <mb type>\tMacroBlock types to use\n" 159 "\t-r <reps>\tRepetitions\n\n" 160 "\tPipeline steps: mc,csc,swap\n" 161 "\tMB types: i,p,b\n", 162 argv[0] 163 ); 164 165 if (config->output_width == 0) 166 config->output_width = config->input_width; 167 if (config->output_height == 0) 168 config->output_height = config->input_height; 169 if (!config->pipeline) 170 config->pipeline = PIPELINE_STEP_MC | PIPELINE_STEP_CSC | PIPELINE_STEP_SWAP; 171 if (!config->mb_types) 172 config->mb_types = MB_TYPE_I | MB_TYPE_P | MB_TYPE_B; 173 } 174 175 int main(int argc, char **argv) 176 { 177 struct Config config; 178 Display *display; 179 Window root, window; 180 const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2}; 181 XvPortID port_num; 182 int surface_type_id; 183 unsigned int is_overlay, intra_unsigned; 184 int colorkey; 185 XvMCContext context; 186 XvMCSurface surface; 187 XvMCBlockArray block_array; 188 XvMCMacroBlockArray mb_array; 189 unsigned int mbw, mbh; 190 unsigned int mbx, mby; 191 unsigned int reps; 192 struct timeval start, stop, diff; 193 double diff_secs; 194 195 ParseArgs(argc, argv, &config); 196 197 mbw = align(config.input_width, MACROBLOCK_WIDTH) / MACROBLOCK_WIDTH; 198 mbh = align(config.input_height, MACROBLOCK_HEIGHT) / MACROBLOCK_HEIGHT; 199 200 display = XOpenDisplay(NULL); 201 202 if (!GetPort 203 ( 204 display, 205 config.input_width, 206 config.input_height, 207 XVMC_CHROMA_FORMAT_420, 208 mc_types, 209 2, 210 &port_num, 211 &surface_type_id, 212 &is_overlay, 213 &intra_unsigned 214 )) 215 { 216 XCloseDisplay(display); 217 error(1, 0, "Error, unable to find a good port.\n"); 218 } 219 220 if (is_overlay) 221 { 222 Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); 223 XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); 224 } 225 226 root = XDefaultRootWindow(display); 227 window = XCreateSimpleWindow(display, root, 0, 0, config.output_width, config.output_height, 0, 0, colorkey); 228 229 assert(XvMCCreateContext(display, port_num, surface_type_id, config.input_width, config.input_height, XVMC_DIRECT, &context) == Success); 230 assert(XvMCCreateSurface(display, &context, &surface) == Success); 231 assert(XvMCCreateBlocks(display, &context, mbw * mbh * BLOCKS_PER_MACROBLOCK, &block_array) == Success); 232 assert(XvMCCreateMacroBlocks(display, &context, mbw * mbh, &mb_array) == Success); 233 234 for (mby = 0; mby < mbh; ++mby) 235 for (mbx = 0; mbx < mbw; ++mbx) 236 { 237 mb_array.macro_blocks[mby * mbw + mbx].x = mbx; 238 mb_array.macro_blocks[mby * mbw + mbx].y = mby; 239 mb_array.macro_blocks[mby * mbw + mbx].macroblock_type = XVMC_MB_TYPE_INTRA; 240 /*mb->motion_type = ;*/ 241 /*mb->motion_vertical_field_select = ;*/ 242 mb_array.macro_blocks[mby * mbw + mbx].dct_type = XVMC_DCT_TYPE_FRAME; 243 /*mb->PMV[0][0][0] = ; 244 mb->PMV[0][0][1] = ; 245 mb->PMV[0][1][0] = ; 246 mb->PMV[0][1][1] = ; 247 mb->PMV[1][0][0] = ; 248 mb->PMV[1][0][1] = ; 249 mb->PMV[1][1][0] = ; 250 mb->PMV[1][1][1] = ;*/ 251 mb_array.macro_blocks[mby * mbw + mbx].index = (mby * mbw + mbx) * BLOCKS_PER_MACROBLOCK; 252 mb_array.macro_blocks[mby * mbw + mbx].coded_block_pattern = 0x3F; 253 } 254 255 XSelectInput(display, window, ExposureMask | KeyPressMask); 256 XMapWindow(display, window); 257 XSync(display, 0); 258 259 gettimeofday(&start, NULL); 260 261 for (reps = 0; reps < config.reps; ++reps) 262 { 263 if (config.pipeline & PIPELINE_STEP_MC) 264 { 265 assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, mbw * mbh, 0, &mb_array, &block_array) == Success); 266 assert(XvMCFlushSurface(display, &surface) == Success); 267 } 268 if (config.pipeline & PIPELINE_STEP_CSC) 269 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); 270 } 271 272 gettimeofday(&stop, NULL); 273 274 timeval_subtract(&diff, &stop, &start); 275 diff_secs = (double)diff.tv_sec + (double)diff.tv_usec / 1000000.0; 276 277 printf("XvMC Benchmark\n"); 278 printf("Input: %u,%u\nOutput: %u,%u\n", config.input_width, config.input_height, config.output_width, config.output_height); 279 printf("Pipeline: "); 280 if (config.pipeline & PIPELINE_STEP_MC) 281 printf("|mc|"); 282 if (config.pipeline & PIPELINE_STEP_CSC) 283 printf("|csc|"); 284 if (config.pipeline & PIPELINE_STEP_SWAP) 285 printf("|swap|"); 286 printf("\n"); 287 printf("Reps: %u\n", config.reps); 288 printf("Total time: %.2lf (%.2lf reps / sec)\n", diff_secs, config.reps / diff_secs); 289 290 assert(XvMCDestroyBlocks(display, &block_array) == Success); 291 assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success); 292 assert(XvMCDestroySurface(display, &surface) == Success); 293 assert(XvMCDestroyContext(display, &context) == Success); 294 295 XvUngrabPort(display, port_num, CurrentTime); 296 XDestroyWindow(display, window); 297 XCloseDisplay(display); 298 299 return 0; 300 } 301