2014-06-26 115 views
3

什麼是以高幀率渲染和縮放圖像到表面的最快方法?快速替代drawInRect

我正在繪製(使用縮放)NSBitmapImageRep使用drawRect在〜30FPS,但它使用了大量的CPU。

示例代碼以30FPS設置在NSBitmapImageRep像素:

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 

drawInRect在NSBitmapImageRep使用了大量的CPU。以高幀率縮放和繪製圖像的最快方式是什麼?源圖像應該是可以直接設置像素的圖像。通過獲取一個bitmapData指針。

如果我將NSBitmapImageRep轉換爲CIImage並使用[ciImage drawInRect]進行繪製,則速度提高大約10%。如果我繪製到NSOpenGLView而不是NSView,它再次快10%,但scale/drawInRect仍佔用大量CPU時間。

+0

您是否試圖根據公式爲每個像素着色?這種操作最適合GPU。根據你要做什麼,你的解決方案可以從OpenGL着色器到CoreImage甚至Quartz。 –

+0

這是簡單的卡拉OK圖形,但它不是公式化的:我更新低分辨率的NSBitmapImageRep圖像,然後將該小圖像縮放到約30FPS的屏幕尺寸。在小型NSBitmapImageRep中設置像素速度非常快,但使用drawInRect將圖像正常放大到屏幕尺寸非常緩慢。升級CIImage會更快嗎?或者,當源圖像可以逐個像素地設置時,是否有一些縮放圖像的更快速的方法? – CocoaMug

回答

0

首先,您應該刪除保存並恢復NSGraphicsContext,因爲-[NSImageRep drawInRect:]方法本身會執行此操作。見「可可繪製圖形上下文」:

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

下一點是您的像素數據的結構:每個樣本8位和每像素,這意味着每像素24位3個的樣本。這是非常硬件(GPU?)不友好的原因,因爲32位值比24位值更快處理。有一個簡單的方法可以使像素處理更好(更快):使用4字節而不是3:爲每個像素添加填充字節,這不會損害圖像!該填充字節不是圖像的一部分,但只是像素存儲的一部分,並且不用於任何繪圖操作。這僅僅是使像素操作更快。

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:所以在你NSBitImageRep的說明中使用這個,如果你讀一個JPEG圖像爲NSBitmapImageRep那麼這些imageReps總是有3個字節的像素加上一個填充字節。爲什麼這種浪費存儲?有充足的理由這樣做!

+0

謝謝,我已經刪除上下文保存並移動到32bpp。這很有道理,但32bpp在我的情況下並沒有對性能產生明顯的影響。從200x200擴展到400x400大約需要7%的CPU,但擴展到1600x1600需要34%的CPU,這似乎都在drawInRect()調用中。也許NSBitmapImageRep drawInRect沒有爲我使用GPU。使用CIImage確保GPU處理它更合適嗎? – CocoaMug