Рендеринг в CAMetalLayer из выделенного потока / цикла рендеринга - PullRequest
0 голосов
/ 02 января 2019

В Windows World выделенный поток рендеринга зациклит что-то похожее на это:

void RenderThread()
{
    while (!quit)
    {
        UpdateStates();
        RenderToDirect3D();
        // Can either present with no synchronisation,
        // or synchronise after 1-4 vertical blanks.
        // See docs for IDXGISwapChain::Present
        PresentToSwapChain();
    }
}

Что такое эквивалент в какао с CAMetalLayer? Все примеры касаются обновлений, выполняемых в главном потоке, либо с использованием MTKView (с внутренним таймером), либо с использованием CADisplayLink в примерах iOS.

Я хочу контролировать весь цикл рендеринга, а не просто получать обратный вызов с неуказанным интервалом (и в идеале блокировать V-Sync, если он включен).

Ответы [ 2 ]

0 голосов
/ 03 января 2019

В точке, где вы хотите выполнить рендеринг на экран, вы получаете отрисовку из слоя, вызывая nextDrawable.Вы получаете текстуру отрисовки из свойства texture.Вы используете эту текстуру, чтобы установить цель рендеринга (цветное вложение) MTLRenderPassDescriptor.Например:

id<CAMetalDrawable> drawable = layer.nextDrawable;
id<MTLTexture> texture = drawable.texture;
MTLRenderPassDescriptor *desc = [MTLRenderPassDescriptor renderPassDescriptor];
desc.colorAttachments[0].texture = texture;

Отсюда это очень похоже на то, что вы делаете в методе MTKView drawRect:.Вы создаете буфер команд (если у вас его еще нет), создаете кодировщик команд рендеринга с использованием дескриптора, кодируете команды рисования, заканчиваете кодирование, сообщаете буферу команд представить чертеж (используя метод -presentDrawable:...) ипередайте командный буфер.То, что было нарисовано в текстуре рисованного объекта, будет отображаться на экране при его представлении.

Я согласен с Уорреном в том, что вы, вероятно, не хотите синхронизировать цикл с обновлением дисплея.Вы хотите параллелизма.Вы хотите, чтобы центральный процессор работал над следующим кадром, в то время как графический процессор отображает самый последний кадр (а на дисплее отображается последний кадр).

Тот факт, что количество доступных для рисования элементов может быть ограниченоПолет сразу, и что nextDrawable заблокирует ожидание одного, предотвратит ваш цикл рендеринга слишком далеко вперед.(Вы, вероятно, будете использовать некоторую другую синхронизацию до этого, например, для управления небольшим пулом буферов.) Если вы хотите использовать только двойную буферизацию, а не тройную буферизацию, вы можете установить maximumDrawableCount слоя вместо 2 вместо его значения по умолчанию.из 3.

0 голосов
/ 02 января 2019

На каком-то уровне вы будете ограничены наличием выдвижных элементов. У CAMetalLayer есть фиксированный пул доступных отрисовок, и вызов nextDrawable заблокирует текущий поток, пока не станет доступным отрисовка. Это не означает, что вам нужно вызывать nextDrawable в верхней части цикла рендеринга.

Если вы хотите рисовать по своему собственному расписанию, не блокируясь в ожидании рисования, выполните рендеринг в закадровый буфер рендеринга (т. Е. MTLTexture с размерами, совпадающими с вашим размером для рисования), а затем оторвитесь от самого последнего -тянутая текстура к текстуре рисованной фигуры и присутствует на любой каденции, которую вы предпочитаете. Это может быть полезно для получения временных рамок, но каждый кадр, который вы рисуете, а затем не отображаете, тратится впустую. Это также увеличивает риск дрожания.

Ваши возможности ограничены, когда дело доходит до получения обратных вызовов, которые соответствуют частоте v-sync. Лучше всего почти наверняка запланировано CVDisplayLink в режимах по умолчанию и в режиме отслеживания цикла выполнения, хотя здесь есть предостережения .

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

Если ваше приложение способно поддерживать частоту кадров в реальном времени, вы обычно будете рендерить кадр или два перед тем, что происходит на стекле, поэтому вы не хотите буквально блокировать v-sync; Вы просто хотите сообщить оконному серверу, что хотите, чтобы презентация соответствовала v-sync. В macOS вы делаете это, устанавливая для слоя displaySyncEnabled значение true (по умолчанию). Отключение может привести к разрыву некоторых дисплеев.

...