2016-01-21 41 views
0

我有(多個)UIViewsCAEAGLLayer類型的層,並且能夠在輔助線程上附加到這些圖層的渲染緩衝區上調用[EAGLContext presentRenderBuffer:],沒有任何形式的圖形故障。在輔助線程上調用[EAGLContext presentRenderBuffer:]是否安全?

我會期望看到至少有一些撕裂,因爲這些UIViews合成的其他UI在主線程上更新。 CAEAGLLayer(我有kEAGLDrawablePropertyRetainedBacking設爲NO)在後臺做一些雙緩衝?

我只是想知道爲什麼它是這個工程......

例子:

BViewUIView子類,它擁有與分配給它的OpenGLES層渲染存儲幀緩存,在共享EAGLContext

@implementation BView 

-(id) initWithFrame:(CGRect)frame context:(EAGLContext*)context 
{ 
    self = [super initWithFrame:frame]; 

    // Configure layer 
    CAEAGLLayer* eaglLayer = (CAEAGLLayer*)self.layer; 
    eaglLayer.opaque = YES; 
    eaglLayer.drawableProperties = @{ kEAGLDrawablePropertyRetainedBacking : [NSNumber numberWithBool:NO], kEAGLDrawablePropertyColorFormat : kEAGLColorFormatSRGBA8 }; 

    // Create framebuffer with renderbuffer attached to layer  
    [EAGLContext setCurrentContext:context]; 
    glGenFramebuffers(1, &FrameBuffer); 
    glBindFramebuffer(GL_FRAMEBUFFER, FrameBuffer);  
    glGenRenderbuffers(1, &RenderBuffer); 
    glBindRenderbuffer(GL_RENDERBUFFER, RenderBuffer); 
    [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id<EAGLDrawable>)self.layer];  
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, RenderBuffer); 

    return self; 
} 

+(Class) layerClass 
{ 
    return [CAEAGLLayer class]; 
}` 

一個UIViewController在初始化時主線程上又增加了BView實例:

BView* view = [[BView alloc] initWithFrame:(CGRect){ 0.0, 0.0, 75.0, 75.0 } context:Context]; 
[self.view addSubView:view]; 

在輔助線程上,渲染到BView中的幀緩衝區並呈現它;在這種情況下,它是在從視頻AVCaptureDevice,定期調用的回調:

-(void) captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection 
{  
    [EAGLContext setCurrentContext:bPipe->Context.GlContext]; 

    // Render into framebuffer ... 

    // Present renderbuffer 
    glBindRenderbuffer(GL_RENDERBUFFER, BViewsRenderBuffer); 
    [Context presentRenderbuffer:GL_RENDERBUFFER]; 
} 
+1

發佈您的代碼片段 – phoenix

+0

誰在更新緩衝區的內容?主線程或輔助線程? –

+0

@JoaEbert更新和演示,如我剛剛添加的代碼所示,在輔助線程上完成 – Dickson

回答

0

它使用到不行。如果緩衝區顯示在除主線程之外的任何地方,那麼在更新視圖時就會出現幾個問題。看起來這個工作已經有一段時間了,但實施它的風險自負。後來的版本可能會有問題,以及一些較舊的版本可能仍然有問題(不是你需要支持一些舊的操作系統版本)。

蘋果總是對內部的工作方式有點封閉,但我們可能會猜到很多事情。由於iOS似乎是唯一使用主緩衝區作爲FBO(幀緩衝區對象)的平臺,所以我期望主框架緩衝區無法用於開發,而且當呈現渲染緩衝區時,主FBO實際上會重新繪製到主幀緩衝區。最後一次檢查提供渲染緩衝區的方法會阻止當前線程,並且似乎僅限於屏幕刷新率(大多數情況下爲60FPS),這意味着仍然存在一些鎖定機制。一些額外的測試應該完成,但我希望有某種緩衝區池需要重繪到主緩衝區,其中池中只有一個唯一緩衝區標識可以存在,或者調用線程被阻塞。這將導致對當前渲染緩衝區的第一次調用根本不會被阻止,但如果前一個緩衝區尚未重新繪製,則每個順序都會被阻止。

如果這是真的,那麼是的,因爲您可以立即繼續繪製到緩衝區,所以在某些時候雙緩衝是強制性的。由於渲染緩衝區在幀上具有相同的ID,因此它可能不會被交換(但我知道),但它可以重繪/複製到另一個緩衝區(最有可能是紋理),這可以在任何給定時間進行。在這個過程中,當你第一次顯示緩衝區時,你將把緩衝區複製到將被鎖定的紋理。當屏幕刷新時,紋理將被收集並解鎖。因此,如果此紋理被鎖定,則您的演示文稿調用將阻止該線程,否則將會順利地繼續。這很難說這是雙緩衝。它有2個緩衝區,但仍然可以使用鎖定機制。

我希望你可以理解它爲什麼有效。這與在單獨的線程上運行單獨的共享上下文中加載大型數據結構時使用的過程基本相同。

大多數情況下,這只是猜測不幸的。

+0

是的,這幾乎是我的看法。我記得過去在次要線程上呈現會導致問題。現在突然它起作用了。我決定看看會發生什麼,因爲文檔沒有明確禁止這個afaik,而且它工作正常。我發佈在Apple開發論壇上,但沒有人回答。很高興知道這裏發生了什麼。不是因爲該應用程序被破壞,只是爲了知道這是否合法和最佳。我的猜測,正如你所建議的那樣,presentRenderbuffer會自動與主線程演示同步 – Dickson

+0

我仍然不敢在非主線程上調用它,但這是你的選擇。我想如果在某個時候你開始發現一些異常,你所需要做的就是調用主線程來執行帶有正確上下文和呈現緩衝區的表示,然後在操作完成時繼續執行線程。所以一般來說,承擔這種風險將會有一點額外的時間成本。 –

+0

確實。然而,實際的渲染也需要同步,這在大多數情況下會妨礙性能(尤其是UI)。渲染可以被轉換成輔助緩衝區,然後只需要同步該緩衝區和視圖的圖層渲染緩衝區之間的blit操作。演示文稿和渲染當然是線程安全的。這就是我猜的蘋果所做的...... – Dickson

相關問題