1/* 2cc -g -o /tmp/fbshared fbshared.c -framework ApplicationServices -framework IOKit -Wall -arch i386 3*/ 4#define IOCONNECT_MAPMEMORY_10_6 1 5#define IOFB_ARBITRARY_SIZE_CURSOR 6#define IOFB_ARBITRARY_FRAMES_CURSOR 1 7#include <CoreFoundation/CoreFoundation.h> 8#include <ApplicationServices/ApplicationServices.h> 9#include <mach/mach_time.h> 10#include <IOKit/graphics/IOGraphicsLib.h> 11#include <IOKit/graphics/IOFramebufferShared.h> 12#include <IOKit/graphics/IOGraphicsTypesPrivate.h> 13#include <stdlib.h> 14#include <stdio.h> 15 16 17int main(int argc, char * argv[]) 18{ 19 kern_return_t kr; 20 io_iterator_t iter; 21 io_service_t framebuffer; 22 io_string_t path; 23 uint32_t index, maxIndex; 24 io_connect_t connect; 25 mach_timebase_info_data_t timebase; 26 StdFBShmem_t * shmem[16]; 27 vm_size_t shmemSize; 28 CFNumberRef clk, count; 29 vm_address_t mapAddr; 30 31 kr = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching( 32 IOFRAMEBUFFER_CONFORMSTO), &iter); 33 assert( KERN_SUCCESS == kr ); 34 35 for ( index = 0; 36 index++, (framebuffer = IOIteratorNext(iter)); 37 IOObjectRelease(framebuffer)) 38 { 39 kr = IORegistryEntryGetPath(framebuffer, kIOServicePlane, path); 40 assert( KERN_SUCCESS == kr ); 41 printf("\n/* [%d] Using device: %s */\n", index, path); 42 43 clk = IORegistryEntryCreateCFProperty(framebuffer, CFSTR(kIOFBCurrentPixelClockKey), 44 kCFAllocatorDefault, kNilOptions); 45 count = IORegistryEntryCreateCFProperty(framebuffer, CFSTR(kIOFBCurrentPixelCountKey), 46 kCFAllocatorDefault, kNilOptions); 47 if (clk && count) 48 { 49 float num, div; 50 CFNumberGetValue(clk, kCFNumberFloatType, &num); 51 CFNumberGetValue(count, kCFNumberFloatType, &div); 52 printf("clock %.0f, count %.0f, rate %f Hz, period %f us\n", 53 num, div, num / div, div * 1000 / num); 54 } 55 if (clk) 56 CFRelease(clk); 57 if (count) 58 CFRelease(count); 59 60 kr = mach_timebase_info(&timebase); 61 assert(kIOReturnSuccess == kr); 62 63 kr = IOServiceOpen(framebuffer, mach_task_self(), kIOFBSharedConnectType, &connect); 64 if (kIOReturnSuccess != kr) 65 { 66 printf("IOServiceOpen(%x)\n", kr); 67 continue; 68 } 69 kr = IOConnectMapMemory(connect, kIOFBCursorMemory, mach_task_self(), 70 &mapAddr, &shmemSize, 71 kIOMapAnywhere); 72 if (kIOReturnSuccess != kr) 73 { 74 printf("IOConnectMapMemory(%x)\n", kr); 75 continue; 76 } 77 shmem[index] = (StdFBShmem_t *) mapAddr; 78 79 // bzero( shmem, shmemSize); // make sure its read only! 80 81 printf("screenBounds (%d, %d), (%d, %d)\n", 82 shmem[index]->screenBounds.minx, shmem[index]->screenBounds.miny, 83 shmem[index]->screenBounds.maxx, shmem[index]->screenBounds.maxy); 84 85 printf("size[0] (%d, %d)\n", 86 shmem[index]->cursorSize[0].width, shmem[index]->cursorSize[0].height); 87 88 if (shmem[index]->hardwareCursorActive && !shmem[index]->cursorShow) 89 do 90 { 91 struct { 92 uint8_t identLength; 93 uint8_t colorMapType; 94 uint8_t dataType; 95 uint8_t colorMap[5]; 96 uint16_t origin[2]; 97 uint16_t width; 98 uint16_t height; 99 uint8_t bitsPerPixel; 100 uint8_t imageDesc; 101 } hdr; 102 FILE * f; 103 char path[256]; 104 uint8_t * bits; 105 uint32_t w, h, y; 106 107 w = shmem[index]->cursorSize[0].width; 108 h = shmem[index]->cursorSize[0].height; 109 110 bzero(&hdr, sizeof(hdr)); 111 hdr.dataType = 2; 112 hdr.width = OSSwapHostToLittleInt16(w); 113 hdr.height = OSSwapHostToLittleInt16(h); 114 hdr.bitsPerPixel = 32; 115 hdr.imageDesc = (1<<5) | 8; 116 117 snprintf(path, sizeof(path), "/tmp/curs%d.tga", index); 118 f = fopen(path, "w" /*"r+"*/); 119 if (!f) continue; 120 fwrite(&hdr, sizeof(hdr), 1, f); 121 bits = (uint8_t *)(uintptr_t) &shmem[index]->cursor[0]; 122 for (y = 0; y < h; y++) 123 { 124 fwrite(bits, sizeof(uint32_t), w, f); 125 bits += w * sizeof(uint32_t); 126 } 127 fclose(f); 128 } 129 while (false); 130 } 131 132 maxIndex = index; 133 while (true) 134 { 135 printf("\n"); 136 for (index = 0; index < maxIndex; index++) 137 { 138 if (!shmem[index]) 139 continue; 140 141 uint64_t time = (((uint64_t) shmem[index]->vblTime.hi) << 32 | shmem[index]->vblTime.lo); 142 uint64_t delta = (((uint64_t) shmem[index]->vblDelta.hi) << 32 | shmem[index]->vblDelta.lo); 143 double usecs = delta * timebase.numer / timebase.denom / 1e6; 144 145 if (!delta) continue; 146 147 printf("[%d] time of last VBL 0x%qx, delta %qd (%f us), count %qd, measured delta %qd(%f%%), drift %qd(%qd%%)\n", 148 index, time, delta, usecs, shmem[index]->vblCount, 149 shmem[index]->vblDeltaMeasured, ((shmem[index]->vblDeltaMeasured * 100.0) / delta), 150 shmem[index]->vblDrift, ((shmem[index]->vblDrift * 100) / delta)); 151 } 152 for (index = 0; index < maxIndex; index++) 153 { 154 if (!shmem[index]) continue; 155 if ((shmem[index]->screenBounds.maxx - shmem[index]->screenBounds.minx) < 128) continue; 156 157 printf("[%d] cursorShow %d, hw %d, frame %d, loc (%d, %d), hs (%d, %d), cursorRect (%d, %d), (%d, %d), saveRect (%d, %d), (%d, %d)\n", 158 index, 159 shmem[index]->cursorShow, shmem[index]->hardwareCursorActive, 160 shmem[index]->frame, shmem[index]->cursorLoc.x, shmem[index]->cursorLoc.y, 161 shmem[index]->hotSpot[0].x, shmem[index]->hotSpot[0].y, 162 shmem[index]->cursorRect.minx, shmem[index]->cursorRect.miny, 163 shmem[index]->cursorRect.maxx, shmem[index]->cursorRect.maxy, 164 shmem[index]->saveRect.minx, shmem[index]->saveRect.miny, 165 shmem[index]->saveRect.maxx, shmem[index]->saveRect.maxy); 166 } 167 sleep(1); 168 } 169 170 exit(0); 171 return(0); 172} 173 174