mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-11 01:34:17 +02:00
GS: Track shader compile count and duration for OSD
This commit is contained in:
@@ -3,87 +3,97 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Pcsx2Types.h"
|
||||
#include "common/Timer.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
namespace GSShaderCompileIndicator
|
||||
{
|
||||
inline constexpr std::uint64_t OSD_RECENT_COMPILE_NS = 500'000'000ULL;
|
||||
inline constexpr u64 RECENT_COMPILE_HOLD_NS = 1'500'000'000ULL;
|
||||
|
||||
inline std::atomic<std::uint32_t> s_active_compilations{0};
|
||||
inline std::atomic<std::uint64_t> s_last_compile_activity_ns{0};
|
||||
inline std::atomic<u32> s_count{0};
|
||||
inline std::atomic<u64> s_time_ns{0};
|
||||
inline std::atomic<u64> s_last_time{0};
|
||||
|
||||
namespace detail
|
||||
inline u64 GetRecentCompileHold()
|
||||
{
|
||||
inline std::uint64_t steady_now_ns()
|
||||
static const u64 hold = static_cast<u64>(Common::Timer::ConvertNanosecondsToValue(static_cast<double>(RECENT_COMPILE_HOLD_NS)));
|
||||
return hold;
|
||||
}
|
||||
|
||||
inline void OnCompileDone(u64 duration_ns, u64 start_time)
|
||||
{
|
||||
const u64 now = Common::Timer::GetCurrentValue();
|
||||
const u64 last = s_last_time.load(std::memory_order_relaxed);
|
||||
if (last != 0 && start_time > last && (start_time - last) >= GetRecentCompileHold())
|
||||
{
|
||||
return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
.count());
|
||||
s_count.store(0, std::memory_order_relaxed);
|
||||
s_time_ns.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline void TouchCompileActivity()
|
||||
{
|
||||
s_last_compile_activity_ns.store(detail::steady_now_ns(), std::memory_order_relaxed);
|
||||
s_count.fetch_add(1, std::memory_order_relaxed);
|
||||
s_time_ns.fetch_add(duration_ns, std::memory_order_relaxed);
|
||||
s_last_time.store(now, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void BeginCompilation()
|
||||
inline u32 GetCount()
|
||||
{
|
||||
TouchCompileActivity();
|
||||
s_active_compilations.fetch_add(1, std::memory_order_relaxed);
|
||||
return s_count.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void EndCompilation()
|
||||
inline u32 GetTimeMs()
|
||||
{
|
||||
s_active_compilations.fetch_sub(1, std::memory_order_relaxed);
|
||||
TouchCompileActivity();
|
||||
const u64 time_ns = s_time_ns.load(std::memory_order_relaxed);
|
||||
const u32 ms = static_cast<u32>(time_ns / 1000000);
|
||||
if (ms > 0)
|
||||
return ms;
|
||||
|
||||
return GetCount() > 0 ? 1u : 0u;
|
||||
}
|
||||
|
||||
inline std::uint32_t GetActiveCompilationCount()
|
||||
inline bool IsVisible()
|
||||
{
|
||||
return s_active_compilations.load(std::memory_order_relaxed);
|
||||
}
|
||||
if (GetCount() == 0)
|
||||
return false;
|
||||
|
||||
inline bool ShouldShowOnOSD(std::uint64_t hold_ns = OSD_RECENT_COMPILE_NS)
|
||||
{
|
||||
if (GetActiveCompilationCount() != 0)
|
||||
return true;
|
||||
|
||||
const std::uint64_t last = s_last_compile_activity_ns.load(std::memory_order_relaxed);
|
||||
const u64 last = s_last_time.load(std::memory_order_relaxed);
|
||||
if (last == 0)
|
||||
return false;
|
||||
|
||||
const std::uint64_t now = detail::steady_now_ns();
|
||||
return now > last && (now - last) < hold_ns;
|
||||
return (Common::Timer::GetCurrentValue() - last) < GetRecentCompileHold();
|
||||
}
|
||||
|
||||
inline float GetPostCompileFadeAlpha(std::uint64_t hold_ns = OSD_RECENT_COMPILE_NS)
|
||||
inline float GetFadeAlpha()
|
||||
{
|
||||
if (GetActiveCompilationCount() != 0)
|
||||
return 1.0f;
|
||||
|
||||
const std::uint64_t last = s_last_compile_activity_ns.load(std::memory_order_relaxed);
|
||||
const u64 last = s_last_time.load(std::memory_order_relaxed);
|
||||
if (last == 0)
|
||||
return 0.0f;
|
||||
|
||||
const std::uint64_t now = detail::steady_now_ns();
|
||||
const u64 now = Common::Timer::GetCurrentValue();
|
||||
if (now <= last)
|
||||
return 1.0f;
|
||||
|
||||
const std::uint64_t elapsed = now - last;
|
||||
if (elapsed >= hold_ns)
|
||||
const u64 hold = GetRecentCompileHold();
|
||||
const u64 elapsed = now - last;
|
||||
if (elapsed >= hold)
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f - static_cast<float>(elapsed) / static_cast<float>(hold_ns);
|
||||
return 1.0f - static_cast<float>(elapsed) / static_cast<float>(hold);
|
||||
}
|
||||
|
||||
struct ScopedCompilation
|
||||
struct CompileTimer
|
||||
{
|
||||
ScopedCompilation() { BeginCompilation(); }
|
||||
~ScopedCompilation() { EndCompilation(); }
|
||||
ScopedCompilation(const ScopedCompilation&) = delete;
|
||||
ScopedCompilation& operator=(const ScopedCompilation&) = delete;
|
||||
Common::Timer timer;
|
||||
|
||||
CompileTimer() = default;
|
||||
|
||||
~CompileTimer()
|
||||
{
|
||||
OnCompileDone(static_cast<u64>(timer.GetTimeNanoseconds()), timer.GetStartValue());
|
||||
}
|
||||
|
||||
CompileTimer(const CompileTimer&) = delete;
|
||||
CompileTimer& operator=(const CompileTimer&) = delete;
|
||||
};
|
||||
} // namespace GSShaderCompileIndicator
|
||||
|
||||
@@ -488,7 +488,7 @@ wil::com_ptr_nothrow<ID3DBlob> D3D::CompileShader(D3D::ShaderType type, D3D::Sha
|
||||
const std::string_view code, const D3D_SHADER_MACRO* macros /* = nullptr */,
|
||||
const char* entry_point /* = "main" */)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
|
||||
const char* target;
|
||||
switch (shader_model)
|
||||
|
||||
@@ -541,7 +541,7 @@ D3D12ShaderCache::ComPtr<ID3DBlob> D3D12ShaderCache::CompileAndAddShaderBlob(
|
||||
D3D12ShaderCache::ComPtr<ID3D12PipelineState> D3D12ShaderCache::CompileAndAddPipeline(
|
||||
ID3D12Device* device, const CacheIndexKey& key, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
|
||||
ComPtr<ID3D12PipelineState> pso;
|
||||
HRESULT hr = device->CreateGraphicsPipelineState(&gpdesc, IID_PPV_ARGS(pso.put()));
|
||||
@@ -558,7 +558,7 @@ D3D12ShaderCache::ComPtr<ID3D12PipelineState> D3D12ShaderCache::CompileAndAddPip
|
||||
D3D12ShaderCache::ComPtr<ID3D12PipelineState> D3D12ShaderCache::CompileAndAddPipeline(
|
||||
ID3D12Device* device, const CacheIndexKey& key, const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
|
||||
ComPtr<ID3D12PipelineState> pso;
|
||||
HRESULT hr = device->CreateComputePipelineState(&gpdesc, IID_PPV_ARGS(pso.put()));
|
||||
|
||||
@@ -713,7 +713,7 @@ MRCOwned<id<MTLFunction>> GSDeviceMTL::LoadShader(NSString* name)
|
||||
|
||||
MRCOwned<id<MTLRenderPipelineState>> GSDeviceMTL::MakePipeline(MTLRenderPipelineDescriptor* desc, id<MTLFunction> vertex, id<MTLFunction> fragment, NSString* name)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
[desc setLabel:name];
|
||||
[desc setVertexFunction:vertex];
|
||||
[desc setFragmentFunction:fragment];
|
||||
@@ -730,7 +730,7 @@ MRCOwned<id<MTLRenderPipelineState>> GSDeviceMTL::MakePipeline(MTLRenderPipeline
|
||||
|
||||
MRCOwned<id<MTLComputePipelineState>> GSDeviceMTL::MakeComputePipeline(id<MTLFunction> compute, NSString* name)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
MRCOwned<MTLComputePipelineDescriptor*> desc = MRCTransfer([MTLComputePipelineDescriptor new]);
|
||||
[desc setLabel:name];
|
||||
[desc setComputeFunction:compute];
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "GSMTLDeviceInfo.h"
|
||||
#include "GS/GS.h"
|
||||
#include "GS/GSShaderCompileIndicator.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/Path.h"
|
||||
|
||||
@@ -57,10 +56,7 @@ static bool detectPrimIDSupport(id<MTLDevice> dev, id<MTLLibrary> lib)
|
||||
[desc setFragmentFunction:MRCTransfer([lib newFunctionWithName:@"primid_test"])];
|
||||
[[desc colorAttachments][0] setPixelFormat:MTLPixelFormatR8Uint];
|
||||
NSError* err;
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
[[dev newRenderPipelineStateWithDescriptor:desc error:&err] release];
|
||||
}
|
||||
[[dev newRenderPipelineStateWithDescriptor:desc error:&err] release];
|
||||
return !err;
|
||||
}
|
||||
|
||||
@@ -92,11 +88,7 @@ static DetectionResult detectIntelGPU(id<MTLDevice> dev, id<MTLLibrary> lib)
|
||||
[pdesc setVertexFunction:MRCTransfer([lib newFunctionWithName:@"fs_triangle"])];
|
||||
[pdesc setFragmentFunction:MRCTransfer([lib newFunctionWithName:@"fbfetch_test"])];
|
||||
[[pdesc colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA8Unorm];
|
||||
MRCOwned<id<MTLRenderPipelineState>> pipe;
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
pipe = MRCTransfer([dev newRenderPipelineStateWithDescriptor:pdesc error:nil]);
|
||||
}
|
||||
auto pipe = MRCTransfer([dev newRenderPipelineStateWithDescriptor:pdesc error:nil]);
|
||||
if (!pipe)
|
||||
return DetectionResult::HaswellOrNotIntel;
|
||||
auto buf = MRCTransfer([dev newBufferWithLength:4 options:MTLResourceStorageModeShared]);
|
||||
|
||||
@@ -367,7 +367,7 @@ bool GLShaderCache::WriteToBlobFile(const CacheIndexKey& key, const std::vector<
|
||||
std::optional<GLProgram> GLShaderCache::CompileProgram(const std::string_view vertex_shader,
|
||||
const std::string_view fragment_shader, const PreLinkCallback& callback, bool set_retrievable)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
|
||||
GLProgram prog;
|
||||
if (!prog.Compile(vertex_shader, fragment_shader))
|
||||
@@ -388,7 +388,7 @@ std::optional<GLProgram> GLShaderCache::CompileProgram(const std::string_view ve
|
||||
std::optional<GLProgram> GLShaderCache::CompileComputeProgram(
|
||||
const std::string_view glsl, const PreLinkCallback& callback, bool set_retrievable)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
|
||||
GLProgram prog;
|
||||
if (!prog.CompileCompute(glsl))
|
||||
|
||||
@@ -280,7 +280,7 @@ void Vulkan::GraphicsPipelineBuilder::Clear()
|
||||
VkPipeline Vulkan::GraphicsPipelineBuilder::Create(
|
||||
VkDevice device, VkPipelineCache pipeline_cache, bool clear /* = true */)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkResult res = vkCreateGraphicsPipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
|
||||
@@ -591,7 +591,7 @@ void Vulkan::ComputePipelineBuilder::Clear()
|
||||
VkPipeline Vulkan::ComputePipelineBuilder::Create(
|
||||
VkDevice device, VkPipelineCache pipeline_cache /*= VK_NULL_HANDLE*/, bool clear /*= true*/)
|
||||
{
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkResult res = vkCreateComputePipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
|
||||
|
||||
@@ -231,7 +231,7 @@ std::optional<VKShaderCache::SPIRVCodeVector> VKShaderCache::CompileShaderToSPV(
|
||||
if (!dyn_shaderc::Open())
|
||||
return ret;
|
||||
|
||||
const GSShaderCompileIndicator::ScopedCompilation compiling;
|
||||
const GSShaderCompileIndicator::CompileTimer compile_timer;
|
||||
|
||||
shaderc_compile_options_t options = dyn_shaderc::shaderc_compile_options_initialize();
|
||||
pxAssertRel(options, "shaderc_compile_options_initialize() failed");
|
||||
|
||||
@@ -785,7 +785,7 @@ __ri void ImGuiManager::DrawShaderCompileIndicator(float scale, float margin, fl
|
||||
static bool s_indicator_was_visible = false;
|
||||
static double s_indicator_fade_in_start = 0.0;
|
||||
|
||||
if (!GSConfig.OsdShowGPU || !GSShaderCompileIndicator::ShouldShowOnOSD())
|
||||
if (!GSConfig.OsdShowGPU || !GSShaderCompileIndicator::IsVisible())
|
||||
{
|
||||
s_indicator_was_visible = false;
|
||||
return;
|
||||
@@ -799,14 +799,23 @@ __ri void ImGuiManager::DrawShaderCompileIndicator(float scale, float margin, fl
|
||||
constexpr double fade_in_seconds = 0.12;
|
||||
const float fade_in_alpha = static_cast<float>(
|
||||
std::min(1.0, (imgui_time - s_indicator_fade_in_start) / fade_in_seconds));
|
||||
const float fade_out_alpha = GSShaderCompileIndicator::GetPostCompileFadeAlpha();
|
||||
const float indicator_alpha = std::clamp(fade_in_alpha * fade_out_alpha, 0.0f, 1.0f);
|
||||
const ImU32 text_col = IM_COL32(255, 255, 255, static_cast<int>(std::lround(255.0f * indicator_alpha)));
|
||||
const ImU32 shadow_col = IM_COL32(0, 0, 0, static_cast<int>(std::lround(100.0f * indicator_alpha)));
|
||||
const ImU32 spinner_track_col =
|
||||
IM_COL32(255, 255, 255, static_cast<int>(std::lround(45.0f * indicator_alpha)));
|
||||
const float fade_out_alpha = GSShaderCompileIndicator::GetFadeAlpha();
|
||||
const float alpha = std::clamp(fade_in_alpha * fade_out_alpha, 0.0f, 1.0f);
|
||||
const ImU32 text_col = IM_COL32(255, 255, 255, static_cast<int>(std::lround(255.0f * alpha)));
|
||||
const ImU32 shadow_col = IM_COL32(0, 0, 0, static_cast<int>(std::lround(100.0f * alpha)));
|
||||
const ImU32 spinner_track_col = IM_COL32(255, 255, 255, static_cast<int>(std::lround(45.0f * alpha)));
|
||||
|
||||
static constexpr const char* COMPILED_ONE =
|
||||
TRANSLATE_NOOP("ImGuiOverlays", "Compiled {0} shader in {1}ms");
|
||||
static constexpr const char* COMPILED_MANY =
|
||||
TRANSLATE_NOOP("ImGuiOverlays", "Compiled {0} shaders in {1}ms");
|
||||
|
||||
const u32 count = GSShaderCompileIndicator::GetCount();
|
||||
const u32 time_ms = GSShaderCompileIndicator::GetTimeMs();
|
||||
const std::string label = (count == 1) ?
|
||||
fmt::format(TRANSLATE_FS("ImGuiOverlays", COMPILED_ONE), count, time_ms) :
|
||||
fmt::format(TRANSLATE_FS("ImGuiOverlays", COMPILED_MANY), count, time_ms);
|
||||
|
||||
const std::string label = TRANSLATE_STR("ImGuiOverlays", "Compiling Shaders");
|
||||
ImFont* const font = ImGuiManager::GetOSDFont();
|
||||
const float font_size = ImGuiManager::GetFontSizeStandard();
|
||||
const float baseline_y =
|
||||
|
||||
Reference in New Issue
Block a user