Skip to content

Commit

Permalink
📸 Add RenderDoc frame capture
Browse files Browse the repository at this point in the history
  • Loading branch information
paulcscharf committed May 6, 2024
1 parent 9c5cae1 commit ffb4447
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
1 change: 1 addition & 0 deletions Bearded.Graphics/Bearded.Graphics.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<PackageReference Include="Bearded.Utilities" Version="0.2.0.393-dev" />
<PackageReference Include="Evergine.Bindings.RenderDoc" Version="2024.4.29.15" PrivateAssets="compile" />
<PackageReference Include="OpenTK.Core" Version="4.8.0" />
<PackageReference Include="OpenTK.Graphics" Version="4.8.0" />
<PackageReference Include="OpenTK.Mathematics" Version="4.8.0" />
Expand Down
112 changes: 112 additions & 0 deletions Bearded.Graphics/Windowing/RenderDoc.Implementation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using Evergine.Bindings.RenderDoc;
using static Evergine.Bindings.RenderDoc.RENDERDOC_OverlayBits;
using Api = Evergine.Bindings.RenderDoc.RenderDoc;

namespace Bearded.Graphics.Windowing;

public interface IRenderDoc
{
string? Version => null;
void ShowOverlay(bool visible) { }
void ClearCaptureKeys() { }
RenderDoc.FrameCapture? CaptureFrame(bool openReplayUIOnDispose = true) => null;
}

static partial class RenderDoc
{
private sealed class DummyImplementation : IRenderDoc;

private sealed class Implementation : IRenderDoc
{
// ReSharper disable BitwiseOperatorOnEnumWithoutFlags
private const uint defaultOverlayMask = (uint)(
eRENDERDOC_Overlay_Enabled |
eRENDERDOC_Overlay_FrameRate |
eRENDERDOC_Overlay_FrameNumber
);
// ReSharper restore BitwiseOperatorOnEnumWithoutFlags

private readonly Api api;

public Implementation(Api api)
{
this.api = api;

api.API.MaskOverlayBits(0, defaultOverlayMask);
}

string IRenderDoc.Version
{
get
{
int major, minor, patch;
unsafe
{
api.API.GetAPIVersion(&major, &minor, &patch);
}
return $"{major}.{minor}.{patch}";
}
}

void IRenderDoc.ShowOverlay(bool visible)
{
var (keep, add) = visible
? (eRENDERDOC_Overlay_All, eRENDERDOC_Overlay_Enabled)
: (~eRENDERDOC_Overlay_Enabled, eRENDERDOC_Overlay_None);

// ReSharper disable once IntVariableOverflowInUncheckedContext
api.API.MaskOverlayBits((uint)keep, (uint)add);
}

void IRenderDoc.ClearCaptureKeys()
{
unsafe
{
api.API.SetCaptureKeys((RENDERDOC_InputButton*)0, 0);
}
}

FrameCapture? IRenderDoc.CaptureFrame(bool openReplayUIOnDispose)
=> new FrameCapture(api, openReplayUIOnDispose);
}

public readonly struct FrameCapture : IDisposable
{
private readonly Api api;
private readonly bool openUIOnDispose;

internal FrameCapture(Api api, bool openUIOnDispose)
{
this.api = api;
this.openUIOnDispose = openUIOnDispose;
api.API.StartFrameCapture(IntPtr.Zero, IntPtr.Zero);
}

void IDisposable.Dispose()
{
EndCapture(openUIOnDispose);
}

public bool EndCapture(bool openReplayUI = true)
{
var success = api.API.EndFrameCapture(IntPtr.Zero, IntPtr.Zero) == 1;

if (success && openReplayUI)
{
openReplayUi();
}

return success;
}

private void openReplayUi()
{
var uiNotYetLaunched = api.API.ShowReplayUI() == 0;
if (uiNotYetLaunched)
{
api.API.LaunchReplayUI(1, "");
}
}
}
}
25 changes: 25 additions & 0 deletions Bearded.Graphics/Windowing/RenderDoc.Load.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Diagnostics.CodeAnalysis;
using Api = Evergine.Bindings.RenderDoc.RenderDoc;

namespace Bearded.Graphics.Windowing;

public static partial class RenderDoc
{
public static bool TryLoad([NotNullWhen(true)] out IRenderDoc? renderDoc)
{
var success = Api.Load(out var api);
renderDoc = success ? new Implementation(api) : null;
return success;
}

public static IRenderDoc LoadOrDummy()
{
var success = Api.Load(out var renderDoc);

return success
? new Implementation(renderDoc)
: Dummy;
}

public static IRenderDoc Dummy { get; } = new DummyImplementation();
}

0 comments on commit ffb4447

Please sign in to comment.