#include "RenderEngine.h" #include RenderEngine::RenderEngine( RuntimeHost& runtimeHost, RuntimeSnapshotProvider& runtimeSnapshotProvider, CRITICAL_SECTION& mutex, HDC hdc, HGLRC hglrc, RenderEffectCallback renderEffect, ScreenshotCallback screenshotReady, PreviewPaintCallback previewPaint) : mRenderer(), mRenderPass(mRenderer), mRenderPipeline(mRenderer, runtimeHost, std::move(renderEffect), std::move(screenshotReady), std::move(previewPaint)), mShaderPrograms(mRenderer, runtimeHost, runtimeSnapshotProvider), mMutex(mutex), mHdc(hdc), mHglrc(hglrc) { } RenderEngine::~RenderEngine() { mRenderer.DestroyResources(); } bool RenderEngine::CompileDecodeShader(int errorMessageSize, char* errorMessage) { return mShaderPrograms.CompileDecodeShader(errorMessageSize, errorMessage); } bool RenderEngine::CompileOutputPackShader(int errorMessageSize, char* errorMessage) { return mShaderPrograms.CompileOutputPackShader(errorMessageSize, errorMessage); } bool RenderEngine::InitializeResources( unsigned inputFrameWidth, unsigned inputFrameHeight, unsigned captureTextureWidth, unsigned outputFrameWidth, unsigned outputFrameHeight, unsigned outputPackTextureWidth, std::string& 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); } bool RenderEngine::CommitPreparedLayerPrograms(const PreparedShaderBuild& preparedBuild, unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage) { return mShaderPrograms.CommitPreparedLayerPrograms(preparedBuild, inputFrameWidth, inputFrameHeight, errorMessageSize, errorMessage); } const std::vector& RenderEngine::CommittedLayerStates() const { return mShaderPrograms.CommittedLayerStates(); } void RenderEngine::ResetTemporalHistoryState() { mShaderPrograms.ResetTemporalHistoryState(); } void RenderEngine::ResetShaderFeedbackState() { mShaderPrograms.ResetShaderFeedbackState(); } void RenderEngine::ResizeView(int width, int height) { mRenderer.ResizeView(width, height); } bool RenderEngine::TryPresentToWindow(unsigned outputFrameWidth, unsigned outputFrameHeight) { if (!TryEnterCriticalSection(&mMutex)) return false; mRenderer.PresentToWindow(mHdc, outputFrameWidth, outputFrameHeight); LeaveCriticalSection(&mMutex); return true; } bool RenderEngine::TryUploadInputFrame(const VideoIOFrame& inputFrame, const VideoIOState& videoState) { if (inputFrame.hasNoInputSource || inputFrame.bytes == nullptr) return true; const long textureSize = inputFrame.rowBytes * static_cast(inputFrame.height); if (!TryEnterCriticalSection(&mMutex)) return false; wglMakeCurrent(mHdc, mHglrc); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mRenderer.TextureUploadBuffer()); glBufferData(GL_PIXEL_UNPACK_BUFFER, textureSize, inputFrame.bytes, GL_DYNAMIC_DRAW); glBindTexture(GL_TEXTURE_2D, mRenderer.CaptureTexture()); if (inputFrame.pixelFormat == VideoIOPixelFormat::V210) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoState.captureTextureWidth, videoState.inputFrameSize.height, GL_RGBA, GL_UNSIGNED_BYTE, NULL); else glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, videoState.captureTextureWidth, videoState.inputFrameSize.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); glBindTexture(GL_TEXTURE_2D, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); wglMakeCurrent(NULL, NULL); LeaveCriticalSection(&mMutex); return true; } bool RenderEngine::RenderOutputFrame(const RenderPipelineFrameContext& context, VideoIOOutputFrame& outputFrame) { EnterCriticalSection(&mMutex); wglMakeCurrent(mHdc, mHglrc); const bool rendered = mRenderPipeline.RenderFrame(context, outputFrame); wglMakeCurrent(NULL, NULL); LeaveCriticalSection(&mMutex); return rendered; } void RenderEngine::RenderLayerStack( bool hasInputSource, const std::vector& layerStates, unsigned inputFrameWidth, unsigned inputFrameHeight, unsigned captureTextureWidth, VideoIOPixelFormat inputPixelFormat, unsigned historyCap) { mRenderPass.Render( hasInputSource, layerStates, inputFrameWidth, inputFrameHeight, captureTextureWidth, inputPixelFormat, historyCap, [this](const RuntimeRenderState& state, OpenGLRenderer::LayerProgram::TextBinding& textBinding, std::string& error) { return mShaderPrograms.UpdateTextBindingTexture(state, textBinding, error); }, [this](const RuntimeRenderState& state, unsigned availableSourceHistoryLength, unsigned availableTemporalHistoryLength, bool feedbackAvailable) { return mShaderPrograms.UpdateGlobalParamsBuffer(state, availableSourceHistoryLength, availableTemporalHistoryLength, feedbackAvailable); }); } bool RenderEngine::ReadOutputFrameRgba(unsigned width, unsigned height, std::vector& bottomUpPixels) { if (width == 0 || height == 0) return false; EnterCriticalSection(&mMutex); wglMakeCurrent(mHdc, mHglrc); bottomUpPixels.resize(static_cast(width) * height * 4); glBindFramebuffer(GL_READ_FRAMEBUFFER, mRenderer.OutputFramebuffer()); glReadBuffer(GL_COLOR_ATTACHMENT0); glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ROW_LENGTH, 0); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, bottomUpPixels.data()); glPixelStorei(GL_PACK_ALIGNMENT, 4); wglMakeCurrent(NULL, NULL); LeaveCriticalSection(&mMutex); return true; }