У меня есть четыре экземпляра 1920x1080 MTKView
в качестве подпредставлений NSWindow
на мониторе 3840x2160 в качестве конфигурации отладки.Представьте, что мои четыре вида пронумерованы как квадранты («1» в правом верхнем углу, затем против часовой стрелки).На этих просмотрах играют четыре видео.Их CVPixelBuffers
снимаются с каждого соответствующего AVPlayer
через выделенный CVDisplayLink
цикл рендеринга для каждого.Каждый MTKView
настроен для рисования вручную с помощью тех же четырех обратных вызовов CVDisplayLink
.Вызов MTKView
draw
находится внутри @autoreleasepool
.
Все это работает довольно хорошо примерно в 95% случаев - при использовании около 75% памяти GPU и около 20% обработки GPU наRadeon R9 M395, iMac 5k, конец 2015 года, с Fusion Drive.В Metal Trace в XCode все мои графические процессы отображаются не более 5 мсек на кадр.
Я пытаюсь выяснить, почему некоторые мои видео заикаются примерно в 5% случаев. Захват GPU-кадра дает мне подсказку, но я не уверен, что с этим делать.
В каждом вызове MTKView
drawRect
я выполняю 4 прохода работы шейдера ядра над текстурой, котораяЯ выделил и до двух входящих CVPixelBuffer
текстур (т. Е. Для перехода от одного видео к другому).Я не запрашиваю и не трогаю currentRenderPassDescriptor
там.
Сразу после этих партий MTLComputeCommandEncoder
работы у меня есть один последний проход с MTLRenderCommandEncoder
и набор вершин с окончательной текстурой вычислениярезультат ввода:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
dispatch_semaphore_wait(self.inflightSemaphore, DISPATCH_TIME_FOREVER);
id<MTLCommandBuffer> commandBuffer = [metalCommandQueue commandBuffer];
<do 4 passes of compute work>
// ********* The next line is where WARNINGS (see below) occur ***********
MTLRenderPassDescriptor *renderPassDescriptor = self.currentRenderPassDescriptor;
id<MTLDrawable> currentDrawable = nil;
if (renderPassDescriptor) {
currentDrawable = self.currentDrawable;
[self doVertexWork:inputTexture
onCommandBuffer:commandBuffer
withDescriptor:renderPassDescriptor];
}
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
dispatch_semaphore_signal(self.inflightSemaphore);
}];
if (currentDrawable)
[commandBuffer presentDrawable:currentDrawable];
[commandBuffer commit];
commandBuffer=nil;
}
Если я делаю захват кадров GPU, я отмечаю частоту кадров 120 кадров в секунду, 4 вызова отрисовки, 4 буфера команд и 4 кодировщика рендеринга.Однако в указанной строке я получаю 7 предупреждений:
CAMetalLayer nextDrawable Called Early
(один раз) CAMetalLayer nextDrawable was Called Unnecessarily
(три раза) Command Buffer was not Enqueued and Committed in this Frame
(три раза - команда буферизует на квадрантах 1,3,4)
Кстати, примечание о раннем вызове, предоставленное Xcode: "Your application called CAMetalLayer nextDrawable earlier than needed. This may block execution until a CAMetalDrawable is available. Delay the call to nextDrawable until the drawing is needed for encoding".
Я замечаю вДокументы о том, что заблокированное выполнение происходит в течение одной секунды, что соответствует времени заикания, которое я периодически вижу (т.е. обновляется каждые 1 секунду или около того).
При вызове endEncoding
, когда я делаюВ моей работе с вершинами я получаю предупреждение "CAMetalDrawable used from Earlier Frame"
(три раза, с текстурами только из квадрантов 1,2,4).
Интересное примечание: когда при захвате кадра паузы останавливались, изображение из квадранта 3 былопродублирована в квадранте 2, а изображение квадранта два не было видно.
Я не могу понять, в чем моя проблема, поскольку я следую методам, использованным во всех примерах, которые я виделтам.
Любая помощь будет оценена.
UPДАТА # 1
Основываясь на Кен-Томасе полезных комментариях, я вставил следующую строку сразу после создания буфера команд в вызове отрисовки:
[metalCommandQueue insertDebugCaptureBoundary];
Это решило почти все предполагаемые проблемы, но я все еще время от времени наблюдаю 1-секундное заикание.Единственная оставшаяся проблема - это согласованный CAMetalLayer nextDrawable was Called Unnecessarily
с комментарием, что «ваше приложение вызвало CAMetalLayer nextDrawable
, но не использовало возвращенное CAMetalDrawable
во время фрейма».Это происходит независимо от того, происходит ли заикание.
Насколько я могу судить, этот nextDrawable
звонок иногда останавливает меня.