HLo*_*nzi 0 iphone performance opengl-es
我是Xcode编程的新手,我正在尝试使用OpenGL创建一个iPhone游戏,支持60 FPS的视网膜显示,但运行速度太慢.我基于developer.apple上的GLSprite示例.我已经尽可能地优化了它,但它在模拟器上一直运行<30 FPS(我还没有在真实设备上测试它 - 也许它更快?).瓶颈似乎是绘制多边形 - 我使用了非常小的纹理(256x256 PNG)和像素格式(RGBA4444); 我已禁用混合; 我已将所有转换代码移至加载阶段,希望获得更好的性能; 一切都没有成功.我保持一个顶点数组存储一切为了这一步,然后绘制使用GL_TRIANGLES一个函数调用 - 因为我觉得它比调用多个调用glDrawArrays更快.当我达到大约120个顶点(每个矩形精灵6个)时,它开始滞后,但在许多地方我读过iPhone甚至可以处理数百万个顶点.下面的代码有什么问题?OpenGL是在iPhone上渲染图形的最快方式吗?如果没有,我还应该使用什么?
OpenGL加载代码,在开头只调用一次:
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D,texture[0]); //Binds a texture loaded previously with the code given below
glVertexPointer(3, GL_FLOAT, 0, vertexes); //The array holding the vertexes
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, uvCoord); //The array holding the uv coordinates
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
Run Code Online (Sandbox Code Playgroud)
纹理加载方法:
- (void)loadSprite:(NSString*)filename intoPos:(int)pos { //Loads a texture within the bundle, at the given position in an array storing all textures (but I actually just use one at a time)
CGImageRef spriteImage;
CGContextRef spriteContext;
GLubyte *spriteData;
size_t width, height;
// Sets up matrices and transforms for OpenGL ES
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
// Clears the view with black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Sets up pointers and enables states needed for using vertex arrays and textures
glVertexPointer(2, GL_FLOAT, 0, spriteVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, spriteTexcoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Creates a Core Graphics image from an image file
spriteImage = [UIImage imageNamed:filename].CGImage;
// Get the width and height of the image
width = CGImageGetWidth(spriteImage);
height = CGImageGetHeight(spriteImage);
textureWidth[pos]=width;
textureHeight[pos]=height;
NSLog(@"Width %lu; Height %lu",width,height);
// Texture dimensions must be a power of 2. If you write an application that allows users to supply an image,
// you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2.
if(spriteImage) {
// Allocated memory needed for the bitmap context
spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
// Uses the bitmap creation function provided by the Core Graphics framework.
spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
// After you create the context, you can draw the sprite image to the context.
CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), spriteImage);
// You don't need the context at this point, so you need to release it to avoid memory leaks.
CGContextRelease(spriteContext);
// Use OpenGL ES to generate a name for the texture.
glGenTextures(1, &texture[pos]);
// Bind the texture name.
glBindTexture(GL_TEXTURE_2D, texture[pos]);
curTexture=pos;
if (1) { //This should convert pixel format
NSLog(@"convert to 4444");
void* tempData;
unsigned int* inPixel32;
unsigned short* outPixel16;
tempData = malloc(height * width * 2);
inPixel32 = (unsigned int*)spriteData;
outPixel16 = (unsigned short*)tempData;
NSUInteger i;
for(i = 0; i < width * height; ++i, ++inPixel32)
*outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, tempData);
free(tempData);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
}
// Set the texture parameters to use a minifying filter and a linear filer (weighted average)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Specify a 2D texture image, providing the a pointer to the image data in memory
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
// Release the image data
free(spriteData);
// Enable use of the texture
glEnable(GL_TEXTURE_2D);
// Set a blending function to use
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Enable blending
glEnable(GL_BLEND);
}
Run Code Online (Sandbox Code Playgroud)
每个游戏循环调用的实际绘图代码:
glDrawArrays(GL_TRIANGLES, 0, vertexIndex); //vertexIndex is the maximum number of vertexes at this loop
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
Run Code Online (Sandbox Code Playgroud)
根据iOS的OpenGL编程指南:
重要的是,模拟器中OpenGL ES的渲染性能与实际设备上OpenGL ES的性能无关.Simulator提供优化的软件光栅化器,利用Macintosh计算机的矢量处理功能.因此,您的OpenGL ES代码可能在iOS模拟器中运行得更快或更慢(取决于您的计算机和您正在绘制的内容),而不是在实际设备上运行.始终在真实设备上分析和优化您的绘图代码,并且永远不要假设模拟器反映了真实世界的性能.
模拟器不能可靠地分析OpenGL应用程序的性能.您需要在真实硬件上运行/配置文件.
当我达到大约120个顶点(每个矩形精灵6个)时,它开始滞后,但在许多地方我读过iPhone甚至可以处理数百万个顶点.
详细说明你的这个评论:顶点的数量不是唯一影响OpenGL性能的变量.例如,只有一个三角形(3个顶点),你可以在整个屏幕上绘制像素.这显然比绘制仅覆盖几个像素的小三角形需要更多的计算.表示绘制多个像素的容量的度量称为填充率.
如果您的顶点在屏幕上表示大三角形,则填充率可能是您的性能瓶颈,而不是顶点变换.由于iOS模拟器确实使用了软件光栅化器,尽管经过优化,它可能比实际的专用硬件慢.
您应该在优化之前分析您的应用程序以了解您的实际性能瓶颈是什么; 这个文件可以帮到你.
| 归档时间: |
|
| 查看次数: |
2540 次 |
| 最近记录: |