2013-10-02 33 views
0

我使用OpenGL ES爲iPhone 4S上的每一幀繪製了2560個非常纖細的多邊形。問題是,我得到30左右的幀速率,這對我的口味來說不夠流暢。我認爲它應該比這更快。iPhone 4S,OpenGL ES似乎太慢了。怎麼了?

  1. 是嗎?

  2. 請幫我找出可以改進的地方。

更新:我在主線程渲染。有沒有關於執行渲染操作的線程的建議?

有點背景: 我試圖做一個平穩滾動(目標是60 FPS)在iPhone視圖座標尺寸320×200的波形,視網膜顯示屏上,這樣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調用,一幀的執行時間爲1毫秒左右,這意味着理論上可以上升到1000 FPS。所有其他時間(大約33ms)都花費在繪圖上。

+0

您需要爲動畫使用着色器和矩陣。對不起,但在glDrawArrays看起來之前計算頂點... – SAKrisT

+3

如果我讀了這個權利,你正在爲這些盒子中的每一個做一個'glDrawArrays()'調用?這將在通話中引入很多開銷。相反,你可以創建一個動態更新的VBO與所有的頂點,並繪製每幀一次? –

+0

@BradLarson,這提供了8倍的性能增益。謝謝!!! –

回答

2

根據丹尼爾的要求,我發佈這個問題作爲解答問題的答案。

在上面的代碼中,看起來您使用的是每個框中的glDrawArrays()調用。這會導致很多盒子的大量開銷。

解決這個問題的一種更有效的方法是使用一個VBO(可能是一個動態更新的),它包含你的場景的所有頂點,或者至少一個更大的盒子組,並且用一個電話。正如rickerster指出的那樣,iOS 7爲實例添加了一些不錯的支持,這也可能是一個幫助。

關於是否在後臺線程上渲染,以我的經驗來看,在後臺線程渲染我的OpenGL ES場景時,我經常看到顯着的性能提升(10-40%,特別是在多核設備上)。使用串行GCD隊列,以安全的方式執行該操作也非常容易。