1/*cc -o /tmp/readfb readfb.c -framework IOKit -framework ApplicationServices -Wall -g -arch i386 2*/ 3 4 5#include <IOKit/IOKitLib.h> 6#include <ApplicationServices/ApplicationServices.h> 7#include <IOKit/i2c/IOI2CInterface.h> 8#include <IOKit/graphics/IOFramebufferShared.h> 9#include <IOKit/graphics/IOAccelSurfaceControl.h> 10#include <IOKit/graphics/IOGraphicsLib.h> 11 12 13IOReturn 14IOAccelReadFramebuffer(io_service_t framebuffer, uint32_t width, uint32_t height, size_t rowBytes, 15 vm_address_t * result, vm_size_t * bytecount) 16{ 17 IOReturn err; 18 io_service_t accelerator; 19 UInt32 framebufferIndex; 20 size_t size = 0; 21 UInt32 surfaceID = 155; 22 vm_address_t buffer = 0; 23 IOAccelConnect connect = MACH_PORT_NULL; 24 IOAccelDeviceRegion * region = NULL; 25 IOAccelSurfaceInformation surfaceInfo; 26 IOGraphicsAcceleratorInterface ** interface = 0; 27 IOBlitterPtr copyRegionProc; 28 IOBlitCopyRegion op; 29 IOBlitSurface dest; 30 SInt32 quality = 0; 31 32 *result = 0; 33 *bytecount = 0; 34 dest.interfaceRef = NULL; 35 36 do 37 { 38 err = IOAccelFindAccelerator(framebuffer, &accelerator, &framebufferIndex); 39 if (kIOReturnSuccess != err) continue; 40 err = IOAccelCreateSurface(accelerator, surfaceID, 41 kIOAccelSurfaceModeWindowedBit | kIOAccelSurfaceModeColorDepth8888, 42 &connect); 43 IOObjectRelease(accelerator); 44 if (kIOReturnSuccess != err) continue; 45 46 size = rowBytes * height; 47 48 region = calloc(1, sizeof (IOAccelDeviceRegion) + sizeof(IOAccelBounds)); 49 if (!region) continue; 50 51 region->num_rects = 1; 52 region->bounds.x = region->rect[0].x = 0; 53 region->bounds.y = region->rect[0].y = 0; 54 region->bounds.h = region->rect[0].h = height; 55 region->bounds.w = region->rect[0].w = width; 56 57 err = vm_allocate(mach_task_self(), &buffer, size, 58 VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS)); 59 if (kIOReturnSuccess != err) continue; 60 61 err = IOAccelSetSurfaceFramebufferShapeWithBackingAndLength(connect, region, 62 kIOAccelSurfaceShapeIdentityScaleBit| 63 kIOAccelSurfaceShapeNonBlockingBit| 64 //kIOAccelSurfaceShapeStaleBackingBit | 65 kIOAccelSurfaceShapeNonSimpleBit, 66 0, 67 (IOVirtualAddress) buffer, 68 (UInt32) rowBytes, 69 (UInt32) size); 70 if (kIOReturnSuccess != err) continue; 71 err = IOCreatePlugInInterfaceForService(framebuffer, 72 kIOGraphicsAcceleratorTypeID, 73 kIOGraphicsAcceleratorInterfaceID, 74 (IOCFPlugInInterface ***)&interface, &quality ); 75 if (kIOReturnSuccess != err) continue; 76 err = (*interface)->GetBlitter(interface, 77 kIOBlitAllOptions, 78 (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), 79 kIOBlitSourceFramebuffer, 80 ©RegionProc); 81 if (kIOReturnSuccess != err) continue; 82 err = (*interface)->AllocateSurface(interface, kIOBlitHasCGSSurface, &dest, (void *) surfaceID); 83 if (kIOReturnSuccess != err) continue; 84 err = (*interface)->SetDestination(interface, kIOBlitSurfaceDestination, &dest); 85 if (kIOReturnSuccess != err) continue; 86 op.region = region; 87 op.deltaX = 0; 88 op.deltaY = 0; 89 err = (*copyRegionProc)(interface, 90 kNilOptions, 91 (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), 92 kIOBlitSourceFramebuffer, 93 &op.operation, 94 (void *) 0); 95 if (kIOReturnSuccess != err) continue; 96 (*interface)->Flush(interface, kNilOptions); 97 err = IOAccelWriteLockSurfaceWithOptions(connect, 98 kIOAccelSurfaceLockInBacking, &surfaceInfo, sizeof(surfaceInfo)); 99 if (kIOReturnSuccess != err) continue; 100 101 (void ) IOAccelWriteUnlockSurfaceWithOptions(connect, kIOAccelSurfaceLockInBacking); 102 } 103 while (false); 104 105 if (dest.interfaceRef) (*interface)->FreeSurface(interface, kIOBlitHasCGSSurface, &dest); 106 107 // destroy the surface 108 if (connect) (void) IOAccelDestroySurface(connect); 109 110 if (region) free(region); 111 112 if (interface) IODestroyPlugInInterface((IOCFPlugInInterface **)interface); 113 114 if (kIOReturnSuccess == err) 115 { 116 *result = buffer; 117 *bytecount = size; 118 } 119 120 return (err); 121} 122 123int main(int argc, char * argv[]) 124{ 125 IOReturn err; 126 CGDirectDisplayID dspy = CGMainDisplayID(); 127 io_service_t framebuffer; 128 CGRect bounds; 129 vm_address_t buffer; 130 vm_size_t size, rowBytes; 131 132 framebuffer = CGDisplayIOServicePort(dspy); 133 assert (framebuffer != MACH_PORT_NULL); 134 dspy = CGMainDisplayID(); 135 bounds = CGDisplayBounds(dspy); 136 rowBytes = CGDisplayBytesPerRow(dspy); 137 138 err = IOAccelReadFramebuffer(framebuffer, bounds.size.width, bounds.size.height, rowBytes, 139 &buffer, &size); 140 if (kIOReturnSuccess == err) 141 { 142 fprintf(stderr, "writing 0x%x bytes from 0x%x\n", size, buffer); 143 write(STDOUT_FILENO, (const void *) buffer, size); 144 vm_deallocate(mach_task_self(), buffer, size); 145 } 146 return (0); 147} 148 149