[Diagnostics] Count GPU barriers and rendering scopes

This commit is contained in:
ParantezTech 2026-10-11 01:35:45 +03:00
parent 84c830f7ce
commit 0de84e34df
4 changed files with 95 additions and 0 deletions

View File

@ -0,0 +1,79 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using Silk.NET.Vulkan;
namespace SharpEmu.Libs.Gpu.Vulkan;
internal enum NativeStateKind
{
Pipeline,
PushConstants,
Descriptors,
VertexBuffers,
IndexBuffer,
Count,
}
internal static class GpuSyncProfile
{
private static readonly long[] _nativeStateRecorded = new long[(int)NativeStateKind.Count];
private static readonly long[] _nativeStateReused = new long[(int)NativeStateKind.Count];
private static long _barriers;
private static long _drainingBarriers;
private static long _memoryBarriers;
private static long _bufferBarriers;
private static long _imageBarriers;
private static long _mergedRequests;
private static long _renderingScopes;
private static long _batchFlushes;
public static bool Enabled => VideoOut.RenderPhaseProfile.Enabled;
public static void CountBarrier(PipelineStageFlags source, PipelineStageFlags destination, uint memory, uint buffer, uint image)
{
Interlocked.Increment(ref _barriers);
if ((source & PipelineStageFlags.AllCommandsBit) != 0 && (destination & (PipelineStageFlags.AllCommandsBit | PipelineStageFlags.TopOfPipeBit | PipelineStageFlags.DrawIndirectBit)) != 0)
{
Interlocked.Increment(ref _drainingBarriers);
}
Interlocked.Add(ref _memoryBarriers, memory);
Interlocked.Add(ref _bufferBarriers, buffer);
Interlocked.Add(ref _imageBarriers, image);
}
public static void CountMergedRequest() => Interlocked.Increment(ref _mergedRequests);
public static void CountRenderingScope() => Interlocked.Increment(ref _renderingScopes);
public static void CountBatchFlush() => Interlocked.Increment(ref _batchFlushes);
public static void CountNativeState(NativeStateKind kind, bool reused)
{
if (reused)
{
Interlocked.Increment(ref _nativeStateReused[(int)kind]);
}
else
{
Interlocked.Increment(ref _nativeStateRecorded[(int)kind]);
}
}
private static string TakeNativeStateReport()
{
var parts = new string[(int)NativeStateKind.Count];
for (var index = 0; index < parts.Length; index++)
{
var reused = Interlocked.Exchange(ref _nativeStateReused[index], 0);
var recorded = Interlocked.Exchange(ref _nativeStateRecorded[index], 0);
parts[index] = FormattableString.Invariant($"{(NativeStateKind)index}={reused}/{reused + recorded}");
}
return string.Join(" ", parts);
}
public static string TakeReport() => FormattableString.Invariant(
$"[PERF][GPU_SYNC] barriers={Interlocked.Exchange(ref _barriers, 0)} draining={Interlocked.Exchange(ref _drainingBarriers, 0)} memory={Interlocked.Exchange(ref _memoryBarriers, 0)} buffer={Interlocked.Exchange(ref _bufferBarriers, 0)} image={Interlocked.Exchange(ref _imageBarriers, 0)} merged_requests={Interlocked.Exchange(ref _mergedRequests, 0)} rendering_scopes={Interlocked.Exchange(ref _renderingScopes, 0)} draw_count_flushes={Interlocked.Exchange(ref _batchFlushes, 0)} reused {TakeNativeStateReport()}");
}

View File

@ -22,6 +22,11 @@ internal static unsafe class VulkanSynchronization
uint imageMemoryBarrierCount,
ImageMemoryBarrier2* imageMemoryBarriers)
{
if (GpuSyncProfile.Enabled)
{
GpuSyncProfile.CountBarrier(sourceStages, destinationStages, memoryBarrierCount, bufferMemoryBarrierCount, imageMemoryBarrierCount);
}
var sourceStages2 = (PipelineStageFlags2)(ulong)sourceStages;
var destinationStages2 = (PipelineStageFlags2)(ulong)destinationStages;
for (var index = 0u; index < memoryBarrierCount; index++)

View File

@ -469,6 +469,7 @@ internal static class RenderPhaseProfile
BufferUploadProfile.Report();
Console.Error.WriteLine(SharpEmu.ShaderCompiler.Resources.ResourceMaterializationCache.TakeReport());
Console.Error.WriteLine(SharpEmu.Libs.Gpu.Buffers.GuestBufferCache.TakeAsyncReadbackReport());
Console.Error.WriteLine(SharpEmu.Libs.Gpu.Vulkan.GpuSyncProfile.TakeReport());
Console.Error.WriteLine(SharpEmu.Libs.Gpu.Images.GuestImageCache.TakeLookupReport());
SharpEmu.ShaderCompiler.Resources.ResourceMaterializationProfile.WriteReport();
SharpEmu.Libs.Diagnostics.AgcRegisterPacketProfile.WriteReport();

View File

@ -407,6 +407,11 @@ internal static unsafe partial class VulkanVideoPresenter
if (_batchDrawCount >= (_renderingActive ? DrawsPerBatchInRenderPass : DrawsPerBatch))
{
if (GpuSyncProfile.Enabled)
{
GpuSyncProfile.CountBatchFlush();
}
EndRendering();
FlushBatchedGuestCommands();
}
@ -927,6 +932,11 @@ internal static unsafe partial class VulkanVideoPresenter
};
_vk.CmdBeginRendering(command, &rendering);
_renderingScopesBegun++;
if (GpuSyncProfile.Enabled)
{
GpuSyncProfile.CountRenderingScope();
}
_renderingActive = true;
_renderingState = state;
}