2014-04-28 117 views
1

我目前正在使用基於Apple的GLPaint示例的庫,用於在Open GL中的屏幕上繪圖。目前,當畫布保存並恢復會話時,繪製線條(可以看到進度),並且如果有很多點要渲染,則需要相當多的時間。有什麼辦法可以讓它平行或更快地渲染?OpenGL GLPaint線程渲染

這是我使用的繪圖代碼:

CGPoint start = step.start; 
CGPoint end = step.end; 

// Convert touch point from UIView referential to OpenGL one (upside-down flip) 
CGRect bounds = [self bounds]; 
start.y = bounds.size.height - start.y; 
end.y = bounds.size.height - end.y; 

static GLfloat*  vertexBuffer = NULL; 
static NSUInteger vertexMax = 64; 
NSUInteger   vertexCount = 0, 
count, 
i; 

[EAGLContext setCurrentContext:context]; 
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); 

// Convert locations from Points to Pixels 
CGFloat scale = self.contentScaleFactor; 
start.x *= scale; 
start.y *= scale; 
end.x *= scale; 
end.y *= scale; 

// Allocate vertex array buffer 
if(vertexBuffer == NULL) 
    vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat)); 

// Add points to the buffer so there are drawing points every X pixels 
count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y))/kBrushPixelStep), 1); 
for(i = 0; i < count; ++i) { 
    if(vertexCount == vertexMax) { 
     vertexMax = 2 * vertexMax; 
     vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat)); 
    } 

    vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i/(GLfloat)count); 
    vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i/(GLfloat)count); 
    vertexCount += 1; 
} 

// Render the vertex array 
glVertexPointer(2, GL_FLOAT, 0, vertexBuffer); 
glDrawArrays(GL_POINTS, 0, (int)vertexCount); 

// Display the buffer 
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); 
[context presentRenderbuffer:GL_RENDERBUFFER_OES]; 
+0

我們在談論多少分?我解釋代碼的方式,它需要兩個屏幕位置(可能來自觸摸輸入),並在每個「kBrushPixelStep」像素之間繪製點。那應該不是那麼多點吧?或者你是否調用了我們重複看到的代碼,使用不同的'start'和'end'值? –

+0

@ReetoKoradi代碼被重複調用,一個包含多個步驟(每個都有起始和結束座標)的數組調用每個步驟的函數 –

回答

1

OpenGL是不是多線程。您必須從單個線程提交OpenGL命令。

你有兩個選擇:

  1. 那麼您可以您的代碼以使用併發來構建您發送到OpenGL的數據,然後將其提交到OpenGL的API,一旦它的所有可用。

  2. 您可以重構它來使用着色器進行計算。這將計算從CPU推到了GPU上,GPU對並行操作進行了高度優化。

上面的代碼使用realloc在for循環中重複分配一個緩衝區。這是非常低效的,因爲內存分配是現代操作系統中最慢的基於RAM的操作之一。您應該重構代碼以預先計算內存緩衝區的最終大小,然後以最終大小分配緩衝區一次,而不是使用realloc。這應該會讓你以很少的努力提高許多次速度。

看着你的代碼,重構你的for循環將頂點計算分解成塊並提交這些塊到GCD進行併發處理應該不難。訣竅在於將任務分解爲足夠大的工作單元,以便從並行處理中受益(在設置任務以在後臺隊列中運行時存在一定的開銷。您希望在每個工作單元中完成足夠的工作使這個開銷值得。)

+0

發佈的代碼在每次通過循環時都不會重新分配。每次將其填充到當前大小時,它會以兩倍的大小進行分配。這是動態調整緩衝區大小的一種非常有效的方法。當然,如果大小可以提前計算,那會更好。 –

+0

在我發表我的評論之後,我意識到這一點,但放棄了它,因爲重新分配是緩慢和不必要的。正如我所說的,內存分配是基於內存的最慢操作之一。 –

0

我相信上面的評論中的對話顯示了你的性能問題的主要部分。除非我完全誤會了吧,你的代碼的高層結構目前看起來是這樣的:

loop over steps 
    calculate list of points from start/end points 
    render list of points 
    present the renderbuffer 
end loop 

它應該是大規模更快地出席了渲染的所有步驟後,才渲染:

loop over steps 
    generate list of points from start/end points 
    draw list of points 
end loop 
present the renderbuffer 

即使更好地,爲每個步驟生成一個頂點緩衝對象(aka VBO)作爲創建它的一部分,並將該步驟的點的座標存儲在緩衝區中。然後你的抽獎邏輯變成:

loop over steps 
    bind VBO for step 
    draw content of VBO 
end loop 
present the renderbuffer