| 1 | /* |
| 2 | * Benchmarks surface-to-surface blits in various formats. |
| 3 | * |
| 4 | * Written by Ryan C. Gordon. |
| 5 | */ |
| 6 | |
| 7 | #include <stdio.h> |
| 8 | #include <stdlib.h> |
| 9 | #include <string.h> |
| 10 | |
| 11 | #include "SDL.h" |
| 12 | |
| 13 | static SDL_Surface *dest = NULL; |
| 14 | static SDL_Surface *src = NULL; |
| 15 | static int testSeconds = 10; |
| 16 | |
| 17 | |
| 18 | static int percent(int val, int total) |
| 19 | { |
| 20 | return((int) ((((float) val) / ((float) total)) * 100.0f)); |
| 21 | } |
| 22 | |
| 23 | static int randRange(int lo, int hi) |
| 24 | { |
| 25 | return(lo + (int) (((double) hi)*rand()/(RAND_MAX+1.0))); |
| 26 | } |
| 27 | |
| 28 | static void copy_trunc_str(char *str, size_t strsize, const char *flagstr) |
| 29 | { |
| 30 | if ( (strlen(str) + strlen(flagstr)) >= (strsize - 1) ) |
| 31 | strcpy(str + (strsize - 5), " ..."); |
| 32 | else |
| 33 | strcat(str, flagstr); |
| 34 | } |
| 35 | |
| 36 | static void __append_sdl_surface_flag(SDL_Surface *_surface, char *str, |
| 37 | size_t strsize, Uint32 flag, |
| 38 | const char *flagstr) |
| 39 | { |
| 40 | if (_surface->flags & flag) |
| 41 | copy_trunc_str(str, strsize, flagstr); |
| 42 | } |
| 43 | |
| 44 | |
| 45 | #define append_sdl_surface_flag(a, b, c, fl) __append_sdl_surface_flag(a, b, c, fl, " " #fl) |
| 46 | #define print_tf_state(str, val) printf("%s: {%s}\n", str, (val) ? "true" : "false" ) |
| 47 | |
| 48 | static void output_videoinfo_details(void) |
| 49 | { |
| 50 | const SDL_VideoInfo *info = SDL_GetVideoInfo(); |
| 51 | printf("SDL_GetVideoInfo():\n"); |
| 52 | if (info == NULL) |
| 53 | printf(" (null.)\n"); |
| 54 | else |
| 55 | { |
| 56 | print_tf_state(" hardware surface available", info->hw_available); |
| 57 | print_tf_state(" window manager available", info->wm_available); |
| 58 | print_tf_state(" accelerated hardware->hardware blits", info->blit_hw); |
| 59 | print_tf_state(" accelerated hardware->hardware colorkey blits", info->blit_hw_CC); |
| 60 | print_tf_state(" accelerated hardware->hardware alpha blits", info->blit_hw_A); |
| 61 | print_tf_state(" accelerated software->hardware blits", info->blit_sw); |
| 62 | print_tf_state(" accelerated software->hardware colorkey blits", info->blit_sw_CC); |
| 63 | print_tf_state(" accelerated software->hardware alpha blits", info->blit_sw_A); |
| 64 | print_tf_state(" accelerated color fills", info->blit_fill); |
| 65 | printf(" video memory: (%d)\n", info->video_mem); |
| 66 | } |
| 67 | |
| 68 | printf("\n"); |
| 69 | } |
| 70 | |
| 71 | static void output_surface_details(const char *name, SDL_Surface *surface) |
| 72 | { |
| 73 | printf("Details for %s:\n", name); |
| 74 | |
| 75 | if (surface == NULL) |
| 76 | { |
| 77 | printf("-WARNING- You've got a NULL surface!"); |
| 78 | } |
| 79 | else |
| 80 | { |
| 81 | char f[256]; |
| 82 | printf(" width : %d\n", surface->w); |
| 83 | printf(" height : %d\n", surface->h); |
| 84 | printf(" depth : %d bits per pixel\n", surface->format->BitsPerPixel); |
| 85 | printf(" pitch : %d\n", (int) surface->pitch); |
| 86 | printf(" alpha : %d\n", (int) surface->format->alpha); |
| 87 | printf(" colorkey : 0x%X\n", (unsigned int) surface->format->colorkey); |
| 88 | |
| 89 | printf(" red bits : 0x%08X mask, %d shift, %d loss\n", |
| 90 | (int) surface->format->Rmask, |
| 91 | (int) surface->format->Rshift, |
| 92 | (int) surface->format->Rloss); |
| 93 | printf(" green bits : 0x%08X mask, %d shift, %d loss\n", |
| 94 | (int) surface->format->Gmask, |
| 95 | (int) surface->format->Gshift, |
| 96 | (int) surface->format->Gloss); |
| 97 | printf(" blue bits : 0x%08X mask, %d shift, %d loss\n", |
| 98 | (int) surface->format->Bmask, |
| 99 | (int) surface->format->Bshift, |
| 100 | (int) surface->format->Bloss); |
| 101 | printf(" alpha bits : 0x%08X mask, %d shift, %d loss\n", |
| 102 | (int) surface->format->Amask, |
| 103 | (int) surface->format->Ashift, |
| 104 | (int) surface->format->Aloss); |
| 105 | |
| 106 | f[0] = '\0'; |
| 107 | |
| 108 | /*append_sdl_surface_flag(surface, f, sizeof (f), SDL_SWSURFACE);*/ |
| 109 | if ((surface->flags & SDL_HWSURFACE) == 0) |
| 110 | copy_trunc_str(f, sizeof (f), " SDL_SWSURFACE"); |
| 111 | |
| 112 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_HWSURFACE); |
| 113 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_ASYNCBLIT); |
| 114 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_ANYFORMAT); |
| 115 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_HWPALETTE); |
| 116 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_DOUBLEBUF); |
| 117 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_FULLSCREEN); |
| 118 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_OPENGL); |
| 119 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_OPENGLBLIT); |
| 120 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_RESIZABLE); |
| 121 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_NOFRAME); |
| 122 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_HWACCEL); |
| 123 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_SRCCOLORKEY); |
| 124 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_RLEACCELOK); |
| 125 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_RLEACCEL); |
| 126 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_SRCALPHA); |
| 127 | append_sdl_surface_flag(surface, f, sizeof (f), SDL_PREALLOC); |
| 128 | |
| 129 | if (f[0] == '\0') |
| 130 | strcpy(f, " (none)"); |
| 131 | |
| 132 | printf(" flags :%s\n", f); |
| 133 | } |
| 134 | |
| 135 | printf("\n"); |
| 136 | } |
| 137 | |
| 138 | static void output_details(void) |
| 139 | { |
| 140 | output_videoinfo_details(); |
| 141 | output_surface_details("Source Surface", src); |
| 142 | output_surface_details("Destination Surface", dest); |
| 143 | } |
| 144 | |
| 145 | static Uint32 blit(SDL_Surface *dst, SDL_Surface *src, int x, int y) |
| 146 | { |
| 147 | Uint32 start = 0; |
| 148 | SDL_Rect srcRect; |
| 149 | SDL_Rect dstRect; |
| 150 | |
| 151 | srcRect.x = 0; |
| 152 | srcRect.y = 0; |
| 153 | dstRect.x = x; |
| 154 | dstRect.y = y; |
| 155 | dstRect.w = srcRect.w = src->w; /* SDL will clip as appropriate. */ |
| 156 | dstRect.h = srcRect.h = src->h; |
| 157 | |
| 158 | start = SDL_GetTicks(); |
| 159 | SDL_BlitSurface(src, &srcRect, dst, &dstRect); |
| 160 | return(SDL_GetTicks() - start); |
| 161 | } |
| 162 | |
| 163 | static void blitCentered(SDL_Surface *dst, SDL_Surface *src) |
| 164 | { |
| 165 | int x = (dst->w - src->w) / 2; |
| 166 | int y = (dst->h - src->h) / 2; |
| 167 | blit(dst, src, x, y); |
| 168 | } |
| 169 | |
| 170 | static int atoi_hex(const char *str) |
| 171 | { |
| 172 | if (str == NULL) |
| 173 | return 0; |
| 174 | |
| 175 | if (strlen(str) > 2) |
| 176 | { |
| 177 | int retval = 0; |
| 178 | if ((str[0] == '0') && (str[1] == 'x')) |
| 179 | sscanf(str + 2, "%X", &retval); |
| 180 | return(retval); |
| 181 | } |
| 182 | |
| 183 | return(atoi(str)); |
| 184 | } |
| 185 | |
| 186 | |
| 187 | static int setup_test(int argc, char **argv) |
| 188 | { |
| 189 | const char *dumpfile = NULL; |
| 190 | SDL_Surface *bmp = NULL; |
| 191 | Uint32 dstbpp = 32; |
| 192 | Uint32 dstrmask = 0x00FF0000; |
| 193 | Uint32 dstgmask = 0x0000FF00; |
| 194 | Uint32 dstbmask = 0x000000FF; |
| 195 | Uint32 dstamask = 0x00000000; |
| 196 | Uint32 dstflags = 0; |
| 197 | int dstw = 640; |
| 198 | int dsth = 480; |
| 199 | Uint32 srcbpp = 32; |
| 200 | Uint32 srcrmask = 0x00FF0000; |
| 201 | Uint32 srcgmask = 0x0000FF00; |
| 202 | Uint32 srcbmask = 0x000000FF; |
| 203 | Uint32 srcamask = 0x00000000; |
| 204 | Uint32 srcflags = 0; |
| 205 | int srcw = 640; |
| 206 | int srch = 480; |
| 207 | Uint32 origsrcalphaflags = 0; |
| 208 | Uint32 origdstalphaflags = 0; |
| 209 | Uint32 srcalphaflags = 0; |
| 210 | Uint32 dstalphaflags = 0; |
| 211 | int srcalpha = 255; |
| 212 | int dstalpha = 255; |
| 213 | int screenSurface = 0; |
| 214 | int i = 0; |
| 215 | |
| 216 | for (i = 1; i < argc; i++) |
| 217 | { |
| 218 | const char *arg = argv[i]; |
| 219 | |
| 220 | if (strcmp(arg, "--dstbpp") == 0) |
| 221 | dstbpp = atoi(argv[++i]); |
| 222 | else if (strcmp(arg, "--dstrmask") == 0) |
| 223 | dstrmask = atoi_hex(argv[++i]); |
| 224 | else if (strcmp(arg, "--dstgmask") == 0) |
| 225 | dstgmask = atoi_hex(argv[++i]); |
| 226 | else if (strcmp(arg, "--dstbmask") == 0) |
| 227 | dstbmask = atoi_hex(argv[++i]); |
| 228 | else if (strcmp(arg, "--dstamask") == 0) |
| 229 | dstamask = atoi_hex(argv[++i]); |
| 230 | else if (strcmp(arg, "--dstwidth") == 0) |
| 231 | dstw = atoi(argv[++i]); |
| 232 | else if (strcmp(arg, "--dstheight") == 0) |
| 233 | dsth = atoi(argv[++i]); |
| 234 | else if (strcmp(arg, "--dsthwsurface") == 0) |
| 235 | dstflags |= SDL_HWSURFACE; |
| 236 | else if (strcmp(arg, "--srcbpp") == 0) |
| 237 | srcbpp = atoi(argv[++i]); |
| 238 | else if (strcmp(arg, "--srcrmask") == 0) |
| 239 | srcrmask = atoi_hex(argv[++i]); |
| 240 | else if (strcmp(arg, "--srcgmask") == 0) |
| 241 | srcgmask = atoi_hex(argv[++i]); |
| 242 | else if (strcmp(arg, "--srcbmask") == 0) |
| 243 | srcbmask = atoi_hex(argv[++i]); |
| 244 | else if (strcmp(arg, "--srcamask") == 0) |
| 245 | srcamask = atoi_hex(argv[++i]); |
| 246 | else if (strcmp(arg, "--srcwidth") == 0) |
| 247 | srcw = atoi(argv[++i]); |
| 248 | else if (strcmp(arg, "--srcheight") == 0) |
| 249 | srch = atoi(argv[++i]); |
| 250 | else if (strcmp(arg, "--srchwsurface") == 0) |
| 251 | srcflags |= SDL_HWSURFACE; |
| 252 | else if (strcmp(arg, "--seconds") == 0) |
| 253 | testSeconds = atoi(argv[++i]); |
| 254 | else if (strcmp(arg, "--screen") == 0) |
| 255 | screenSurface = 1; |
| 256 | else if (strcmp(arg, "--dumpfile") == 0) |
| 257 | dumpfile = argv[++i]; |
| 258 | /* !!! FIXME: set colorkey. */ |
| 259 | else if (0) /* !!! FIXME: we handle some commandlines elsewhere now */ |
| 260 | { |
| 261 | fprintf(stderr, "Unknown commandline option: %s\n", arg); |
| 262 | return(0); |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | if (SDL_Init(SDL_INIT_VIDEO) == -1) |
| 267 | { |
| 268 | fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); |
| 269 | return(0); |
| 270 | } |
| 271 | |
| 272 | bmp = SDL_LoadBMP("sample.bmp"); |
| 273 | if (bmp == NULL) |
| 274 | { |
| 275 | fprintf(stderr, "SDL_LoadBMP failed: %s\n", SDL_GetError()); |
| 276 | SDL_Quit(); |
| 277 | return(0); |
| 278 | } |
| 279 | |
| 280 | if ((dstflags & SDL_HWSURFACE) == 0) dstflags |= SDL_SWSURFACE; |
| 281 | if ((srcflags & SDL_HWSURFACE) == 0) srcflags |= SDL_SWSURFACE; |
| 282 | |
| 283 | if (screenSurface) |
| 284 | dest = SDL_SetVideoMode(dstw, dsth, dstbpp, dstflags); |
| 285 | else |
| 286 | { |
| 287 | dest = SDL_CreateRGBSurface(dstflags, dstw, dsth, dstbpp, |
| 288 | dstrmask, dstgmask, dstbmask, dstamask); |
| 289 | } |
| 290 | |
| 291 | if (dest == NULL) |
| 292 | { |
| 293 | fprintf(stderr, "dest surface creation failed: %s\n", SDL_GetError()); |
| 294 | SDL_Quit(); |
| 295 | return(0); |
| 296 | } |
| 297 | |
| 298 | src = SDL_CreateRGBSurface(srcflags, srcw, srch, srcbpp, |
| 299 | srcrmask, srcgmask, srcbmask, srcamask); |
| 300 | if (src == NULL) |
| 301 | { |
| 302 | fprintf(stderr, "src surface creation failed: %s\n", SDL_GetError()); |
| 303 | SDL_Quit(); |
| 304 | return(0); |
| 305 | } |
| 306 | |
| 307 | /* handle alpha settings... */ |
| 308 | srcalphaflags = (src->flags&SDL_SRCALPHA) | (src->flags&SDL_RLEACCEL); |
| 309 | dstalphaflags = (dest->flags&SDL_SRCALPHA) | (dest->flags&SDL_RLEACCEL); |
| 310 | origsrcalphaflags = srcalphaflags; |
| 311 | origdstalphaflags = dstalphaflags; |
| 312 | srcalpha = src->format->alpha; |
| 313 | dstalpha = dest->format->alpha; |
| 314 | for (i = 1; i < argc; i++) |
| 315 | { |
| 316 | const char *arg = argv[i]; |
| 317 | |
| 318 | if (strcmp(arg, "--srcalpha") == 0) |
| 319 | srcalpha = atoi(argv[++i]); |
| 320 | else if (strcmp(arg, "--dstalpha") == 0) |
| 321 | dstalpha = atoi(argv[++i]); |
| 322 | else if (strcmp(arg, "--srcsrcalpha") == 0) |
| 323 | srcalphaflags |= SDL_SRCALPHA; |
| 324 | else if (strcmp(arg, "--srcnosrcalpha") == 0) |
| 325 | srcalphaflags &= ~SDL_SRCALPHA; |
| 326 | else if (strcmp(arg, "--srcrleaccel") == 0) |
| 327 | srcalphaflags |= SDL_RLEACCEL; |
| 328 | else if (strcmp(arg, "--srcnorleaccel") == 0) |
| 329 | srcalphaflags &= ~SDL_RLEACCEL; |
| 330 | else if (strcmp(arg, "--dstsrcalpha") == 0) |
| 331 | dstalphaflags |= SDL_SRCALPHA; |
| 332 | else if (strcmp(arg, "--dstnosrcalpha") == 0) |
| 333 | dstalphaflags &= ~SDL_SRCALPHA; |
| 334 | else if (strcmp(arg, "--dstrleaccel") == 0) |
| 335 | dstalphaflags |= SDL_RLEACCEL; |
| 336 | else if (strcmp(arg, "--dstnorleaccel") == 0) |
| 337 | dstalphaflags &= ~SDL_RLEACCEL; |
| 338 | } |
| 339 | if ((dstalphaflags != origdstalphaflags) || (dstalpha != dest->format->alpha)) |
| 340 | SDL_SetAlpha(dest, dstalphaflags, (Uint8) dstalpha); |
| 341 | if ((srcalphaflags != origsrcalphaflags) || (srcalpha != src->format->alpha)) |
| 342 | SDL_SetAlpha(src, srcalphaflags, (Uint8) srcalpha); |
| 343 | |
| 344 | /* set some sane defaults so we can see if the blit code is broken... */ |
| 345 | SDL_FillRect(dest, NULL, SDL_MapRGB(dest->format, 0, 0, 0)); |
| 346 | SDL_FillRect(src, NULL, SDL_MapRGB(src->format, 0, 0, 0)); |
| 347 | |
| 348 | blitCentered(src, bmp); |
| 349 | SDL_FreeSurface(bmp); |
| 350 | |
| 351 | if (dumpfile) |
| 352 | SDL_SaveBMP(src, dumpfile); /* make sure initial convert is sane. */ |
| 353 | |
| 354 | output_details(); |
| 355 | |
| 356 | return(1); |
| 357 | } |
| 358 | |
| 359 | |
| 360 | static void test_blit_speed(void) |
| 361 | { |
| 362 | Uint32 clearColor = SDL_MapRGB(dest->format, 0, 0, 0); |
| 363 | Uint32 iterations = 0; |
| 364 | Uint32 elasped = 0; |
| 365 | Uint32 end = 0; |
| 366 | Uint32 now = 0; |
| 367 | Uint32 last = 0; |
| 368 | int testms = testSeconds * 1000; |
| 369 | int wmax = (dest->w - src->w); |
| 370 | int hmax = (dest->h - src->h); |
| 371 | int isScreen = (SDL_GetVideoSurface() == dest); |
| 372 | SDL_Event event; |
| 373 | |
| 374 | printf("Testing blit speed for %d seconds...\n", testSeconds); |
| 375 | |
| 376 | now = SDL_GetTicks(); |
| 377 | end = now + testms; |
| 378 | |
| 379 | do |
| 380 | { |
| 381 | /* pump the event queue occasionally to keep OS happy... */ |
| 382 | if (now - last > 1000) |
| 383 | { |
| 384 | last = now; |
| 385 | while (SDL_PollEvent(&event)) { /* no-op. */ } |
| 386 | } |
| 387 | |
| 388 | iterations++; |
| 389 | elasped += blit(dest, src, randRange(0, wmax), randRange(0, hmax)); |
| 390 | if (isScreen) |
| 391 | { |
| 392 | SDL_Flip(dest); /* show it! */ |
| 393 | SDL_FillRect(dest, NULL, clearColor); /* blank it for next time! */ |
| 394 | } |
| 395 | |
| 396 | now = SDL_GetTicks(); |
| 397 | } while (now < end); |
| 398 | |
| 399 | printf("Non-blitting crap accounted for %d percent of this run.\n", |
| 400 | percent(testms - elasped, testms)); |
| 401 | |
| 402 | printf("%d blits took %d ms (%d fps).\n", |
| 403 | (int) iterations, |
| 404 | (int) elasped, |
| 405 | (int) (((float)iterations) / (((float)elasped) / 1000.0f))); |
| 406 | } |
| 407 | |
| 408 | int main(int argc, char **argv) |
| 409 | { |
| 410 | int initialized = setup_test(argc, argv); |
| 411 | if (initialized) |
| 412 | { |
| 413 | test_blit_speed(); |
| 414 | SDL_Quit(); |
| 415 | } |
| 416 | return(!initialized); |
| 417 | } |
| 418 | |
| 419 | /* end of testblitspeed.c ... */ |
| 420 | |