#import //#define USEBITMAP @interface MyView : NSView { CGContextRef bitmap; unsigned char* data; CGImageRef image; unsigned long long pixels; unsigned long long frames; } @property (readonly) unsigned long long pixels; @property (readonly) unsigned long long frames; @property(getter=isOpaque, readonly) BOOL opaque; @property(readonly) BOOL wantsDefaultClipping; @end @implementation MyView - (id)init { self = [super initWithFrame:NSMakeRect(0, 0, 1024, 768)]; //[self setWantsLayer:YES]; CGColorSpaceRef lut; lut = CGDisplayCopyColorSpace(kCGDirectMainDisplay); data = malloc(self.frame.size.width * self.frame.size.height * 4); #ifdef USEBITMAP bitmap = CGBitmapContextCreate(data, self.frame.size.width, self.frame.size.height, 8, self.frame.size.width * 4, lut, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little); #else CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, self.frame.size.width * self.frame.size.height * 4, NULL); image = CGImageCreate(self.frame.size.width, self.frame.size.height, 8, 32, self.frame.size.width * 4, lut, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, provider, NULL, false, kCGRenderingIntentDefault); CGDataProviderRelease(provider); #endif CGColorSpaceRelease(lut); [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(onTimeout:) userInfo:nil repeats:NO]; pixels = 0; frames = 0; return self; } - (void)dealloc { free(data); [super dealloc]; } - (unsigned long long)pixels { return pixels; } - (unsigned long long)frames { return frames; } - (BOOL)isOpaque { return YES; } - (BOOL)wantsDefaultClipping { return NO; } - (void)drawRect:(NSRect)dirtyRect { //[super drawRect:dirtyRect]; CGContextRef gc; memset(data, rand(), self.frame.size.width * self.frame.size.height * 4); gc = [[NSGraphicsContext currentContext] graphicsPort]; //CGContextSaveGState(gc); #ifdef USEBITMAP image = CGBitmapContextCreateImage(bitmap); #endif CGContextDrawImage(gc, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image); #ifdef USEBITMAP CGImageRelease(image); #endif //CGContextRestoreGState(gc); frames++; pixels += self.frame.size.width * self.frame.size.height; [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(onTimer:) userInfo:nil repeats:NO]; } - (void)onTimer:(NSTimer*)timer { [self setNeedsDisplay:true]; } - (void)onTimeout:(NSTimer*)timer { fprintf(stderr, "Stopping!\n"); [NSApp terminate:self]; } @end @interface MyApp: NSObject { struct timeval start, stop; struct rusage cpuStart, cpuStop; } @end @implementation MyApp - (void)applicationDidFinishLaunching:(NSNotification *)notification { gettimeofday(&start, NULL); getrusage(RUSAGE_SELF, &cpuStart); } static size_t doPrefix(long long value, const char *unit, char *buffer, size_t maxlen, unsigned divisor, const char **prefixes, size_t prefixCount) { double newValue; size_t prefix, len; newValue = value; prefix = 0; while (newValue >= divisor) { if (prefix >= prefixCount) break; newValue /= divisor; prefix++; } len = snprintf(buffer, maxlen, "%g %s%s", newValue, (prefix == 0) ? "" : prefixes[prefix-1], unit); buffer[maxlen-1] = '\0'; return len; } static const char *siPrefixes[] = { "k", "M", "G", "T", "P", "E", "Z", "Y" }; static const char *iecPrefixes[] = { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; size_t siPrefix(long long value, const char *unit, char *buffer, size_t maxlen) { return doPrefix(value, unit, buffer, maxlen, 1000, siPrefixes, sizeof(siPrefixes)/sizeof(*siPrefixes)); } size_t iecPrefix(long long value, const char *unit, char *buffer, size_t maxlen) { return doPrefix(value, unit, buffer, maxlen, 1024, iecPrefixes, sizeof(iecPrefixes)/sizeof(*iecPrefixes)); } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { double realTime, encodeTime; double sysSeconds, userSeconds; id view; char s[1024]; getrusage(RUSAGE_SELF, &cpuStop); gettimeofday(&stop, NULL); realTime = (double)stop.tv_sec - start.tv_sec; realTime += ((double)stop.tv_usec - start.tv_usec)/1000000.0; sysSeconds = (double)(cpuStop.ru_stime.tv_sec - cpuStart.ru_stime.tv_sec); sysSeconds += (double)(cpuStop.ru_stime.tv_usec - cpuStart.ru_stime.tv_usec) / 1000000.0; userSeconds = (double)(cpuStop.ru_utime.tv_sec - cpuStart.ru_utime.tv_sec); userSeconds += (double)(cpuStop.ru_utime.tv_usec - cpuStart.ru_utime.tv_usec) / 1000000.0; encodeTime = sysSeconds + userSeconds; view = [[[NSApp windows] objectAtIndex:0] contentView]; siPrefix([view pixels] / realTime, "Pixels/s", s, sizeof(s)); fprintf(stderr, "Fill rate: %s\n", s); fprintf(stderr, "Frame rate: %g fps\n", (double)[view frames] / realTime); fprintf(stderr, "CPU Usage: %g %%\n", 100.0 * encodeTime / realTime); return NSTerminateNow; } @end int main () { [NSAutoreleasePool new]; [NSApplication sharedApplication]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; id menubar = [[NSMenu new] autorelease]; id appMenuItem = [[NSMenuItem new] autorelease]; [menubar addItem:appMenuItem]; [NSApp setMainMenu:menubar]; id appMenu = [[NSMenu new] autorelease]; id appName = [[NSProcessInfo processInfo] processName]; id quitTitle = [@"Quit " stringByAppendingString:appName]; id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle action:@selector(terminate:) keyEquivalent:@"q"] autorelease]; [appMenu addItem:quitMenuItem]; [appMenuItem setSubmenu:appMenu]; id window = [[[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1024, 768) styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO] autorelease]; [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; [window setTitle:appName]; [window makeKeyAndOrderFront:nil]; id view = [[MyView alloc] init]; [window setContentView:view]; [NSApp setDelegate:[[MyApp alloc] init]]; [NSApp activateIgnoringOtherApps:YES]; [NSApp run]; return 0; }