Несколько целей рендеринга в металле

Я пытаюсь реализовать два различных 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, который может копировать данные между двумя текстурами на графическом процессоре, который, как я полагаю, должен быть намного быстрее, чем процессор.

https://developer.apple.com/library/mac/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Blit-Ctx/Blit-Ctx.html

Насколько я читал об этой проблеме, вы можете попытаться отрисовать только одну MTLTexture (не прорисовываемый слой), а затем попытаться использовать методы MTLTexture getBytes и replaceRegion для копирования данных текстуры в два прорисовываемых слоя.

В настоящее время я работаю над рендерингом на обычную текстуру, но я сталкиваюсь с некоторыми артефактами, и в настоящее время это не работает для меня, возможно, вы найдете способ решить эту проблему.

Другие вопросы по тегам