dear XCopyArea, please stop exploring your frame buffer, it freaks me out.
Here's today's unanswerable Mac programming question:
When I'm copying bits from an image to a window, Shark seems to show that I'm spending more than half of my time doing colorspace conversions:
- 29.9% CGContextDrawImage
29.9% CGContextDelegateDrawImage
29.7% ripc_DrawImage
20.6% ripc_AcquireImage
20.0% CGSImageDataLockWithReference
19.8% img_data_lock
16.5% img_colormatch_read
14.6% CGColorTransformConvertData
14.4% CWMatchBitmap
My understanding is that this should only happen if my image and context did not have the same colorspace; if the colorspaces were already the same, then this should turn into basically a memmove(), which is what I want. (And what X11.app appears to accomplish somehow.)
In the case I'm looking at, I'm trying to copy a rectangle from a window, back onto itself, without scaling. Say, 50x50@10,10 to 50x50@200,200. I'm getting the bits off of the window with:
- NSBitmapImageRep *bm = [NSBitmapImageRep alloc];
[bm initWithFocusedViewRect:rect];
CGDataProviderRef prov = CGDataProviderCreateWithData (...);
CGImageRef cgi = CGImageCreate (...);
The colorspace I'm using when creating that image is the default one of this window's CGDirectDisplayID, so it should match:
- CMGetProfileByAVID ((CMDisplayIDType) cgdpy, &profile);
colorspace = CGColorSpaceCreateWithPlatformColorSpace (profile);
Then I draw the bits back onto the window with CGContextDrawImage(). CGImageGetColorSpace() says the image I'm drawing has the color space I expect. So how do I tell why I'm getting a colorspace mismatch?
I also hate that this process involves copying the image data at least twice, but I don't see any way around that. But the main problem here seems to be that not only is it copying it, it's bit-twiddling it too.
Reading the bits off the window is also slow, but according to Shark, it doesn't seem to be calling any obvious "convert" routines; looks like it spends all of its time directly inside of _NSReadImage:
- 30.1% -[NSBitmapImageRep initWithFocusedViewRect:]
28.5% _NSReadImage
3.4% _NSImageRealloc
0.4% CGSLockWindowRectBits
0.4% _NSImageMalloc
0.4% CGSUnlockWindowBits
1.3% -[NSBitmapImageRep initWithBitmapDataPlanes:...]
The thing is, I'm just implementing the X11 routine XCopyArea() here. When running an actual X11 program against Apple's X11.app, XCopyArea() is fast, so I know that it's possible to move bits around in the frame buffer fast, in a 2D-graphics context. I just can't see how. I'm guessing that the real X11 server is not going in via NSBitmapImageRep and CGContextDrawImage(), but I have yet to find any lower level API that will give me more direct access to an NSView's backing store.