簡體   English   中英

iOS OpenGL太慢

[英]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];

根據適用於iOSOpenGL編程指南

重要的是,模擬器中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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM