我有一个“软件渲染器”,我从PC移植到iPhone。使用iphone上的像素缓冲区手动更新屏幕的最快方法是什么?例如在Windows中,我找到的最快的函数是SetDIBitsToDevice。
我对iphone或库不太了解,似乎有很多层和不同类型的UI元素,所以我可能需要大量的解释...
现在我只是不断更新opengl中的纹理并将其渲染到屏幕上,我非常怀疑这将是最好的方法。
更新:
我尝试过openGL屏幕大小的纹理方法:
我得到了17fps ......
我使用了512x512纹理(因为它需要是2的幂)
只是
的召唤glTexSubImage2D(GL_TEXTURE_2D,0,0,0,512,512,GL_RGBA,GL_UNSIGNED_BYTE, baseWindowGUI->GetBuffer());
似乎对所有减速负责。
将其评论出来,并留下我所有的软件渲染GUI代码,以及现在非更新纹理的渲染,导致60fps,30%的渲染器使用率,以及来自cpu的没有明显的峰值。
请注意,GetBuffer()只返回一个指向GUI系统软件后台缓冲区的指针,无论如何都没有重新调整缓冲区或调整缓冲区大小,它的大小和纹理格式正确,所以我相当肯定减速与软件渲染器无关,这是个好消息,看起来如果我能找到一种方法在60点更新屏幕,软件渲染应该暂时有用。
我尝试使用512,320而不是512,512进行更新纹理调用,这奇怪甚至更慢...以10fps运行,也表示渲染利用率仅为5%,并且所有时间都被浪费在调用在openGLES里面unntwiddle32bpp。
我可以将我的软件渲染更改为原生渲染为任何pixle格式,如果它会导致更直接的blit。
fyi,在2.2.1 ipod touch G2上测试(就像类固醇上的Iphone 3G一样)
更新2:
我刚刚写完了CoreAnimation / Graphics方法,它看起来不错,但是我有点担心它如何更新每一帧的屏幕,基本上抛弃旧的CGImage,创建一个全新的...查看它在下面的'someRandomFunction'中: 这是更新图像的最快方法吗?任何帮助将不胜感激。
//
// catestAppDelegate.m
// catest
//
// Created by User on 3/14/10.
// Copyright __MyCompanyName__ 2010. All rights reserved.
//
#import "catestAppDelegate.h"
#import "catestViewController.h"
#import "QuartzCore/QuartzCore.h"
const void* GetBytePointer(void* info)
{
// this is currently only called once
return info; // info is a pointer to the buffer
}
void ReleaseBytePointer(void*info, const void* pointer)
{
// don't care, just using the one static buffer at the moment
}
size_t GetBytesAtPosition(void* info, void* buffer, off_t position, size_t count)
{
// I don't think this ever gets called
memcpy(buffer, ((char*)info) + position, count);
return count;
}
CGDataProviderDirectCallbacks providerCallbacks =
{ 0, GetBytePointer, ReleaseBytePointer, GetBytesAtPosition, 0 };
static CGImageRef cgIm;
static CGDataProviderRef dataProvider;
unsigned char* imageData;
const size_t imageDataSize = 320 * 480 * 4;
NSTimer *animationTimer;
NSTimeInterval animationInterval= 1.0f/60.0f;
@implementation catestAppDelegate
@synthesize window;
@synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window makeKeyAndVisible];
const size_t byteRowSize = 320 * 4;
imageData = malloc(imageDataSize);
for(int i=0;i<imageDataSize/4;i++)
((unsigned int*)imageData)[i] = 0xFFFF00FF; // just set it to some random init color, currently yellow
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
dataProvider =
CGDataProviderCreateDirect(imageData, imageDataSize,
&providerCallbacks); // currently global
cgIm = CGImageCreate
(320, 480,
8, 32, 320*4, colorSpace,
kCGImageAlphaNone | kCGBitmapByteOrder32Little,
dataProvider, 0, false, kCGRenderingIntentDefault); // also global, probably doesn't need to be
self.window.layer.contents = cgIm; // set the UIWindow's CALayer's contents to the image, yay works!
// CGImageRelease(cgIm); // we should do this at some stage...
// CGDataProviderRelease(dataProvider);
animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(someRandomFunction) userInfo:nil repeats:YES];
// set up a timer in the attempt to update the image
}
float col = 0;
-(void)someRandomFunction
{
// update the original buffer
for(int i=0;i<imageDataSize;i++)
imageData[i] = (unsigned char)(int)col;
col+=256.0f/60.0f;
// and currently the only way I know how to apply that buffer update to the screen is to
// create a new image and bind it to the layer...???
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
cgIm = CGImageCreate
(320, 480,
8, 32, 320*4, colorSpace,
kCGImageAlphaNone | kCGBitmapByteOrder32Little,
dataProvider, 0, false, kCGRenderingIntentDefault);
CGColorSpaceRelease(colorSpace);
self.window.layer.contents = cgIm;
// and that currently works, updating the screen, but i don't know how well it runs...
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
@end
答案 0 :(得分:11)
App Store批准的最快的仅使用CPU的2D图形的方法是使用CGImage
创建一个由缓冲区支持的CGDataProviderCreateDirect
并将其分配给CALayer
的{{1}属性。
为获得最佳效果,请使用contents
或kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little
位图类型和双缓冲区,以便显示永远不会处于不一致状态。
编辑:这应该比理论上绘制到OpenGL纹理更快,但是一如既往,配置文件可以肯定。
edit2:无论您使用哪种合成方法,kCGImageAlphaNone | kCGBitmapByteOrder32Little
都是一个有用的类。
答案 1 :(得分:3)
最快的方法是使用IOFrameBuffer / IOSurface,它们是私有框架。
因此,OpenGL似乎是AppStore应用程序的唯一可行方式。
答案 2 :(得分:3)
只是以答案的形式将我的评论发布到@ rpetrich的答案,我会在测试中说我发现OpenGL是最快的方式。我已经实现了一个名为EEPixelViewer的简单对象(UIView子类),这个对象通用性很强,它应该适用于我认为的大多数人。
它使用OpenGL将各种格式的像素(24bpp RGB,32位RGBA和几种YpCbCr格式)尽可能高效地推送到屏幕。该解决方案几乎在每个iOS设备(包括旧设备)上实现了大多数像素格式的60fps。用法非常简单,不需要OpenGL知识:
pixelViewer.pixelFormat = kCVPixelFormatType_32RGBA;
pixelViewer.sourceImageSize = CGSizeMake(1024, 768);
EEPixelViewerPlane plane;
plane.width = 1024;
plane.height = 768;
plane.data = pixelBuffer;
plane.rowBytes = plane.width * 4;
[pixelViewer displayPixelBufferPlanes: &plane count: 1 withCompletion:nil];
对每个帧重复displayPixelBufferPlanes调用(使用glTexImage2D将像素缓冲区加载到GPU),这几乎就是它的全部内容。代码很聪明,因为它试图将GPU用于任何所需的简单处理,例如置换颜色通道,将YpCbCr转换为RGB等。
使用UIView的contentMode
属性来实现扩展也有很多逻辑,所以UIViewContentModeScaleToFit
/ Fill等都按预期工作。
答案 3 :(得分:1)
也许您可以将软件渲染器中使用的方法抽象为GPU着色器......可能会获得更好的性能。您需要将编码的“视频”数据作为纹理发送。
答案 4 :(得分:0)
比CGDataProvider
和glTexSubImage
更快的方法是使用CVOpenGLESTextureCache
。 CVOpenGLESTextureCache
允许您直接修改图形内存中的OpenGL纹理而无需重新上传。
我将它用于快速动画视图,你可以在这里看到:
https://github.com/justinmeiners/image-sequence-streaming
使用起来有点棘手,我在问自己关于这个主题的问题后遇到了它:How to directly update pixels - with CGImage and direct CGDataProvider