Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop calling getNextDrawable on buffer swap to avoid CPU stalls #497

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
8 changes: 3 additions & 5 deletions src/Veldrid/MTL/MTLCommandList.cs
Expand Up @@ -11,7 +11,7 @@ internal unsafe class MTLCommandList : CommandList
{
private readonly MTLGraphicsDevice _gd;
private MTLCommandBuffer _cb;
private MTLFramebufferBase _mtlFramebuffer;
private MTLFramebuffer _mtlFramebuffer;
private uint _viewportCount;
private bool _currentFramebufferEverActive;
private MTLRenderCommandEncoder _rce;
Expand Down Expand Up @@ -695,7 +695,7 @@ protected override void SetFramebufferCore(Framebuffer fb)
}

EnsureNoRenderPass();
_mtlFramebuffer = Util.AssertSubtype<Framebuffer, MTLFramebufferBase>(fb);
_mtlFramebuffer = Util.AssertSubtype<Framebuffer, MTLFramebuffer>(fb);
_viewportCount = Math.Max(1u, (uint)fb.ColorTargets.Count);
Util.EnsureArrayMinimumSize(ref _viewports, _viewportCount);
Util.ClearArray(_viewports);
Expand Down Expand Up @@ -942,10 +942,8 @@ private bool EnsureRenderPass()

private bool BeginCurrentRenderPass()
{
if (!_mtlFramebuffer.IsRenderable)
{
if (_mtlFramebuffer is MTLSwapchainFramebuffer swapchainFramebuffer && !swapchainFramebuffer.EnsureDrawableAvailable())
return false;
}

MTLRenderPassDescriptor rpDesc = _mtlFramebuffer.CreateRenderPassDescriptor();
for (uint i = 0; i < _clearColors.Length; i++)
Expand Down
13 changes: 9 additions & 4 deletions src/Veldrid/MTL/MTLFramebuffer.cs
Expand Up @@ -3,19 +3,23 @@

namespace Veldrid.MTL
{
internal class MTLFramebuffer : MTLFramebufferBase
internal class MTLFramebuffer : Framebuffer
{
public override bool IsRenderable => true;
private bool _disposed;

public MTLFramebuffer(MTLGraphicsDevice gd, ref FramebufferDescription description)
: base(gd, ref description)
: base(description.DepthTarget, description.ColorTargets)
{
}

public override MTLRenderPassDescriptor CreateRenderPassDescriptor()
public MTLFramebuffer()
{
}

public MTLRenderPassDescriptor CreateRenderPassDescriptor()
{
MTLRenderPassDescriptor ret = MTLRenderPassDescriptor.New();

for (int i = 0; i < ColorTargets.Count; i++)
{
FramebufferAttachment colorTarget = ColorTargets[i];
Expand Down Expand Up @@ -50,6 +54,7 @@ public override MTLRenderPassDescriptor CreateRenderPassDescriptor()
return ret;
}

public override string Name { get; set; }
public override bool IsDisposed => _disposed;

public override void Dispose()
Expand Down
21 changes: 0 additions & 21 deletions src/Veldrid/MTL/MTLFramebufferBase.cs

This file was deleted.

4 changes: 2 additions & 2 deletions src/Veldrid/MTL/MTLGraphicsDevice.cs
Expand Up @@ -304,9 +304,9 @@ private protected override void SwapBuffersCore(Swapchain swapchain)
submitCB.presentDrawable(currentDrawablePtr);
submitCB.commit();
}
}

mtlSC.GetNextDrawable();
mtlSC.InvalidateDrawable();
}
}

private protected override void UpdateBufferCore(DeviceBuffer buffer, uint bufferOffsetInBytes, IntPtr source, uint sizeInBytes)
Expand Down
48 changes: 0 additions & 48 deletions src/Veldrid/MTL/MTLPlaceholderTexture.cs

This file was deleted.

30 changes: 22 additions & 8 deletions src/Veldrid/MTL/MTLSwapchain.cs
Expand Up @@ -106,18 +106,16 @@ public MTLSwapchain(MTLGraphicsDevice gd, ref SwapchainDescription description)

SetSyncToVerticalBlank(_syncToVerticalBlank);

GetNextDrawable();

_framebuffer = new MTLSwapchainFramebuffer(
gd,
this,
width,
height,
description.DepthFormat,
format);

getNextDrawable();
}

public void GetNextDrawable()
private bool getNextDrawable()
{
if (!_drawable.IsNull)
{
Expand All @@ -127,7 +125,15 @@ public void GetNextDrawable()
using (NSAutoreleasePool.Begin())
{
_drawable = _metalLayer.nextDrawable();
ObjectiveCRuntime.retain(_drawable.NativePtr);

if (!_drawable.IsNull)
{
ObjectiveCRuntime.retain(_drawable.NativePtr);
_framebuffer.UpdateTextures(_drawable, _metalLayer.drawableSize);
return true;
}

return false;
}
}

Expand All @@ -143,13 +149,21 @@ public override void Resize(uint width, uint height)
_metalLayer.frame = _uiView.frame;
}

_framebuffer.Resize(width, height);
_metalLayer.drawableSize = new CGSize(width, height);
if (_uiView.NativePtr != IntPtr.Zero)
{
_metalLayer.frame = _uiView.frame;
}
GetNextDrawable();

getNextDrawable();
}

public bool EnsureDrawableAvailable() => !_drawable.IsNull || getNextDrawable();

public void InvalidateDrawable()
{
ObjectiveCRuntime.release(_drawable.NativePtr);
_drawable = default;
}

private void SetSyncToVerticalBlank(bool value)
Expand Down
57 changes: 16 additions & 41 deletions src/Veldrid/MTL/MTLSwapchainFramebuffer.cs
Expand Up @@ -5,54 +5,46 @@

namespace Veldrid.MTL
{
internal class MTLSwapchainFramebuffer : MTLFramebufferBase
internal class MTLSwapchainFramebuffer : MTLFramebuffer
{
private readonly MTLGraphicsDevice _gd;
private readonly MTLPlaceholderTexture _placeholderTexture;
private MTLTexture _colorTexture;
private MTLTexture _depthTexture;
private readonly MTLSwapchain _parentSwapchain;
private bool _disposed;
private readonly PixelFormat _colorFormat;

public override uint Width => _placeholderTexture.Width;
public override uint Height => _placeholderTexture.Height;
public override uint Width => _colorTexture.Width;
public override uint Height => _colorTexture.Height;

public override OutputDescription OutputDescription { get; }

private readonly FramebufferAttachment[] _colorTargets;
private readonly FramebufferAttachment? _depthTarget;
private FramebufferAttachment[] _colorTargets;
private FramebufferAttachment? _depthTarget;

private readonly PixelFormat? _depthFormat;

public override IReadOnlyList<FramebufferAttachment> ColorTargets => _colorTargets;
public override FramebufferAttachment? DepthTarget => _depthTarget;

public override bool IsDisposed => _disposed;

public MTLSwapchainFramebuffer(
MTLGraphicsDevice gd,
MTLSwapchain parent,
uint width,
uint height,
PixelFormat? depthFormat,
PixelFormat colorFormat)
: base()
{
_gd = gd;
_parentSwapchain = parent;
_colorFormat = colorFormat;

OutputAttachmentDescription? depthAttachment = null;
if (depthFormat != null)
{
_depthFormat = depthFormat;
depthAttachment = new OutputAttachmentDescription(depthFormat.Value);
RecreateDepthTexture(width, height);
_depthTarget = new FramebufferAttachment(_depthTexture, 0);
}
OutputAttachmentDescription colorAttachment = new OutputAttachmentDescription(colorFormat);

OutputDescription = new OutputDescription(depthAttachment, colorAttachment);
_placeholderTexture = new MTLPlaceholderTexture(colorFormat);
_placeholderTexture.Resize(width, height);
_colorTargets = new[] { new FramebufferAttachment(_placeholderTexture, 0) };
}

private void RecreateDepthTexture(uint width, uint height)
Expand All @@ -66,41 +58,24 @@ private void RecreateDepthTexture(uint width, uint height)
_depthTexture = Util.AssertSubtype<Texture, MTLTexture>(
_gd.ResourceFactory.CreateTexture(TextureDescription.Texture2D(
width, height, 1, 1, _depthFormat.Value, TextureUsage.DepthStencil)));
_depthTarget = new FramebufferAttachment(_depthTexture, 0);
}

public void Resize(uint width, uint height)
public void UpdateTextures(CAMetalDrawable drawable, CGSize size)
{
_placeholderTexture.Resize(width, height);
_colorTexture = new MTLTexture(drawable, size, _colorFormat);
_colorTargets = new[] { new FramebufferAttachment(_colorTexture, 0) };

if (_depthFormat.HasValue)
{
RecreateDepthTexture(width, height);
}
RecreateDepthTexture((uint)size.width, (uint)size.height);
}

public override bool IsRenderable => !_parentSwapchain.CurrentDrawable.IsNull;

public override MTLRenderPassDescriptor CreateRenderPassDescriptor()
{
MTLRenderPassDescriptor ret = MTLRenderPassDescriptor.New();
var color0 = ret.colorAttachments[0];
color0.texture = _parentSwapchain.CurrentDrawable.texture;
color0.loadAction = MTLLoadAction.Load;

if (_depthTarget != null)
{
var depthAttachment = ret.depthAttachment;
depthAttachment.texture = _depthTexture.DeviceTexture;
depthAttachment.loadAction = MTLLoadAction.Load;
}

return ret;
}
public bool EnsureDrawableAvailable() => _parentSwapchain.EnsureDrawableAvailable();

public override void Dispose()
{
_depthTexture?.Dispose();
_disposed = true;
base.Dispose();
}
}
}
17 changes: 17 additions & 0 deletions src/Veldrid/MTL/MTLTexture.cs
Expand Up @@ -118,6 +118,23 @@ public MTLTexture(ulong nativeTexture, ref TextureDescription description)
(Usage & TextureUsage.Cubemap) != 0);
}

public MTLTexture(CAMetalDrawable drawable, CGSize size, PixelFormat format)
{
DeviceTexture = drawable.texture;
Width = (uint)size.width;
Height = (uint)size.height;
Depth = 1;
ArrayLayers = 1;
MipLevels = 1;
Format = format;
Usage = TextureUsage.RenderTarget;
Type = TextureType.Texture2D;
SampleCount = TextureSampleCount.Count1;

MTLPixelFormat = MTLFormats.VdToMTLPixelFormat(Format, false);
MTLTextureType = MTLTextureType.Type2D;
}

internal uint GetSubresourceSize(uint mipLevel, uint arrayLayer)
{
uint blockSize = FormatHelpers.IsCompressedFormat(Format) ? 4u : 1u;
Expand Down