drawInRect的快速替代方案

时间:2014-06-26 23:49:42

标签: objective-c macos cocoa

以高帧速率渲染图像并将图像缩放到曲面的最快方法是什么?

我正在绘制(使用缩放)一个NSBitmapImageRep,使用drawRect在~30FPS,但它使用了大量的CPU。

用于设置NSFitmapImageRep中30FPS像素的示例代码:

NSInteger x, y;
unsigned char *imgptr = nsBitmapImageRepObj.bitmapData;
unsigned char *ptr;
NSInteger rowBytes = nsBitmapImageRepObj.bytesPerRow;

for (y = 0; y < nsInputFrameRect.size.height; y++) {
    ptr = imgptr + (y * rowBytes);
    for (x = 0; x < nsInputFrameRect.size.width; x++) {
        *ptr++ = 1; // R
        *ptr++ = 2; // G
        *ptr++ = 3; // B
    }

}
[self setNeedsDisplay:YES];

抽签发生在30FPS:

- (void)drawRect:(NSRect)pRect {
    [NSGraphicsContext saveGraphicsState];    
    [nsBitmapImageRepObj drawInRect:pRect];
    [NSGraphicsContext restoreGraphicsState];    
} // end drawRect

NSBitmapImageRep上的drawInRect使用了大量的CPU。以高帧速率缩放和绘制图像的最快方法是什么?源图像应该是我可以直接设置像素的图像,例如通过获取bitmapData指针。

如果我将NSBitmapImageRep转换为CIImage并使用[ciImage drawInRect]进行绘制,那么它的速度提高了大约10%。如果我绘制NSOpenGLView而不是NSView,它再次快10%,但是scale / drawInRect仍占用大量的CPU时间。

1 个答案:

答案 0 :(得分:0)

首先,您应该删除保存并恢复NSGraphicsContext,因为-[NSImageRep drawInRect:]方法会自行执行此操作。请参阅&#34; Cocoa绘图图形上下文&#34;:

Important: Saving and restoring the current graphics state is a relatively expensive operation that should done as little as possible.

下一点是像素数据的结构:每个样本8位,每个像素3个样本,这意味着每像素24位。这是非常硬件(GPU?)不友好,因为32位值比24位值更快处理。有一种简单的方法可以使像素处理更好(更快):使用4个字节而不是3个:为每个像素添加填充字节,这不会损害图像!此填充字节不是图像的一部分,而只是存储像素的存储的一部分,并且不用于任何绘图操作。只是在这里使像素操作更快。因此,请在NSBitImageRep

的说明中使用此功能
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO    // must be meshed
bytesPerRow:0  // let the system do it
bitsPerPixel:32   // <-- important !!

因此您的代码必须修改:

    *ptr++ = 3; // B
    *ptr++ = 123; // new!! value is unimportant

BTW:如果你将jpeg-image读入NSBitmapImageRep,那么这些imageReps总是有3个字节的像素加上一个填充字节。为什么这会浪费存储?有充分的理由这样做!