title: Very elusive Metal issue with 'nextDrawable'
body: <p>I have a setup of four 1920x1080 <code>MTKView</code> instances as subviews of an <code>NSWindow</code> on a 3840x2160 monitor as a debugging configuration.  Imagine my four views numbered as quadrants ("1" in upper-right, then going counter-clockwise).  There are four videos playing on these views. Their <code>CVPixelBuffers</code> are captured from each respective <code>AVPlayer</code>, via a dedicated <code>CVDisplayLink</code> render loop for each.  Each <code>MTKView</code> is configured for manual drawing by these same four <code>CVDisplayLink</code> callbacks.  The <code>MTKView</code> <code>draw</code> call therein is inside an <code>@autoreleasepool</code>.</p>
  
  <p>All this works quite well about 95% of the time -- with about 75% GPU memory usage and about 20% GPU processing on a Radeon R9 M395, iMac 5k Late 2015 w/Fusion Drive.  A Metal Trace in Xcode has all my GPU rendering taking not more than 5ms per frame.</p>
  
  <p><strong>I'm trying to track down why some of my videos stutter about 5% of the time.</strong>
  A GPU Frame capture is giving me a clue, but I'm not sure what to do about it.</p>
  
  <p>In each <code>MTKView</code> <code>drawRect</code> call, I do 4 passes of kernel shader work on a texture that I've allocated and up to two incoming <code>CVPixelBuffer</code> textures  (ie. for fades from one video to the next).  I don't request or touch the <code>currentRenderPassDescriptor</code> in there.</p>
  
  <p>Immediately following these batches of <code>MTLComputeCommandEncoder</code> work, I have one final pass with a <code>MTLRenderCommandEncoder</code> and a set of vertices with the final compute texture result as input:</p>
  
  <pre><code>- (void)drawRect:(NSRect)dirtyRect {
      [super drawRect:dirtyRect];
      dispatch_semaphore_wait(self.inflightSemaphore, DISPATCH_TIME_FOREVER);
      id&lt;MTLCommandBuffer&gt; commandBuffer = [metalCommandQueue commandBuffer];
  
      &lt;do 4 passes of compute work&gt;
  
      // ********* The next line is where WARNINGS (see below) occur ***********
      MTLRenderPassDescriptor *renderPassDescriptor = self.currentRenderPassDescriptor;
  
      id&lt;MTLDrawable&gt; currentDrawable = nil;
      if (renderPassDescriptor) {
         currentDrawable = self.currentDrawable;
         [self doVertexWork:inputTexture
            onCommandBuffer:commandBuffer
             withDescriptor:renderPassDescriptor];
      }
  
      [commandBuffer addCompletedHandler:^(id&lt;MTLCommandBuffer&gt; buffer) {
          dispatch_semaphore_signal(self.inflightSemaphore);
      }];
  
      if (currentDrawable)
          [commandBuffer presentDrawable:currentDrawable];
      [commandBuffer commit];
  
      commandBuffer=nil;
  }
  </code></pre>
  
  <p><br>
  If I do a GPU frame capture, I note a frame rate of 120fps, 4 draw calls, 4 command buffers, and 4 render encoders.  However, I get a total of 7 warnings on the line indicated:</p>
  
  <ul>
  <li><code>CAMetalLayer nextDrawable Called Early</code> (once)</li>
  <li><code>CAMetalLayer nextDrawable was Called Unnecessarily</code> (three times)</li>
  <li><code>Command Buffer was not Enqueued and Committed in this Frame</code> (three times -- the command buffers on quadrants 1,3,4)</li>
  </ul>
  
  <p>BTW, a note about calling early provided by Xcode: <code>"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".</code></p>
  
  <p>I notice in the docs that the blocked execution occurs for one second, which matches the timing of the stutter I'm occasionally seeing (ie. updates every 1 second or so).</p>
  
  <p>On the <code>endEncoding</code> call when I'm doing my vertex work, I get a <code>"CAMetalDrawable used from Earlier Frame"</code> warning (three times, with textures from quadrants 1,2,4 only).</p>
  
  <p>Interesting side note: when the frame capture paused things, the image from quadrant 3 was duplicated in quadrant 2, and quadrant two's image was not visible.</p>
  
  <p><strong>I can't really figure out what my issue is as I'm following the techniques used by all the examples I've seen out there.</strong></p>
  
  <p><strong>Any help would be appreciated.</strong></p>
  
  <hr>
  
  <p><strong>UPDATE #1</strong></p>
  
  <p>Based on <a href="https://stackoverflow.com/users/1312143/ken-thomases">Ken-Thomases</a> helpful comments, I inserted the following line immediately after the creation of the command buffer in the draw call:</p>
  
  <pre><code>[metalCommandQueue insertDebugCaptureBoundary];
  </code></pre>
  
  <p>This resolved almost all of the purported issues, but I'm still seeing the 1-second stutters occasionally.  The only remaining issue is a consistent <code>CAMetalLayer nextDrawable was Called Unnecessarily</code> with a comment that "your application called <code>CAMetalLayer nextDrawable</code> but did not use the returned <code>CAMetalDrawable</code> during the frame".  This occurs irrespective of whether the stutter is occurring.</p>
  
  <p>Near as I can tell, this <code>nextDrawable</code> call is stalling things occasionally for me.</p>
  
  <hr>