[英]iOS OpenGL too slow
我是Xcode編程的新手,我正在嘗試使用OpenGL創建iPhone游戲,並以60 FPS的速度支持視網膜顯示,但是運行速度太慢。 我基於developer.apple上的GLSprite示例。 我已經盡我所能對其進行了優化,但是它在Simulator上始終保持<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);
紋理加載方法:
- (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);
}
在每個游戲循環中調用的實際繪圖代碼:
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];
根據適用於iOS的OpenGL編程指南 :
重要的是,模擬器中OpenGL ES的渲染性能與實際設備上OpenGL ES的性能無關。 Simulator提供了一個優化的軟件光柵化程序,它可以利用Macintosh計算機的矢量處理功能。 結果,與實際設備相比,您的OpenGL ES代碼在iOS模擬器中運行的速度可能更快或更慢(具體取決於您的計算機和繪圖內容)。 始終在真實設備上剖析和優化您的繪圖代碼,永遠不要假設Simulator反映了真實的性能。
該模擬器對於分析OpenGL應用程序的性能不可靠。 您需要在實際硬件上運行/配置文件。
當我達到大約120個頂點(每個矩形精靈6個)時,它開始滯后,但是在許多地方,我讀過iPhone甚至可以處理數百萬個頂點。
要詳細說明一下:頂點數不是影響OpenGL性能的唯一變量,例如,只有一個三角形(3個頂點),您就可以在整個屏幕上繪制像素。 與繪制僅覆蓋幾個像素的小三角形相比,這顯然需要更多的計算。 表示繪制許多像素的能力的度量標准稱為填充率 。
如果您的頂點表示屏幕上的大三角形,則填充率很可能是您的性能瓶頸,而不是頂點變換。 盡管優化了,但iOS模擬器確實使用了軟件光柵化程序,因此實際專用硬件的運行速度可能會較慢。
您應該在優化之前對應用程序進行概要分析,以了解您的實際性能瓶頸; 本文檔可以為您提供幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.