View Layout
Add the following views in a view controller:
- Label
- View A, with a subview of the same size: MTKView A
- View B, with a subview of the same size: MTKView B
Refresh Rates of Each View
- The label view refreshes at 60fps (driven by CADisplayLink).
- MTKView A and B refresh at 15fps.
MTKView Implementation Details
- The corresponding CAMetalLayer's
maximumDrawableCount
is set to 2, changed to double buffering. - The scheduling mechanism is modified; drawing is not driven by the internal loop but is done manually. The
draw
call is triggered immediately upon receiving a frame.self.metalView.enableSetNeedsDisplay = NO;
self.metalView.paused = YES;
- A new high-priority queue is created for drawing, instead of handling it on the main queue.
MTKView Latency Tracking
- The GPU completion time T1 is observed through the
addCompletedHandler
callback of the CommandBuffer. - The presentation time T2 of the frame is observed through the
addPresentedHandler
callback of thecurrentDrawable
in MTKView.
Testing shows that T2 - T1 > 16.6ms (the Vsync period at 60Hz). This means that after the GPU rendering in MTLView is finished, the frame is not actually displayed at the next Vsync instruction but only at the Vsync instruction after that. I believe there is an extra 16.6ms of latency here, which I want to eliminate by adjusting the rendering mechanism.
Observation from Instruments
From Instruments, the Surface presentation aligns with the above test results. After the Metal encoder finishes, the Surface in Display switches only after the next-next Vsync instruction. See the image in the link for details.
Questions
- According to a beginner's understanding, after MTKView's GPU rendering is finished, the next Vsync instruction should officially display (make it visible). However, this is not what is observed. Does the subview MTKView need to wait for another Vsync cycle to be drawn to the actual display buffer?
- The label updates its text at 60fps, so the entire interface should be displayed at 60fps. Is the content of MTKView not synchronized when the display happens?
Explanation of the Reasoning Behind Some MTKView Code Details
- Changing from the default triple buffering to double buffering helps reduce the latency introduced by rendering.
- Not using MTKView's own scheduling mechanism but using manual triggering of the
draw
method is because MTKView's own scheduling mechanism is driven by CADisplayLink. Therefore, if a frame falls within a Vsync window, it needs to wait for the next Vsync window to trigger thedraw
operation, which introduces waiting latency.