2015-11-29 115 views
2

我試圖實現兩個截然不同的CAMetalLayers並使用一個MTLRenderCommandEncoder將同一場景渲染到兩個圖層(Metal for OS X)。金屬中的多個渲染目標

爲此,我試過創建一個MTLRenderPassDescriptor並將兩個圖層的紋理附加到它的顏色附件中。我的渲染方法如下所示:

- (void)render { 
    dispatch_semaphore_wait(_inflight_semaphore, DISPATCH_TIME_FOREVER); 

    id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer]; 
    __block dispatch_semaphore_t block_sema = _inflight_semaphore; 
    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) { 
     dispatch_semaphore_signal(block_sema); 
    }]; 

    MTLRenderPassDescriptor *renderPass = [MTLRenderPassDescriptor renderPassDescriptor]; 

    for (int i = 0; i < [_metalLayers count]; i++) { 
     _metalDrawables[i] = [_metalLayers[i] nextDrawable]; 
     renderPass.colorAttachments[i].texture = _metalDrawables[[_metalDrawables count] - 1].texture; 
     renderPass.colorAttachments[i].clearColor = MTLClearColorMake(0.5, 0.5, (float)i/(float)[_metalLayers count], 1); 
     renderPass.colorAttachments[i].storeAction = MTLStoreActionStore; 
     renderPass.colorAttachments[i].loadAction = MTLLoadActionClear; 
    } 

    id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPass]; 
    [commandEncoder setRenderPipelineState:_pipeline]; 
    [commandEncoder setVertexBuffer:_positionBuffer offset:0 atIndex:0 ]; 
    [commandEncoder setVertexBuffer:_colorBuffer offset:0 atIndex:1 ]; 
    [commandEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3 instanceCount:1]; 
    [commandEncoder endEncoding]; 

    for (int i = 0; i < [_metalDrawables count]; i++) { 
     [commandBuffer presentDrawable:_metalDrawables[i]]; 
    } 
    [commandBuffer commit]; 
} 

然而,場面被渲染到層,這原來是與第一附色的紋理相關聯的一個的只有一個。使用指定的透明顏色清除其他圖層,但不繪製任何圖層。

嘗試將同一場景渲染到多個屏幕(即CAMetalLayers)時,有沒有辦法成功或正在使用渲染通道描述符的顏色附件?如果是這樣,是否還有其他可行的方法來實現這一結果?

+1

您的片段着色器是否寫入多個顏色附件?我想看看'[用於片段函數輸出的屬性限定符]'(https://developer.apple.com/library/ios/documentation/Metal/Reference/MetalShadingLanguageGuide/func-var-qual/func- var-qual.html#// apple_ref/doc/uid/TP40014364-CH4-SW12)和'[[color(m)]]'限定符。 – lock

+0

上面的答案是正確的,你需要什麼。除非着色器寫入多個渲染目標,否則在附加紋理中不會看到這些寫入。 – m3v3rik

回答

1

據我瞭解這個問題,你可以嘗試渲染一個MTLTexture(不可繪製圖層),然後嘗試使用MTLTexture方法getBytes和replaceRegion將紋理數據複製到兩個可繪製圖層中。

目前我正致力於渲染到普通紋理,但我遇到一些工件,目前它不適合我,也許你會找到辦法解決這個問題。

1

要寫入多個渲染目標,您需要明確寫出片段着色器中的渲染目標。 @lock已經指出了這一點。

struct MyFragmentOutput { 
    // color attachment 0 
    float4 clr_f [[ color(0) ]]; 

    // color attachment 1 
    int4 clr_i [[ color(1) ]]; 

    // color attachment 2 
    uint4 clr_ui [[ color(2) ]]; 
}; 

fragment MyFragmentOutput 
my_frag_shader(...) 
{ 
    MyFragmentOutput f; 
    .... 
    f.clr_f = ...; 
    f.clr_i = ...; 
    ... 
    return f;
 } 

但是,這是一個矯枉過正,因爲你不需要GPU來渲染場景兩次。所以@Kacper上面的答案對你的情況更準確。但是,爲了增加他的答案,我建議使用BlitEncoder,它可以在GPU上的兩個紋理之間複製數據,我認爲這應該比CPU快得多。

https://developer.apple.com/library/mac/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Blit-Ctx/Blit-Ctx.html#//apple_ref/doc/uid/TP40014221-CH9-SW4