Step 3
This commit is contained in:
@@ -26,17 +26,128 @@ RenderEngine::RenderEngine(
|
||||
|
||||
RenderEngine::~RenderEngine()
|
||||
{
|
||||
mRenderer.DestroyResources();
|
||||
StopRenderThread();
|
||||
if (!mResourcesDestroyed)
|
||||
{
|
||||
mRenderer.DestroyResources();
|
||||
mResourcesDestroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderEngine::StartRenderThread()
|
||||
{
|
||||
if (mRenderThreadRunning)
|
||||
return true;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mRenderThreadMutex);
|
||||
mRenderThreadStopping = false;
|
||||
}
|
||||
|
||||
std::promise<bool> ready;
|
||||
std::future<bool> readyResult = ready.get_future();
|
||||
mRenderThread = std::thread(&RenderEngine::RenderThreadMain, this, std::move(ready));
|
||||
if (!readyResult.get())
|
||||
{
|
||||
if (mRenderThread.joinable())
|
||||
mRenderThread.join();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderEngine::StopRenderThread()
|
||||
{
|
||||
if (mRenderThreadRunning)
|
||||
{
|
||||
InvokeOnRenderThread([this]() {
|
||||
if (!mResourcesDestroyed)
|
||||
{
|
||||
mRenderer.DestroyResources();
|
||||
mResourcesDestroyed = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mRenderThreadMutex);
|
||||
mRenderThreadStopping = true;
|
||||
}
|
||||
mRenderThreadCondition.notify_one();
|
||||
|
||||
if (mRenderThread.joinable())
|
||||
mRenderThread.join();
|
||||
}
|
||||
|
||||
void RenderEngine::RenderThreadMain(std::promise<bool> ready)
|
||||
{
|
||||
mRenderThreadId = GetCurrentThreadId();
|
||||
if (!wglMakeCurrent(mHdc, mHglrc))
|
||||
{
|
||||
mRenderThreadId = 0;
|
||||
ready.set_value(false);
|
||||
return;
|
||||
}
|
||||
|
||||
mRenderThreadRunning = true;
|
||||
ready.set_value(true);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
std::function<void()> task;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mRenderThreadMutex);
|
||||
mRenderThreadCondition.wait(lock, [this]() {
|
||||
return mRenderThreadStopping || !mRenderThreadTasks.empty();
|
||||
});
|
||||
|
||||
if (mRenderThreadStopping && mRenderThreadTasks.empty())
|
||||
break;
|
||||
|
||||
task = std::move(mRenderThreadTasks.front());
|
||||
mRenderThreadTasks.pop();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
task();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
OutputDebugStringA("Render thread task failed with an unhandled exception.\n");
|
||||
}
|
||||
}
|
||||
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
mRenderThreadRunning = false;
|
||||
mRenderThreadId = 0;
|
||||
}
|
||||
|
||||
void RenderEngine::ReportRenderThreadRequestFailure(const char* operationName, const char* reason)
|
||||
{
|
||||
std::ostringstream message;
|
||||
message << "Render thread request failed";
|
||||
if (operationName && operationName[0] != '\0')
|
||||
message << " [" << operationName << "]";
|
||||
if (reason && reason[0] != '\0')
|
||||
message << ": " << reason;
|
||||
message << ".\n";
|
||||
OutputDebugStringA(message.str().c_str());
|
||||
}
|
||||
|
||||
bool RenderEngine::CompileDecodeShader(int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
return mShaderPrograms.CompileDecodeShader(errorMessageSize, errorMessage);
|
||||
return InvokeOnRenderThread([this, errorMessageSize, errorMessage]() {
|
||||
return mShaderPrograms.CompileDecodeShader(errorMessageSize, errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
bool RenderEngine::CompileOutputPackShader(int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
return mShaderPrograms.CompileOutputPackShader(errorMessageSize, errorMessage);
|
||||
return InvokeOnRenderThread([this, errorMessageSize, errorMessage]() {
|
||||
return mShaderPrograms.CompileOutputPackShader(errorMessageSize, errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
bool RenderEngine::InitializeResources(
|
||||
@@ -48,24 +159,30 @@ bool RenderEngine::InitializeResources(
|
||||
unsigned outputPackTextureWidth,
|
||||
std::string& error)
|
||||
{
|
||||
return mRenderer.InitializeResources(
|
||||
inputFrameWidth,
|
||||
inputFrameHeight,
|
||||
captureTextureWidth,
|
||||
outputFrameWidth,
|
||||
outputFrameHeight,
|
||||
outputPackTextureWidth,
|
||||
error);
|
||||
return InvokeOnRenderThread([this, inputFrameWidth, inputFrameHeight, captureTextureWidth, outputFrameWidth, outputFrameHeight, outputPackTextureWidth, &error]() {
|
||||
return mRenderer.InitializeResources(
|
||||
inputFrameWidth,
|
||||
inputFrameHeight,
|
||||
captureTextureWidth,
|
||||
outputFrameWidth,
|
||||
outputFrameHeight,
|
||||
outputPackTextureWidth,
|
||||
error);
|
||||
});
|
||||
}
|
||||
|
||||
bool RenderEngine::CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
return mShaderPrograms.CompileLayerPrograms(inputFrameWidth, inputFrameHeight, errorMessageSize, errorMessage);
|
||||
return InvokeOnRenderThread([this, inputFrameWidth, inputFrameHeight, errorMessageSize, errorMessage]() {
|
||||
return mShaderPrograms.CompileLayerPrograms(inputFrameWidth, inputFrameHeight, errorMessageSize, errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
bool RenderEngine::CommitPreparedLayerPrograms(const PreparedShaderBuild& preparedBuild, unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage)
|
||||
{
|
||||
return mShaderPrograms.CommitPreparedLayerPrograms(preparedBuild, inputFrameWidth, inputFrameHeight, errorMessageSize, errorMessage);
|
||||
return InvokeOnRenderThread([this, &preparedBuild, inputFrameWidth, inputFrameHeight, errorMessageSize, errorMessage]() {
|
||||
return mShaderPrograms.CommitPreparedLayerPrograms(preparedBuild, inputFrameWidth, inputFrameHeight, errorMessageSize, errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
bool RenderEngine::ApplyPreparedShaderBuild(
|
||||
@@ -88,32 +205,38 @@ bool RenderEngine::ApplyPreparedShaderBuild(
|
||||
|
||||
void RenderEngine::ResetTemporalHistoryState()
|
||||
{
|
||||
mRenderCommandQueue.RequestRenderReset(RenderCommandResetScope::TemporalHistoryOnly);
|
||||
ProcessRenderResetCommandsOnRenderThread();
|
||||
InvokeOnRenderThread([this]() {
|
||||
mRenderCommandQueue.RequestRenderReset(RenderCommandResetScope::TemporalHistoryOnly);
|
||||
ProcessRenderResetCommandsOnRenderThread();
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEngine::ResetShaderFeedbackState()
|
||||
{
|
||||
mRenderCommandQueue.RequestRenderReset(RenderCommandResetScope::ShaderFeedbackOnly);
|
||||
ProcessRenderResetCommandsOnRenderThread();
|
||||
InvokeOnRenderThread([this]() {
|
||||
mRenderCommandQueue.RequestRenderReset(RenderCommandResetScope::ShaderFeedbackOnly);
|
||||
ProcessRenderResetCommandsOnRenderThread();
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEngine::ApplyRuntimeCoordinatorRenderReset(RuntimeCoordinatorRenderResetScope resetScope)
|
||||
{
|
||||
switch (resetScope)
|
||||
{
|
||||
case RuntimeCoordinatorRenderResetScope::TemporalHistoryOnly:
|
||||
mRenderCommandQueue.RequestRenderReset(RenderCommandResetScope::TemporalHistoryOnly);
|
||||
ProcessRenderResetCommandsOnRenderThread();
|
||||
break;
|
||||
case RuntimeCoordinatorRenderResetScope::TemporalHistoryAndFeedback:
|
||||
mRenderCommandQueue.RequestRenderReset(RenderCommandResetScope::TemporalHistoryAndFeedback);
|
||||
ProcessRenderResetCommandsOnRenderThread();
|
||||
break;
|
||||
case RuntimeCoordinatorRenderResetScope::None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
InvokeOnRenderThread([this, resetScope]() {
|
||||
switch (resetScope)
|
||||
{
|
||||
case RuntimeCoordinatorRenderResetScope::TemporalHistoryOnly:
|
||||
mRenderCommandQueue.RequestRenderReset(RenderCommandResetScope::TemporalHistoryOnly);
|
||||
ProcessRenderResetCommandsOnRenderThread();
|
||||
break;
|
||||
case RuntimeCoordinatorRenderResetScope::TemporalHistoryAndFeedback:
|
||||
mRenderCommandQueue.RequestRenderReset(RenderCommandResetScope::TemporalHistoryAndFeedback);
|
||||
ProcessRenderResetCommandsOnRenderThread();
|
||||
break;
|
||||
case RuntimeCoordinatorRenderResetScope::None:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEngine::ResetTemporalHistoryStateOnRenderThread()
|
||||
@@ -177,7 +300,9 @@ void RenderEngine::UpdateOscOverlayState(
|
||||
|
||||
void RenderEngine::ResizeView(int width, int height)
|
||||
{
|
||||
mRenderer.ResizeView(width, height);
|
||||
InvokeOnRenderThread([this, width, height]() {
|
||||
mRenderer.ResizeView(width, height);
|
||||
});
|
||||
}
|
||||
|
||||
bool RenderEngine::TryPresentPreview(bool force, unsigned previewFps, unsigned outputFrameWidth, unsigned outputFrameHeight)
|
||||
@@ -196,6 +321,16 @@ bool RenderEngine::TryPresentPreview(bool force, unsigned previewFps, unsigned o
|
||||
}
|
||||
}
|
||||
|
||||
if (mRenderThreadRunning)
|
||||
{
|
||||
return TryInvokeOnRenderThread("preview-present", [this, outputFrameWidth, outputFrameHeight]() {
|
||||
mRenderCommandQueue.RequestPreviewPresent({ outputFrameWidth, outputFrameHeight });
|
||||
RenderPreviewPresentRequest request;
|
||||
return mRenderCommandQueue.TryTakePreviewPresent(request) &&
|
||||
PresentPreviewOnRenderThread(request.outputFrameWidth, request.outputFrameHeight);
|
||||
});
|
||||
}
|
||||
|
||||
if (!TryEnterCriticalSection(&mMutex))
|
||||
return false;
|
||||
|
||||
@@ -219,11 +354,24 @@ bool RenderEngine::TryUploadInputFrame(const VideoIOFrame& inputFrame, const Vid
|
||||
if (inputFrame.hasNoInputSource || inputFrame.bytes == nullptr)
|
||||
return true;
|
||||
|
||||
if (mRenderThreadRunning)
|
||||
{
|
||||
return TryInvokeOnRenderThread("input-upload", [this, inputFrame, videoState]() {
|
||||
mRenderCommandQueue.RequestInputUpload({ inputFrame, videoState });
|
||||
RenderInputUploadRequest request;
|
||||
return mRenderCommandQueue.TryTakeInputUpload(request) &&
|
||||
UploadInputFrameOnRenderThread(request.inputFrame, request.videoState);
|
||||
});
|
||||
}
|
||||
|
||||
if (!TryEnterCriticalSection(&mMutex))
|
||||
return false;
|
||||
|
||||
wglMakeCurrent(mHdc, mHglrc);
|
||||
const bool uploaded = UploadInputFrameOnRenderThread(inputFrame, videoState);
|
||||
mRenderCommandQueue.RequestInputUpload({ inputFrame, videoState });
|
||||
RenderInputUploadRequest request;
|
||||
const bool uploaded = mRenderCommandQueue.TryTakeInputUpload(request) &&
|
||||
UploadInputFrameOnRenderThread(request.inputFrame, request.videoState);
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
LeaveCriticalSection(&mMutex);
|
||||
return uploaded;
|
||||
@@ -249,9 +397,22 @@ bool RenderEngine::UploadInputFrameOnRenderThread(const VideoIOFrame& inputFrame
|
||||
|
||||
bool RenderEngine::RenderOutputFrame(const RenderPipelineFrameContext& context, VideoIOOutputFrame& outputFrame)
|
||||
{
|
||||
if (mRenderThreadRunning)
|
||||
{
|
||||
return TryInvokeOnRenderThread("output-render", [this, &context, &outputFrame]() {
|
||||
mRenderCommandQueue.RequestOutputFrame({ context.videoState, context.completion });
|
||||
RenderOutputFrameRequest request;
|
||||
return mRenderCommandQueue.TryTakeOutputFrame(request) &&
|
||||
RenderOutputFrameOnRenderThread({ request.videoState, request.completion }, outputFrame);
|
||||
});
|
||||
}
|
||||
|
||||
EnterCriticalSection(&mMutex);
|
||||
wglMakeCurrent(mHdc, mHglrc);
|
||||
const bool rendered = RenderOutputFrameOnRenderThread(context, outputFrame);
|
||||
mRenderCommandQueue.RequestOutputFrame({ context.videoState, context.completion });
|
||||
RenderOutputFrameRequest request;
|
||||
const bool rendered = mRenderCommandQueue.TryTakeOutputFrame(request) &&
|
||||
RenderOutputFrameOnRenderThread({ request.videoState, request.completion }, outputFrame);
|
||||
wglMakeCurrent(NULL, NULL);
|
||||
LeaveCriticalSection(&mMutex);
|
||||
return rendered;
|
||||
@@ -339,6 +500,16 @@ bool RenderEngine::ReadOutputFrameRgbaOnRenderThread(unsigned width, unsigned he
|
||||
|
||||
bool RenderEngine::CaptureOutputFrameRgbaTopDown(unsigned width, unsigned height, std::vector<unsigned char>& topDownPixels)
|
||||
{
|
||||
if (mRenderThreadRunning)
|
||||
{
|
||||
return TryInvokeOnRenderThread("screenshot-capture", [this, width, height, &topDownPixels]() {
|
||||
mRenderCommandQueue.RequestScreenshotCapture({ width, height });
|
||||
RenderScreenshotCaptureRequest request;
|
||||
return mRenderCommandQueue.TryTakeScreenshotCapture(request) &&
|
||||
CaptureOutputFrameRgbaTopDownOnRenderThread(request.width, request.height, topDownPixels);
|
||||
});
|
||||
}
|
||||
|
||||
EnterCriticalSection(&mMutex);
|
||||
wglMakeCurrent(mHdc, mHglrc);
|
||||
mRenderCommandQueue.RequestScreenshotCapture({ width, height });
|
||||
|
||||
Reference in New Issue
Block a user