Pacing problems
This commit is contained in:
@@ -53,12 +53,17 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
||||
hGLWnd(hWnd), hGLDC(hDC), hGLRC(hRC),
|
||||
mDeckLink(std::make_unique<DeckLinkSession>()),
|
||||
mRenderer(std::make_unique<OpenGLRenderer>())
|
||||
mRenderer(std::make_unique<OpenGLRenderer>()),
|
||||
mRuntimePollRunning(false),
|
||||
mRuntimeRegistryChanged(false),
|
||||
mRuntimeReloadRequested(false),
|
||||
mRuntimePollFailed(false)
|
||||
{
|
||||
InitializeCriticalSection(&pMutex);
|
||||
mRuntimeHost = std::make_unique<RuntimeHost>();
|
||||
@@ -79,6 +84,7 @@ OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
||||
|
||||
OpenGLComposite::~OpenGLComposite()
|
||||
{
|
||||
StopRuntimePolling();
|
||||
mDeckLink->ReleaseResources();
|
||||
mRenderer->DestroyResources();
|
||||
if (mOscServer)
|
||||
@@ -284,6 +290,7 @@ bool OpenGLComposite::InitOpenGLState()
|
||||
}
|
||||
|
||||
broadcastRuntimeState();
|
||||
StartRuntimePolling();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -305,6 +312,8 @@ bool OpenGLComposite::Start()
|
||||
|
||||
bool OpenGLComposite::Stop()
|
||||
{
|
||||
StopRuntimePolling();
|
||||
|
||||
if (mOscServer)
|
||||
mOscServer->Stop();
|
||||
|
||||
@@ -351,10 +360,17 @@ bool OpenGLComposite::ReloadShader()
|
||||
|
||||
void OpenGLComposite::renderEffect()
|
||||
{
|
||||
PollRuntimeChanges();
|
||||
ProcessRuntimePollResults();
|
||||
|
||||
const bool hasInputSource = mDeckLink->HasInputSource();
|
||||
const std::vector<RuntimeRenderState> layerStates = mRuntimeHost ? mRuntimeHost->GetLayerRenderStates(mDeckLink->InputFrameWidth(), mDeckLink->InputFrameHeight()) : std::vector<RuntimeRenderState>();
|
||||
std::vector<RuntimeRenderState> layerStates;
|
||||
if (mRuntimeHost)
|
||||
{
|
||||
if (mRuntimeHost->TryGetLayerRenderStates(mDeckLink->InputFrameWidth(), mDeckLink->InputFrameHeight(), layerStates))
|
||||
mCachedLayerRenderStates = layerStates;
|
||||
else
|
||||
layerStates = mCachedLayerRenderStates;
|
||||
}
|
||||
const unsigned historyCap = mRuntimeHost ? mRuntimeHost->GetMaxTemporalHistoryFrames() : 0;
|
||||
mRenderPass->Render(
|
||||
hasInputSource,
|
||||
@@ -370,25 +386,72 @@ void OpenGLComposite::renderEffect()
|
||||
});
|
||||
}
|
||||
|
||||
bool OpenGLComposite::PollRuntimeChanges()
|
||||
void OpenGLComposite::StartRuntimePolling()
|
||||
{
|
||||
if (!mRuntimeHost || mRuntimePollRunning.exchange(true))
|
||||
return;
|
||||
|
||||
mRuntimePollThread = std::thread([this]() { RuntimePollLoop(); });
|
||||
}
|
||||
|
||||
void OpenGLComposite::StopRuntimePolling()
|
||||
{
|
||||
if (!mRuntimePollRunning.exchange(false))
|
||||
return;
|
||||
|
||||
if (mRuntimePollThread.joinable())
|
||||
mRuntimePollThread.join();
|
||||
}
|
||||
|
||||
void OpenGLComposite::RuntimePollLoop()
|
||||
{
|
||||
while (mRuntimePollRunning)
|
||||
{
|
||||
bool registryChanged = false;
|
||||
bool reloadRequested = false;
|
||||
std::string runtimeError;
|
||||
if (!mRuntimeHost->PollFileChanges(registryChanged, reloadRequested, runtimeError))
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mRuntimePollErrorMutex);
|
||||
mRuntimePollError = runtimeError;
|
||||
}
|
||||
mRuntimePollFailed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (registryChanged)
|
||||
mRuntimeRegistryChanged = true;
|
||||
if (reloadRequested)
|
||||
mRuntimeReloadRequested = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 25 && mRuntimePollRunning; ++i)
|
||||
Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenGLComposite::ProcessRuntimePollResults()
|
||||
{
|
||||
if (!mRuntimeHost)
|
||||
return true;
|
||||
|
||||
bool registryChanged = false;
|
||||
bool reloadRequested = false;
|
||||
std::string runtimeError;
|
||||
if (!mRuntimeHost->PollFileChanges(registryChanged, reloadRequested, runtimeError))
|
||||
if (mRuntimePollFailed.exchange(false))
|
||||
{
|
||||
std::string runtimeError;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mRuntimePollErrorMutex);
|
||||
runtimeError = mRuntimePollError;
|
||||
}
|
||||
mRuntimeHost->SetCompileStatus(false, runtimeError);
|
||||
broadcastRuntimeState();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (registryChanged)
|
||||
if (mRuntimeRegistryChanged.exchange(false))
|
||||
broadcastRuntimeState();
|
||||
|
||||
if (!reloadRequested)
|
||||
if (!mRuntimeReloadRequested.exchange(false))
|
||||
return true;
|
||||
|
||||
char compilerErrorMessage[1024] = {};
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
|
||||
@@ -119,10 +122,21 @@ private:
|
||||
std::unique_ptr<OpenGLShaderPrograms> mShaderPrograms;
|
||||
std::unique_ptr<ControlServer> mControlServer;
|
||||
std::unique_ptr<OscServer> mOscServer;
|
||||
std::thread mRuntimePollThread;
|
||||
std::atomic<bool> mRuntimePollRunning;
|
||||
std::atomic<bool> mRuntimeRegistryChanged;
|
||||
std::atomic<bool> mRuntimeReloadRequested;
|
||||
std::atomic<bool> mRuntimePollFailed;
|
||||
std::mutex mRuntimePollErrorMutex;
|
||||
std::string mRuntimePollError;
|
||||
std::vector<RuntimeRenderState> mCachedLayerRenderStates;
|
||||
|
||||
bool InitOpenGLState();
|
||||
void renderEffect();
|
||||
bool PollRuntimeChanges();
|
||||
void StartRuntimePolling();
|
||||
void StopRuntimePolling();
|
||||
void RuntimePollLoop();
|
||||
bool ProcessRuntimePollResults();
|
||||
void broadcastRuntimeState();
|
||||
void resetTemporalHistoryState();
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ void OpenGLDeckLinkBridge::RecordFramePacing(BMDOutputFrameCompletionResult comp
|
||||
else if (completionResult == bmdOutputFrameFlushed)
|
||||
++mFlushedFrameCount;
|
||||
|
||||
mRuntimeHost.SetFramePacingStats(
|
||||
mRuntimeHost.TrySetFramePacingStats(
|
||||
mCompletionIntervalMilliseconds,
|
||||
mSmoothedCompletionIntervalMilliseconds,
|
||||
mMaxCompletionIntervalMilliseconds,
|
||||
@@ -64,7 +64,7 @@ void OpenGLDeckLinkBridge::RecordFramePacing(BMDOutputFrameCompletionResult comp
|
||||
void OpenGLDeckLinkBridge::VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame, bool hasNoInputSource)
|
||||
{
|
||||
mDeckLink.SetInputSourceMissing(hasNoInputSource);
|
||||
mRuntimeHost.SetSignalStatus(!hasNoInputSource, mDeckLink.InputFrameWidth(), mDeckLink.InputFrameHeight(), mDeckLink.InputDisplayModeName());
|
||||
mRuntimeHost.TrySetSignalStatus(!hasNoInputSource, mDeckLink.InputFrameWidth(), mDeckLink.InputFrameHeight(), mDeckLink.InputDisplayModeName());
|
||||
|
||||
if (!mDeckLink.HasInputSource())
|
||||
return; // don't transfer texture when there's no input
|
||||
@@ -147,8 +147,8 @@ void OpenGLDeckLinkBridge::PlayoutFrameCompleted(IDeckLinkVideoFrame* completedF
|
||||
const auto renderEndTime = std::chrono::steady_clock::now();
|
||||
const double frameBudgetMilliseconds = mDeckLink.FrameBudgetMilliseconds();
|
||||
const double renderMilliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(renderEndTime - renderStartTime).count();
|
||||
mRuntimeHost.SetPerformanceStats(frameBudgetMilliseconds, renderMilliseconds);
|
||||
mRuntimeHost.AdvanceFrame();
|
||||
mRuntimeHost.TrySetPerformanceStats(frameBudgetMilliseconds, renderMilliseconds);
|
||||
mRuntimeHost.TryAdvanceFrame();
|
||||
|
||||
IDeckLinkVideoBuffer* outputVideoFrameBuffer;
|
||||
if (outputVideoFrame->QueryInterface(IID_IDeckLinkVideoBuffer, (void**)&outputVideoFrameBuffer) != S_OK)
|
||||
|
||||
Reference in New Issue
Block a user