代码之家  ›  专栏  ›  技术社区  ›  f3r3nc

为什么iPhone上的OpenGL ES代码速度慢?

  •  6
  • f3r3nc  · 技术社区  · 17 年前

    在学习OpenGL ES时,我稍微修改了iPhone SDK的GLSprite示例,结果发现速度非常慢。即使在模拟器中(在硬件最差的情况下),我一定是做错了什么,因为它只有400个纹理三角形。

    const GLfloat spriteVertices[] = {
      0.0f, 0.0f, 
      100.0f, 0.0f,  
      0.0f, 100.0f,
      100.0f, 100.0f
    };
    
    const GLshort spriteTexcoords[] = {
      0,0,
      1,0,
      0,1,
      1,1
    };
    
    - (void)setupView {
        glViewport(0, 0, backingWidth, backingHeight);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrthof(0.0f, backingWidth, backingHeight,0.0f, -10.0f, 10.0f);
        glMatrixMode(GL_MODELVIEW);
    
        glClearColor(0.3f, 0.0f, 0.0f, 1.0f);
    
        glVertexPointer(2, GL_FLOAT, 0, spriteVertices);
        glEnableClientState(GL_VERTEX_ARRAY);
        glTexCoordPointer(2, GL_SHORT, 0, spriteTexcoords);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    
        // sprite data is preloaded. 512x512 rgba8888   
        glGenTextures(1, &spriteTexture);
        glBindTexture(GL_TEXTURE_2D, spriteTexture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
        free(spriteData);
    
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
        glEnable(GL_TEXTURE_2D);
        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        glEnable(GL_BLEND);
    } 
    
    - (void)drawView {
      ..
        glClear(GL_COLOR_BUFFER_BIT);
        glLoadIdentity();
        glTranslatef(tx-100, ty-100,10);
        for (int i=0; i<200; i++) { 
            glTranslatef(1, 1, 0);
            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        }
      ..
    }
    

    每次触摸屏幕或移动屏幕上的手指时都会调用drawView,tx,ty设置为触摸发生的x,y坐标。

    我也尝试过使用GLBuffer,当翻译是预先生成的,只有一个DrawArray,但提供了相同的性能(~4fps)。

    同时,我对其进行了修改,以便使用更小的四边形(大小:34x20),并且完成的重叠更少。大约有400个四元组->800个三角形分布在整个屏幕上。纹理坐标为浮动时,纹理大小为512x512 atlas和RGBA_8888。 现在可以产生约45 FPS。

    5 回复  |  直到 13 年前
        1
  •  19
  •   Bruce Miller    16 年前

    (我知道现在已经很晚了,但我还是忍不住。我还是会发帖的,以防其他人来这里寻求建议。)

    这与纹理大小无关。我不知道为什么人们给零分。他似乎对OpenGL管道有一个根本性的误解。他似乎认为,对于给定的三角形,整个纹理被加载并映射到该三角形上。事实恰恰相反。

    将三角形映射到视口后,将对其进行栅格化。对于三角形覆盖的每个屏幕像素,称为片段着色器。默认的片段着色器(您正在使用的OpenGL ES 1.1)将查找与正在绘制的像素最接近(GL_最接近)的纹理。它可能会查找4个texel,因为您正在使用更高质量的GL_线性方法来平均最佳texel。尽管如此,如果三角形中的像素数是,比如说100,那么你需要读取的最多纹理字节数是4(查找)*100(像素)*4(每种颜色的字节数)。远低于Nils所说的。令人惊讶的是,他能让人觉得他真的知道自己在说什么。

    在平铺体系结构中,这在嵌入式OpenGL设备中很常见,以保持引用的局部性。我相信每个瓷砖都会暴露在每个绘图操作中,很快就会剔除其中的大部分。然后瓷砖决定自己画什么。这将是慢得多,当你有混合打开,因为你这样做。因为您使用的是可能与其他瓷砖重叠和混合的大三角形,所以GPU必须做大量额外的工作。如果不使用alpha边渲染示例正方形,而是渲染实际形状(而不是形状的方形图片),则可以关闭场景这一部分的混合,我打赌这将大大加快速度。

    如果你想试试,只需关闭混合,看看速度有多快,即使看起来不对劲。glDisable(GLU混合);

        2
  •  3
  •   Martin Nordholts    13 年前

    你的纹理是每像素512*512*4字节。这是一兆字节的数据。如果每帧渲染200次,则每帧生成200兆字节的带宽负载。

    仅对于纹理读取,大约4fps的速度就消耗800mb/秒。帧写入和Zbuffer写入也需要带宽。还有CPU,不要低估显示器的带宽要求。

    嵌入式系统(如iphone)上的RAM速度不如台式PC上的快。您在这里看到的是带宽不足效应。RAM根本无法更快地处理数据。

    如何解决这个问题:

    • 选择一个合理的纹理大小。平均而言,每个像素应该有1 texel。这会产生清晰的纹理。我知道——这并不总是可能的。运用常识。

    • 使用mipmap。这将占用33%的额外空间,但允许图形芯片在可能的情况下使用较低分辨率的mipmap进行拾取。

    • 尝试更小的纹理格式。也许您可以使用ARGB4444格式。这将使渲染速度加倍。还可以查看压缩的纹理格式。解压缩不会像在硬件中那样导致性能下降。事实恰恰相反:由于内存较小,图形芯片可以更快地读取纹理数据。

        3
  •  2
  •   f3r3nc    17 年前

    iPhone有一个PowerVR MBX Lite,它有一个基于平铺的图形处理器。它将屏幕细分为较小的平铺,并将其平行渲染。现在,在第一种情况下,上面的细分可能会有点疲惫,因为重叠非常高。此外,由于距离相同,它们无法被剪裁,因此必须计算所有纹理坐标(这可以通过更改循环中的平移来轻松测试)。 另外,由于重叠,并行性无法被利用,一些瓦片什么也不做,其余的(1/3)工作很多。

    所以我认为,虽然内存带宽可能是一个瓶颈,但本例中并非如此。问题更多的是因为图形硬件的工作方式和测试的设置。

        4
  •  0
  •   Maciej Gryka    17 年前

    我不熟悉iPhone,但如果它没有处理浮点数字的专用硬件(我怀疑它没有),那么尽可能使用整数会更快。

    我目前正在为Android开发(它也使用OpenGL ES),例如,我的顶点数组是int而不是float。我不能说这有多大的不同,但我想值得一试。

        5
  •  0
  •   user61805    17 年前

    苹果对iPhone的具体硬件规格守口如瓶,对于我们这些来自控制台背景的人来说,这似乎很奇怪。但是人们已经能够确定CPU是32位RISC ARM1176JZF . 好消息是它有一个完整的浮点单元,所以我们可以继续像在大多数平台上那样编写数学和物理代码。

    http://gamesfromwithin.com/?p=239