我正在尝试实现两个不同的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
)时,是否有机会成功或使用渲染过程描述符的颜色附件完全没有意义?如果是这样,有没有其他可以想象的方法来实现这个结果?
答案 0 :(得分:2)
要写入多个渲染目标,您需要在片段着色器中显式写出该渲染目标。 @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的上述答案对您的案例更准确。但是,为了补充他的答案,我建议使用可以在GPU上的两个纹理之间复制数据的BlitEncoder,我认为它应该比CPU快得多。
答案 1 :(得分:1)
据我读到这个问题,你可以尝试只渲染一个MTLTexture(不是可绘制层),然后尝试使用MTLTexture方法getBytes和replaceRegion将纹理数据复制到两个可绘制层中。
目前我正在渲染普通纹理,但我遇到了一些文物,目前它不适合我,也许你会找到解决方法。