iPhone 4S,OpenGL ES似乎太慢了。怎么了?

时间:2013-10-02 15:47:06

标签: iphone ios opengl-es 2d

我使用OpenGL ES在iPhone 4S上为每个帧绘制2560个非常纤细的多边形。问题是我的帧速率大约是30,这对我来说不够顺畅。我认为它应该比那更快。

  1. 是吗?

  2. 请帮我找出可以改进的地方。

  3. UPDATE :我在主线程上进行渲染。是否有关于执行渲染操作的线程的建议?

    有点背景: 我正在尝试在iPhone视图坐标中进行大小为320x200的平滑滚动(目标为60 FPS)波形,因此在视网膜显示屏上为640x400像素。 我的测试设备是iPhone 4S。使用iOS 6和6.1,我可以通过普通的UIKit绘图操作轻松实现这一点。但是,由于我将设备更新到iOS 7,速度要慢得多,所以我决定使用OpenGL ES,因为我多次阅读它可以更快地进行2D绘图。

    我实现了使用OpenGL ES 2.0绘制波形,但现在它在设备上的速度比UIKit快一点。和UIKit一样,速度很大程度上取决于绘制的像素数量,这让我想知道发生了什么。

    波形由条形/矩形组成,每个条形宽度恰好为1个像素。我为每个像素列绘制两个条形,每个条形由两个多边形组成,这意味着我为每个框架绘制1280个条形或2560个多边形。多边形非常纤细。它们中的每一个最多为1个像素宽。我认为使用OpenGL ES以60FPS绘制应该没问题。

    我画了一个这样的栏:

    - (void) glFillRect: (Float32)x0 : (Float32)y0 : (Float32)x1 : (Float32)y1 {
        glEnableVertexAttribArray(GLKVertexAttribPosition);
    
        GLfloat vertices[8];
        glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 0, vertices);
    
        GLfloat* vp = vertices;
        *vp++ = x0; *vp++ = y0;
        *vp++ = x1; *vp++ = y0;
        *vp++ = x0; *vp++ = y1;
        *vp++ = x1; *vp++ = y1;
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
        glDisableVertexAttribArray(GLKVertexAttribPosition);
    }
    

    调用上述方法的代码如下。 _maxDrawing和_ avgDrawing是我的效果,在应用启动时就像这样组成:

    _maxDrawing = [[GLKBaseEffect alloc] init];
    _maxDrawing.useConstantColor = GL_TRUE;
    _maxDrawing.constantColor = GLKVector4Make(0.075f, 0.1f, 0.25f, 1.0f);
    

    我稍后调整投影矩阵,以便我的OpenGL ES绘图坐标与我视图的视图坐标对齐,afaik是2D绘图的标准方法。

    [_maxDrawing prepareToDraw];
    x_Cu = [self transformViewXToWaveformX:rect.origin.x];
    for (Float32 x_Vu = rect.origin.x; x_Vu < viewEndX_Vu; x_Vu += onePixelInViewUnits) {
        x_Cu += onePixelInContentUnits;
        if (x_Cu < 0 || x_Cu >= waveformEndX_Cu) {
            continue;
        }
    
        SInt64 frameIdx = (SInt64) x_Cu;
        CBWaveformElement element;
        element = [self.dataSource getElementContainingFrame:frameIdx];
    
        prevMax = curMax;
        curMax = futureMax;
        futureMax = element.max;
        smoothMax = prevMax * 0.25 + curMax * 0.5 + futureMax * 0.25;
        if (smoothMax < curMax)
            smoothMax = curMax;
    
        Float32 barHeightHalf = smoothMax * heightScaleHalf;
        Float32 barY0 = viewHeightHalf - barHeightHalf;
        Float32 barY1 = viewHeightHalf + barHeightHalf;
        [self glFillRect: x_Vu : barY0 : x_Vu + onePixelInViewUnits : barY1];
    }
    
    [_avgDrawing prepareToDraw];
    x_Cu = [self transformViewXToWaveformX:rect.origin.x];
    for (Float32 x_Vu = rect.origin.x; x_Vu < viewEndX_Vu; x_Vu += onePixelInViewUnits) {
        x_Cu += onePixelInContentUnits;
        if (x_Cu < 0 || x_Cu >= waveformEndX_Cu) {
            continue;
        }
    
        SInt64 frameIdx = (SInt64) x_Cu;
        CBWaveformElement element;
        element = [self.dataSource getElementContainingFrame:frameIdx];
    
        Float32 barHeightHalf = element.avg * heightScaleHalf;
        Float32 barY0 = viewHeightHalf - barHeightHalf;
        Float32 barY1 = viewHeightHalf + barHeightHalf;
        [self glFillRect: x_Vu : barY0 : x_Vu + onePixelInViewUnits : barY1];
    }
    

    当我取出所有OpenGL调用时,一帧的执行持续时间约为1ms,这意味着它理论上可以达到1000 FPS。所有其他时间(约33毫秒)花在绘图上。

1 个答案:

答案 0 :(得分:2)

根据丹尼尔的要求,我发布这个作为解决问题的答案。

在上面的代码中,您似乎每个方框都使用glDrawArrays()来电。这会导致大量的开销带来大量的开销。

更有效的方法是使用包含场景的所有顶点的VBO(可能是动态更新的),或至少包含更大的一组框,并绘制所有这些顶点单个电话。

正如rickster所指出的,iOS 7为实例化添加了一些不错的支持,这也可能是一种帮助。

关于是否在后台线程上渲染,根据我的经验,在后台线程上渲染我的OpenGL ES场景时,我通常会看到显着的性能提升(10-40%,特别是在多核设备上)。使用串行GCD队列,以安全的方式执行此操作也非常容易。