/*cc -o /tmp/readfb readfb.c -framework IOKit -framework ApplicationServices -Wall -g -arch i386 */ #include #include #include #include #include #include IOReturn IOAccelReadFramebuffer(io_service_t framebuffer, uint32_t width, uint32_t height, size_t rowBytes, vm_address_t * result, vm_size_t * bytecount) { IOReturn err; io_service_t accelerator; UInt32 framebufferIndex; size_t size = 0; UInt32 surfaceID = 155; vm_address_t buffer = 0; IOAccelConnect connect = MACH_PORT_NULL; IOAccelDeviceRegion * region = NULL; IOAccelSurfaceInformation surfaceInfo; IOGraphicsAcceleratorInterface ** interface = 0; IOBlitterPtr copyRegionProc; IOBlitCopyRegion op; IOBlitSurface dest; SInt32 quality = 0; *result = 0; *bytecount = 0; dest.interfaceRef = NULL; do { err = IOAccelFindAccelerator(framebuffer, &accelerator, &framebufferIndex); if (kIOReturnSuccess != err) continue; err = IOAccelCreateSurface(accelerator, surfaceID, kIOAccelSurfaceModeWindowedBit | kIOAccelSurfaceModeColorDepth8888, &connect); IOObjectRelease(accelerator); if (kIOReturnSuccess != err) continue; size = rowBytes * height; region = calloc(1, sizeof (IOAccelDeviceRegion) + sizeof(IOAccelBounds)); if (!region) continue; region->num_rects = 1; region->bounds.x = region->rect[0].x = 0; region->bounds.y = region->rect[0].y = 0; region->bounds.h = region->rect[0].h = height; region->bounds.w = region->rect[0].w = width; err = vm_allocate(mach_task_self(), &buffer, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS)); if (kIOReturnSuccess != err) continue; err = IOAccelSetSurfaceFramebufferShapeWithBackingAndLength(connect, region, kIOAccelSurfaceShapeIdentityScaleBit| kIOAccelSurfaceShapeNonBlockingBit| //kIOAccelSurfaceShapeStaleBackingBit | kIOAccelSurfaceShapeNonSimpleBit, 0, (IOVirtualAddress) buffer, (UInt32) rowBytes, (UInt32) size); if (kIOReturnSuccess != err) continue; err = IOCreatePlugInInterfaceForService(framebuffer, kIOGraphicsAcceleratorTypeID, kIOGraphicsAcceleratorInterfaceID, (IOCFPlugInInterface ***)&interface, &quality ); if (kIOReturnSuccess != err) continue; err = (*interface)->GetBlitter(interface, kIOBlitAllOptions, (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), kIOBlitSourceFramebuffer, ©RegionProc); if (kIOReturnSuccess != err) continue; err = (*interface)->AllocateSurface(interface, kIOBlitHasCGSSurface, &dest, (void *) surfaceID); if (kIOReturnSuccess != err) continue; err = (*interface)->SetDestination(interface, kIOBlitSurfaceDestination, &dest); if (kIOReturnSuccess != err) continue; op.region = region; op.deltaX = 0; op.deltaY = 0; err = (*copyRegionProc)(interface, kNilOptions, (kIOBlitTypeCopyRegion | kIOBlitTypeOperationType0), kIOBlitSourceFramebuffer, &op.operation, (void *) 0); if (kIOReturnSuccess != err) continue; (*interface)->Flush(interface, kNilOptions); err = IOAccelWriteLockSurfaceWithOptions(connect, kIOAccelSurfaceLockInBacking, &surfaceInfo, sizeof(surfaceInfo)); if (kIOReturnSuccess != err) continue; (void ) IOAccelWriteUnlockSurfaceWithOptions(connect, kIOAccelSurfaceLockInBacking); } while (false); if (dest.interfaceRef) (*interface)->FreeSurface(interface, kIOBlitHasCGSSurface, &dest); // destroy the surface if (connect) (void) IOAccelDestroySurface(connect); if (region) free(region); if (interface) IODestroyPlugInInterface((IOCFPlugInInterface **)interface); if (kIOReturnSuccess == err) { *result = buffer; *bytecount = size; } return (err); } int main(int argc, char * argv[]) { IOReturn err; CGDirectDisplayID dspy; io_service_t framebuffer; CGRect bounds; vm_address_t buffer; vm_size_t size, rowBytes; framebuffer = CGDisplayIOServicePort(dspy); assert (framebuffer != MACH_PORT_NULL); dspy = CGMainDisplayID(); bounds = CGDisplayBounds(dspy); rowBytes = CGDisplayBytesPerRow(dspy); err = IOAccelReadFramebuffer(framebuffer, bounds.size.width, bounds.size.height, rowBytes, &buffer, &size); if (kIOReturnSuccess == err) { fprintf(stderr, "writing 0x%x bytes from 0x%x\n", size, buffer); write(STDOUT_FILENO, (const void *) buffer, size); vm_deallocate(mach_task_self(), buffer, size); } return (0); }