Mercurial > sdl-ios-xcode
view test/testblitspeed.c @ 4216:5b99971a27b4 SDL-1.2
Fixed bug #698
Hans de Goede 2009-02-13 01:10:52 PST
Since the new "glitch free" version of pulseaudio (used in Fedora 10 amongst
others), the sound of SDL using apps (like a simple playmus call) has been
crackling.
While looking in to fixing this I noticed that the current pulseaudio code in
SDL uses pa_simple. However pa_simple uses a thread to pump pulseaudio events
and ipc, given that SDL already has its own thread for audio handling this is
clearly suboptimal, leading to unnecessary context switching IPC, etc. Also
pa_simple does not allow one to implement the WaitAudio() callback for SDL
audiodrivers properly.
Given that my work is mostly a rewrite (although some original pieces remain)
I'm attaching the new .c and .h file, as that is easier to review then the huge
diff.
Let me know if you also want the diff.
This new version has the following features:
-no longer use an additional thread next to the SDL sound thread
-do not crackle with glitch free audio
-when used with a newer pulse, which does glitch free audio, the total latency
is
the same as with the alsa driver
-proper WaitAudio() implementation, saving another mixlen worth of latency
-adds a WaitDone() implementation
This patch has been written in consultancy with Lennart Poetering (the
pulseaudio author) and has been reviewed by him for correct use of the pa API.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 21 Sep 2009 09:27:08 +0000 |
parents | cf59e7b91ed4 |
children | e49147870aac c121d94672cb |
line wrap: on
line source
/* * Benchmarks surface-to-surface blits in various formats. * * Written by Ryan C. Gordon. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "SDL.h" static SDL_Surface *dest = NULL; static SDL_Surface *src = NULL; static int testSeconds = 10; static int percent(int val, int total) { return((int) ((((float) val) / ((float) total)) * 100.0f)); } static int randRange(int lo, int hi) { return(lo + (int) (((double) hi)*rand()/(RAND_MAX+1.0))); } static void copy_trunc_str(char *str, size_t strsize, const char *flagstr) { if ( (strlen(str) + strlen(flagstr)) >= (strsize - 1) ) strcpy(str + (strsize - 5), " ..."); else strcat(str, flagstr); } static void __append_sdl_surface_flag(SDL_Surface *_surface, char *str, size_t strsize, Uint32 flag, const char *flagstr) { if (_surface->flags & flag) copy_trunc_str(str, strsize, flagstr); } #define append_sdl_surface_flag(a, b, c, fl) __append_sdl_surface_flag(a, b, c, fl, " " #fl) #define print_tf_state(str, val) printf("%s: {%s}\n", str, (val) ? "true" : "false" ) static void output_videoinfo_details(void) { const SDL_VideoInfo *info = SDL_GetVideoInfo(); printf("SDL_GetVideoInfo():\n"); if (info == NULL) printf(" (null.)\n"); else { print_tf_state(" hardware surface available", info->hw_available); print_tf_state(" window manager available", info->wm_available); print_tf_state(" accelerated hardware->hardware blits", info->blit_hw); print_tf_state(" accelerated hardware->hardware colorkey blits", info->blit_hw_CC); print_tf_state(" accelerated hardware->hardware alpha blits", info->blit_hw_A); print_tf_state(" accelerated software->hardware blits", info->blit_sw); print_tf_state(" accelerated software->hardware colorkey blits", info->blit_sw_CC); print_tf_state(" accelerated software->hardware alpha blits", info->blit_sw_A); print_tf_state(" accelerated color fills", info->blit_fill); printf(" video memory: (%d)\n", info->video_mem); } printf("\n"); } static void output_surface_details(const char *name, SDL_Surface *surface) { printf("Details for %s:\n", name); if (surface == NULL) { printf("-WARNING- You've got a NULL surface!"); } else { char f[256]; printf(" width : %d\n", surface->w); printf(" height : %d\n", surface->h); printf(" depth : %d bits per pixel\n", surface->format->BitsPerPixel); printf(" pitch : %d\n", (int) surface->pitch); printf(" alpha : %d\n", (int) surface->format->alpha); printf(" colorkey : 0x%X\n", (unsigned int) surface->format->colorkey); printf(" red bits : 0x%08X mask, %d shift, %d loss\n", (int) surface->format->Rmask, (int) surface->format->Rshift, (int) surface->format->Rloss); printf(" green bits : 0x%08X mask, %d shift, %d loss\n", (int) surface->format->Gmask, (int) surface->format->Gshift, (int) surface->format->Gloss); printf(" blue bits : 0x%08X mask, %d shift, %d loss\n", (int) surface->format->Bmask, (int) surface->format->Bshift, (int) surface->format->Bloss); printf(" alpha bits : 0x%08X mask, %d shift, %d loss\n", (int) surface->format->Amask, (int) surface->format->Ashift, (int) surface->format->Aloss); f[0] = '\0'; /*append_sdl_surface_flag(surface, f, sizeof (f), SDL_SWSURFACE);*/ if ((surface->flags & SDL_HWSURFACE) == 0) copy_trunc_str(f, sizeof (f), " SDL_SWSURFACE"); append_sdl_surface_flag(surface, f, sizeof (f), SDL_HWSURFACE); append_sdl_surface_flag(surface, f, sizeof (f), SDL_ASYNCBLIT); append_sdl_surface_flag(surface, f, sizeof (f), SDL_ANYFORMAT); append_sdl_surface_flag(surface, f, sizeof (f), SDL_HWPALETTE); append_sdl_surface_flag(surface, f, sizeof (f), SDL_DOUBLEBUF); append_sdl_surface_flag(surface, f, sizeof (f), SDL_FULLSCREEN); append_sdl_surface_flag(surface, f, sizeof (f), SDL_OPENGL); append_sdl_surface_flag(surface, f, sizeof (f), SDL_OPENGLBLIT); append_sdl_surface_flag(surface, f, sizeof (f), SDL_RESIZABLE); append_sdl_surface_flag(surface, f, sizeof (f), SDL_NOFRAME); append_sdl_surface_flag(surface, f, sizeof (f), SDL_HWACCEL); append_sdl_surface_flag(surface, f, sizeof (f), SDL_SRCCOLORKEY); append_sdl_surface_flag(surface, f, sizeof (f), SDL_RLEACCELOK); append_sdl_surface_flag(surface, f, sizeof (f), SDL_RLEACCEL); append_sdl_surface_flag(surface, f, sizeof (f), SDL_SRCALPHA); append_sdl_surface_flag(surface, f, sizeof (f), SDL_PREALLOC); if (f[0] == '\0') strcpy(f, " (none)"); printf(" flags :%s\n", f); } printf("\n"); } static void output_details(void) { output_videoinfo_details(); output_surface_details("Source Surface", src); output_surface_details("Destination Surface", dest); } static Uint32 blit(SDL_Surface *dst, SDL_Surface *src, int x, int y) { Uint32 start = 0; SDL_Rect srcRect; SDL_Rect dstRect; srcRect.x = 0; srcRect.y = 0; dstRect.x = x; dstRect.y = y; dstRect.w = srcRect.w = src->w; /* SDL will clip as appropriate. */ dstRect.h = srcRect.h = src->h; start = SDL_GetTicks(); SDL_BlitSurface(src, &srcRect, dst, &dstRect); return(SDL_GetTicks() - start); } static void blitCentered(SDL_Surface *dst, SDL_Surface *src) { int x = (dst->w - src->w) / 2; int y = (dst->h - src->h) / 2; blit(dst, src, x, y); } static int atoi_hex(const char *str) { if (str == NULL) return 0; if (strlen(str) > 2) { int retval = 0; if ((str[0] == '0') && (str[1] == 'x')) sscanf(str + 2, "%X", &retval); return(retval); } return(atoi(str)); } static int setup_test(int argc, char **argv) { const char *dumpfile = NULL; SDL_Surface *bmp = NULL; Uint32 dstbpp = 32; Uint32 dstrmask = 0x00FF0000; Uint32 dstgmask = 0x0000FF00; Uint32 dstbmask = 0x000000FF; Uint32 dstamask = 0x00000000; Uint32 dstflags = 0; int dstw = 640; int dsth = 480; Uint32 srcbpp = 32; Uint32 srcrmask = 0x00FF0000; Uint32 srcgmask = 0x0000FF00; Uint32 srcbmask = 0x000000FF; Uint32 srcamask = 0x00000000; Uint32 srcflags = 0; int srcw = 640; int srch = 480; Uint32 origsrcalphaflags = 0; Uint32 origdstalphaflags = 0; Uint32 srcalphaflags = 0; Uint32 dstalphaflags = 0; int srcalpha = 255; int dstalpha = 255; int screenSurface = 0; int i = 0; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (strcmp(arg, "--dstbpp") == 0) dstbpp = atoi(argv[++i]); else if (strcmp(arg, "--dstrmask") == 0) dstrmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--dstgmask") == 0) dstgmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--dstbmask") == 0) dstbmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--dstamask") == 0) dstamask = atoi_hex(argv[++i]); else if (strcmp(arg, "--dstwidth") == 0) dstw = atoi(argv[++i]); else if (strcmp(arg, "--dstheight") == 0) dsth = atoi(argv[++i]); else if (strcmp(arg, "--dsthwsurface") == 0) dstflags |= SDL_HWSURFACE; else if (strcmp(arg, "--srcbpp") == 0) srcbpp = atoi(argv[++i]); else if (strcmp(arg, "--srcrmask") == 0) srcrmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--srcgmask") == 0) srcgmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--srcbmask") == 0) srcbmask = atoi_hex(argv[++i]); else if (strcmp(arg, "--srcamask") == 0) srcamask = atoi_hex(argv[++i]); else if (strcmp(arg, "--srcwidth") == 0) srcw = atoi(argv[++i]); else if (strcmp(arg, "--srcheight") == 0) srch = atoi(argv[++i]); else if (strcmp(arg, "--srchwsurface") == 0) srcflags |= SDL_HWSURFACE; else if (strcmp(arg, "--seconds") == 0) testSeconds = atoi(argv[++i]); else if (strcmp(arg, "--screen") == 0) screenSurface = 1; else if (strcmp(arg, "--dumpfile") == 0) dumpfile = argv[++i]; /* !!! FIXME: set colorkey. */ else if (0) /* !!! FIXME: we handle some commandlines elsewhere now */ { fprintf(stderr, "Unknown commandline option: %s\n", arg); return(0); } } if (SDL_Init(SDL_INIT_VIDEO) == -1) { fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError()); return(0); } bmp = SDL_LoadBMP("sample.bmp"); if (bmp == NULL) { fprintf(stderr, "SDL_LoadBMP failed: %s\n", SDL_GetError()); SDL_Quit(); return(0); } if ((dstflags & SDL_HWSURFACE) == 0) dstflags |= SDL_SWSURFACE; if ((srcflags & SDL_HWSURFACE) == 0) srcflags |= SDL_SWSURFACE; if (screenSurface) dest = SDL_SetVideoMode(dstw, dsth, dstbpp, dstflags); else { dest = SDL_CreateRGBSurface(dstflags, dstw, dsth, dstbpp, dstrmask, dstgmask, dstbmask, dstamask); } if (dest == NULL) { fprintf(stderr, "dest surface creation failed: %s\n", SDL_GetError()); SDL_Quit(); return(0); } src = SDL_CreateRGBSurface(srcflags, srcw, srch, srcbpp, srcrmask, srcgmask, srcbmask, srcamask); if (src == NULL) { fprintf(stderr, "src surface creation failed: %s\n", SDL_GetError()); SDL_Quit(); return(0); } /* handle alpha settings... */ srcalphaflags = (src->flags&SDL_SRCALPHA) | (src->flags&SDL_RLEACCEL); dstalphaflags = (dest->flags&SDL_SRCALPHA) | (dest->flags&SDL_RLEACCEL); origsrcalphaflags = srcalphaflags; origdstalphaflags = dstalphaflags; srcalpha = src->format->alpha; dstalpha = dest->format->alpha; for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (strcmp(arg, "--srcalpha") == 0) srcalpha = atoi(argv[++i]); else if (strcmp(arg, "--dstalpha") == 0) dstalpha = atoi(argv[++i]); else if (strcmp(arg, "--srcsrcalpha") == 0) srcalphaflags |= SDL_SRCALPHA; else if (strcmp(arg, "--srcnosrcalpha") == 0) srcalphaflags &= ~SDL_SRCALPHA; else if (strcmp(arg, "--srcrleaccel") == 0) srcalphaflags |= SDL_RLEACCEL; else if (strcmp(arg, "--srcnorleaccel") == 0) srcalphaflags &= ~SDL_RLEACCEL; else if (strcmp(arg, "--dstsrcalpha") == 0) dstalphaflags |= SDL_SRCALPHA; else if (strcmp(arg, "--dstnosrcalpha") == 0) dstalphaflags &= ~SDL_SRCALPHA; else if (strcmp(arg, "--dstrleaccel") == 0) dstalphaflags |= SDL_RLEACCEL; else if (strcmp(arg, "--dstnorleaccel") == 0) dstalphaflags &= ~SDL_RLEACCEL; } if ((dstalphaflags != origdstalphaflags) || (dstalpha != dest->format->alpha)) SDL_SetAlpha(dest, dstalphaflags, (Uint8) dstalpha); if ((srcalphaflags != origsrcalphaflags) || (srcalpha != src->format->alpha)) SDL_SetAlpha(src, srcalphaflags, (Uint8) srcalpha); /* set some sane defaults so we can see if the blit code is broken... */ SDL_FillRect(dest, NULL, SDL_MapRGB(dest->format, 0, 0, 0)); SDL_FillRect(src, NULL, SDL_MapRGB(src->format, 0, 0, 0)); blitCentered(src, bmp); SDL_FreeSurface(bmp); if (dumpfile) SDL_SaveBMP(src, dumpfile); /* make sure initial convert is sane. */ output_details(); return(1); } static void test_blit_speed(void) { Uint32 clearColor = SDL_MapRGB(dest->format, 0, 0, 0); Uint32 iterations = 0; Uint32 elasped = 0; Uint32 end = 0; Uint32 now = 0; Uint32 last = 0; int testms = testSeconds * 1000; int wmax = (dest->w - src->w); int hmax = (dest->h - src->h); int isScreen = (SDL_GetVideoSurface() == dest); SDL_Event event; printf("Testing blit speed for %d seconds...\n", testSeconds); now = SDL_GetTicks(); end = now + testms; do { /* pump the event queue occasionally to keep OS happy... */ if (now - last > 1000) { last = now; while (SDL_PollEvent(&event)) { /* no-op. */ } } iterations++; elasped += blit(dest, src, randRange(0, wmax), randRange(0, hmax)); if (isScreen) { SDL_Flip(dest); /* show it! */ SDL_FillRect(dest, NULL, clearColor); /* blank it for next time! */ } now = SDL_GetTicks(); } while (now < end); printf("Non-blitting crap accounted for %d percent of this run.\n", percent(testms - elasped, testms)); printf("%d blits took %d ms (%d fps).\n", (int) iterations, (int) elasped, (int) (((float)iterations) / (((float)elasped) / 1000.0f))); } int main(int argc, char **argv) { int initialized = setup_test(argc, argv); if (initialized) { test_blit_speed(); SDL_Quit(); } return(!initialized); } /* end of testblitspeed.c ... */