#include "RenderThread.h" #include "../frames/InputFrameMailbox.h" #include "../frames/SystemFrameExchange.h" #include "../frames/SystemFrameTypes.h" #include "../logging/Logger.h" #include "../platform/HiddenGlWindow.h" #include "InputFrameTexture.h" #include "readback/OutputReadbackPipeline.h" #include "GLExtensions.h" #include "RuntimeRenderScene.h" #include "SimpleMotionRenderer.h" #include #include void RenderThread::ThreadMain() { RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread starting."); HiddenGlWindow window; std::string error; if (!window.Create(mConfig.width, mConfig.height, error)) { SignalStartupFailure(error.empty() ? "OpenGL context creation failed." : error); return; } std::unique_ptr prepareWindow = std::make_unique(); if (!prepareWindow->CreateShared(mConfig.width, mConfig.height, window.DeviceContext(), window.Context(), error)) { SignalStartupFailure(error.empty() ? "Runtime shader prepare shared context creation failed." : error); return; } if (!window.MakeCurrent()) { SignalStartupFailure("OpenGL context creation failed."); return; } if (!ResolveGLExtensions()) { SignalStartupFailure("OpenGL extension resolution failed."); return; } SimpleMotionRenderer renderer; RuntimeRenderScene runtimeRenderScene; OutputReadbackPipeline readback; InputFrameTexture inputTexture; if (!runtimeRenderScene.StartPrepareWorker(std::move(prepareWindow), error)) { SignalStartupFailure(error.empty() ? "Runtime shader prepare worker initialization failed." : error); return; } if (!renderer.InitializeGl(mConfig.width, mConfig.height) || !readback.Initialize(mConfig.width, mConfig.height, mConfig.outputPixelFormat, mConfig.pboDepth)) { SignalStartupFailure("Render pipeline initialization failed."); return; } RenderCadenceClock clock(mConfig.frameDurationMilliseconds); uint64_t frameIndex = 0; mRunning.store(true, std::memory_order_release); SignalStarted(); while (!mStopping.load(std::memory_order_acquire)) { readback.ConsumeCompleted( [this](SystemFrame& frame) { return mFrameExchange.AcquireForRender(frame); }, [this](const SystemFrame& frame) { return mFrameExchange.PublishCompleted(frame); }, [this]() { CountAcquireMiss(); }, [this]() { CountCompleted(); }); PublishReadbackMetrics(readback); const auto now = RenderCadenceClock::Clock::now(); const RenderCadenceClock::Tick tick = clock.Poll(now); if (!tick.due) { if (tick.sleepFor > RenderCadenceClock::Duration::zero()) std::this_thread::sleep_for(tick.sleepFor); continue; } TryCommitReadyRuntimeShader(runtimeRenderScene); const GLuint videoInputTexture = inputTexture.PollAndUpload(mInputMailbox); PublishInputMetrics(inputTexture); if (!readback.RenderAndQueue(frameIndex, [this, &renderer, &runtimeRenderScene, videoInputTexture](uint64_t index) { if (runtimeRenderScene.HasLayers()) runtimeRenderScene.RenderFrame(index, mConfig.width, mConfig.height, videoInputTexture); else if (videoInputTexture != 0) renderer.RenderTexture(videoInputTexture); else renderer.RenderFrame(index); })) { mPboQueueMisses.fetch_add(1, std::memory_order_relaxed); } PublishReadbackMetrics(readback); CountRendered(); ++frameIndex; clock.MarkRendered(RenderCadenceClock::Clock::now()); mClockOverruns.store(clock.OverrunCount(), std::memory_order_relaxed); mSkippedFrames.store(clock.SkippedFrameCount(), std::memory_order_relaxed); } for (std::size_t i = 0; i < mConfig.pboDepth * 2; ++i) { readback.ConsumeCompleted( [this](SystemFrame& frame) { return mFrameExchange.AcquireForRender(frame); }, [this](const SystemFrame& frame) { return mFrameExchange.PublishCompleted(frame); }, [this]() { CountAcquireMiss(); }, [this]() { CountCompleted(); }); PublishReadbackMetrics(readback); } readback.Shutdown(); inputTexture.ShutdownGl(); runtimeRenderScene.ShutdownGl(); renderer.ShutdownGl(); window.ClearCurrent(); mRunning.store(false, std::memory_order_release); RenderCadenceCompositor::TryLog(RenderCadenceCompositor::LogLevel::Log, "render-thread", "Render thread stopped."); }