#pragma once #include "RenderCadenceClock.h" #include "../runtime/RuntimeSlangShaderCompiler.h" #include "RuntimeShaderRenderer.h" #include #include #include #include #include #include #include class SystemFrameExchange; class RenderThread { public: struct Config { unsigned width = 1920; unsigned height = 1080; double frameDurationMilliseconds = 1000.0 / 59.94; std::size_t pboDepth = 6; }; struct Metrics { uint64_t renderedFrames = 0; uint64_t completedReadbacks = 0; uint64_t acquireMisses = 0; uint64_t pboQueueMisses = 0; uint64_t clockOverruns = 0; uint64_t skippedFrames = 0; uint64_t shaderBuildsCommitted = 0; uint64_t shaderBuildFailures = 0; }; RenderThread(SystemFrameExchange& frameExchange, Config config); RenderThread(const RenderThread&) = delete; RenderThread& operator=(const RenderThread&) = delete; ~RenderThread(); bool Start(std::string& error); void Stop(); Metrics GetMetrics() const; bool IsRunning() const { return mRunning.load(std::memory_order_acquire); } private: void ThreadMain(); void SignalStarted(); void SignalStartupFailure(const std::string& error); void CountRendered(); void CountCompleted(); void CountAcquireMiss(); void TryCommitReadyRuntimeShader(RuntimeShaderRenderer& runtimeShaderRenderer); SystemFrameExchange& mFrameExchange; Config mConfig; RuntimeSlangShaderCompiler mSlangCompiler; std::thread mThread; std::atomic mStopping{ false }; std::atomic mRunning{ false }; mutable std::mutex mStartupMutex; std::condition_variable mStartupCondition; bool mStarted = false; std::string mStartupError; mutable std::mutex mMetricsMutex; Metrics mMetrics; };