1/*
2cc -o /tmp/timefb timefb.c -framework IOKit -framework ApplicationServices -Wall -arch x86_64
3*/
4
5#include <IOKit/IOKitLib.h>
6#include <ApplicationServices/ApplicationServicesPriv.h>
7#include <IOKit/i2c/IOI2CInterface.h>
8#include <IOKit/graphics/IOFramebufferShared.h>
9#include <IOKit/graphics/IOGraphicsTypesPrivate.h>
10#include <IOKit/graphics/IOAccelSurfaceControl.h>
11#include <IOKit/graphics/IOGraphicsLib.h>
12#include </System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/Versions/A/PrivateHeaders/blt.h>
13#include <libc.h>
14
15double currentTime(void)
16{
17        struct timeval          v;
18
19        gettimeofday(&v, NULL);
20        return (v.tv_sec  +  (1e-6) * v.tv_usec);
21}
22
23int main(int argc, char * argv[])
24{
25    IOReturn            kr;
26    CGDirectDisplayID   dspy = CGMainDisplayID();
27    io_service_t        framebuffer;
28    io_connect_t	connect;
29    CGRect              bounds;
30    mach_vm_size_t      size;
31    CGSRowBytes         rb;
32    mach_vm_address_t   p, mapAddr;
33    double		t;
34    int i;
35
36    dspy = CGMainDisplayID();
37    bounds = CGDisplayBounds(dspy);
38//    rb = CGDisplayBytesPerRow(dspy);
39    CGSGetDisplayRowBytes(dspy, &rb);
40
41    framebuffer = CGDisplayIOServicePort(dspy);
42    assert (framebuffer != MACH_PORT_NULL);
43    kr = IOServiceOpen(framebuffer, mach_task_self(), kIOFBSharedConnectType, &connect);
44    if (kIOReturnSuccess != kr)
45    {
46	printf("IOServiceOpen(%x)\n", kr);
47	exit(1);
48    }
49
50    static IOOptionBits mapTypes[] = {
51    	kIOMapInhibitCache, kIOMapWriteThruCache, kIOMapCopybackCache, kIOMapWriteCombineCache };
52    static const char * mapNames[] = {
53    	"kIOMapInhibitCache", "kIOMapWriteThruCache", "kIOMapCopybackCache", "kIOMapWriteCombineCache" };
54
55    bounds.size.height -= 40;
56
57    int mapType, x, y;
58    for (mapType = 0; mapType < sizeof(mapTypes) / sizeof(mapTypes[0]); mapType++)
59    {
60	kr = IOConnectMapMemory64(connect, kIOFBVRAMMemory, mach_task_self(),
61			&mapAddr, &size,
62			kIOMapAnywhere | mapTypes[mapType]);
63	if (kIOReturnSuccess != kr)
64	{
65	    printf("IOConnectMapMemory(%x)\n", kr);
66	    exit(1);
67	}
68
69	mapAddr += 128*1024;
70	t = currentTime();
71
72	uint32_t sum;
73	for (i = 0; i < 20; i++) {
74	    p = mapAddr;
75	    sum = 0;
76	    for (y = 0; y < bounds.size.height; y++)
77	    {
78		for (x = 0; x < bounds.size.width; x++)
79		{
80		    sum += ((uint32_t*)(uintptr_t)p)[x];
81		}
82		p += rb;
83	    }
84	}
85	printf("read (%s) %d times at (%dx%dx32): %g MB/sec sum 0x%x\n", mapNames[mapType], i,
86		(int)bounds.size.width, (int)bounds.size.height,
87		i*bounds.size.width*bounds.size.height*4/(1e6*(currentTime() - t)), sum);
88
89	t = currentTime();
90	for (i = 0; i < 20; i++) {
91	    CGBlt_fillBytes(bounds.size.width*4, bounds.size.height, 1, (void*)(uintptr_t) mapAddr, rb, 0);
92	}
93	printf("CGBlt_fillBytes(%s) %d times at (%dx%dx32): %g MB/sec\n", mapNames[mapType], i,
94		(int)bounds.size.width, (int)bounds.size.height,
95		i*bounds.size.width*bounds.size.height*4/(1e6*(currentTime() - t)));
96
97	for (i = 0; i < 20; i++) {
98	    p = mapAddr;
99	    for (y = 0; y < bounds.size.height; y++)
100	    {
101		for (x = 0; x < bounds.size.width; x++)
102		{
103		    ((uint32_t*)(uintptr_t)p)[x] = random();
104		}
105		p += rb;
106	    }
107	}
108	printf("fill random(%s) %d times at (%dx%dx32): %g MB/sec\n", mapNames[mapType], i,
109		(int)bounds.size.width, (int)bounds.size.height,
110		i*bounds.size.width*bounds.size.height*4/(1e6*(currentTime() - t)));
111
112	kr = IOConnectUnmapMemory(connect, kIOFBVRAMMemory, mach_task_self(), mapAddr);
113	if (kIOReturnSuccess != kr)
114	{
115	    printf("IOConnectUnmapMemory(%x)\n", kr);
116	    exit(1);
117	}
118    }
119
120    return (0);
121}
122
123