Несколько целей рендеринга в металле
Я пытаюсь реализовать два различных CAMetalLayers
и использовать один MTLRenderCommandEncoder
визуализировать одну и ту же сцену в оба слоя (Metal для 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
)? Если да, есть ли другой возможный подход для достижения этого результата?
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;
}
Тем не менее, это излишнее, так как вам не нужен графический процессор для рендеринга сцены дважды. Таким образом, ответ выше @Kacper является более точным для вашего случая. Однако, чтобы добавить к его ответу, я бы порекомендовал использовать BlitEncoder, который может копировать данные между двумя текстурами на графическом процессоре, который, как я полагаю, должен быть намного быстрее, чем процессор.
Насколько я читал об этой проблеме, вы можете попытаться отрисовать только одну MTLTexture (не прорисовываемый слой), а затем попытаться использовать методы MTLTexture getBytes и replaceRegion для копирования данных текстуры в два прорисовываемых слоя.
В настоящее время я работаю над рендерингом на обычную текстуру, но я сталкиваюсь с некоторыми артефактами, и в настоящее время это не работает для меня, возможно, вы найдете способ решить эту проблему.