【问题标题】:iOS OpenGL too slowiOS OpenGL 太慢了
【发布时间】:2012-01-22 00:05:50
【问题描述】:

我是 Xcode 编程的新手,我正在尝试使用支持 60 FPS 视网膜显示的 OpenGL 创建 iPhone 游戏,但运行速度太慢。我基于 developer.apple 上的 GLSprite 示例。我已经尽我所能对其进行了优化,但它在模拟器上一直运行

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

【问题讨论】:

  • 您是否分析过您的代码以查看减速的位置?如果没有,你应该运行 Instruments 并做一个时间样本,看看你的代码在哪里花费了大部分时间。这将告诉您需要进行哪些优化。 OpenGL 应该适合您正在尝试做的事情。

标签: iphone performance opengl-es


【解决方案1】:

根据OpenGL programming guide for iOS

重要 OpenGL ES 在模拟器中的渲染性能与 OpenGL ES 在实际设备上的性能无关。 Simulator 提供了一个优化的软件光栅化器,它采用 充分利用 Macintosh 的矢量处理能力 电脑。因此,您的 OpenGL ES 代码可能运行得更快或更慢 iOS模拟器(取决于您的计算机和您正在绘制的内容) 比在实际设备上。始终配置和优化您的绘图 真实设备上的代码,永远不要假设模拟器反映 真实世界的表现。

模拟器无法可靠地分析 OpenGL 应用程序的性能。您需要在真实硬件上运行/配置文件。

当我达到大约 120 个顶点(每个顶点 6 个)时,它开始滞后 矩形精灵),但在很多地方我读过 iPhone 可以 处理数百万个顶点。

详细说明一下您的评论:顶点的数量并不是影响 OpenGL 性能的唯一变量。例如,只有一个三角形(3 个顶点),您可以在整个屏幕上绘制像素。这显然比绘制仅覆盖几个像素的小三角形需要更多的计算。表示绘制许多像素的能力的指标称为 fill-rate

如果您的顶点代表屏幕上的大三角形,则填充率很可能是您的性能瓶颈,而不是顶点变换。由于 iOS 模拟器确实使用了软件光栅化器,尽管它已经过优化,但它可能比实际的专用硬件要慢。

您应该在优化之前分析您的应用程序以了解您的实际性能瓶颈; this document可以帮到你。

【讨论】:

  • 好吧,但我认为即使是模拟器也可以处理这么少的顶点,所以我认为我的编码必须是问题......
  • 模拟器以速度慢而著称,由于版本不兼容,实际上可能并不总是支持您正在进行的所有 OpenGL ES 调用。
  • @HLorenzi 更新了我的答案,以详细说明您对顶点数的评论。
  • +1 表示正确答案 - 模拟器实际上使用完全在软件中完成的解决方案来模拟设备 GL。结果几乎不会接近您在实际设备上看到的结果。
  • 模拟器中的软件光栅化器与实际硬件有很大不同,即使与最古老的基于 MBX 的设备相比也是如此。它有一些不同的功能集、限制和性能。它不支持“真实”硬件的某些功能,并支持硬件不支持的某些功能。在做任何不平凡的事情时,您不应该浪费时间来找出模拟器的怪癖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-10
  • 2014-06-07
  • 2016-05-31
  • 2011-07-07
  • 2015-08-23
  • 2012-07-05
相关资源
最近更新 更多