/* -LICENSE-START- ** Copyright (c) 2012 Blackmagic Design ** ** Permission is hereby granted, free of charge, to any person or organization ** obtaining a copy of the software and accompanying documentation (the ** "Software") to use, reproduce, display, distribute, sub-license, execute, ** and transmit the Software, and to prepare derivative works of the Software, ** and to permit third-parties to whom the Software is furnished to do so, in ** accordance with: ** ** (1) if the Software is obtained from Blackmagic Design, the End User License ** Agreement for the Software Development Kit ("EULA") available at ** https://www.blackmagicdesign.com/EULA/DeckLinkSDK; or ** ** (2) if the Software is obtained from any third party, such licensing terms ** as notified by that third party, ** ** and all subject to the following: ** ** (3) the copyright notices in the Software and this entire statement, ** including the above license grant, this restriction and the following ** disclaimer, must be included in all copies of the Software, in whole or in ** part, and all derivative works of the Software, unless such copies or ** derivative works are solely in the form of machine-executable object code ** generated by a source language processor. ** ** (4) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT ** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE ** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ** DEALINGS IN THE SOFTWARE. ** ** A copy of the Software is available free of charge at ** https://www.blackmagicdesign.com/desktopvideo_sdk under the EULA. ** ** -LICENSE-END- */ #ifndef __OPENGL_COMPOSITE_H__ #define __OPENGL_COMPOSITE_H__ #include #include #include #include #include #include #include #include #include "DeckLinkAPI_h.h" #include "GLExtensions.h" #include "RuntimeHost.h" #include #include #include #include #include #include class PlayoutDelegate; class CaptureDelegate; class PinnedMemoryAllocator; class ControlServer; class OscServer; class OpenGLComposite { public: OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC); ~OpenGLComposite(); bool InitDeckLink(); bool Start(); bool Stop(); bool ReloadShader(); std::string GetRuntimeStateJson() const; bool AddLayer(const std::string& shaderId, std::string& error); bool RemoveLayer(const std::string& layerId, std::string& error); bool MoveLayer(const std::string& layerId, int direction, std::string& error); bool MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error); bool SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error); bool SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error); bool UpdateLayerParameterJson(const std::string& layerId, const std::string& parameterId, const std::string& valueJson, std::string& error); bool UpdateLayerParameterByControlKeyJson(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error); bool ResetLayerParameters(const std::string& layerId, std::string& error); bool SaveStackPreset(const std::string& presetName, std::string& error); bool LoadStackPreset(const std::string& presetName, std::string& error); void resizeGL(WORD width, WORD height); void paintGL(); void VideoFrameArrived(IDeckLinkVideoInputFrame* inputFrame, bool hasNoInputSource); void PlayoutFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result); private: void resizeWindow(int width, int height); bool CheckOpenGLExtensions(); CaptureDelegate* mCaptureDelegate; PlayoutDelegate* mPlayoutDelegate; HWND hGLWnd; HDC hGLDC; HGLRC hGLRC; CRITICAL_SECTION pMutex; // DeckLink IDeckLinkInput* mDLInput; IDeckLinkOutput* mDLOutput; IDeckLinkKeyer* mDLKeyer; std::deque mDLOutputVideoFrameQueue; PinnedMemoryAllocator* mPlayoutAllocator; BMDTimeValue mFrameDuration; BMDTimeScale mFrameTimescale; unsigned mTotalPlayoutFrames; unsigned mInputFrameWidth; unsigned mInputFrameHeight; unsigned mOutputFrameWidth; unsigned mOutputFrameHeight; std::string mInputDisplayModeName; std::string mOutputDisplayModeName; bool mHasNoInputSource; std::string mDeckLinkOutputModelName; bool mDeckLinkSupportsInternalKeying; bool mDeckLinkSupportsExternalKeying; bool mDeckLinkKeyerInterfaceAvailable; bool mDeckLinkExternalKeyingActive; std::string mDeckLinkStatusMessage; // OpenGL data bool mFastTransferExtensionAvailable; GLuint mCaptureTexture; GLuint mDecodedTexture; GLuint mLayerTempTexture; GLuint mFBOTexture; GLuint mOutputTexture; GLuint mUnpinnedTextureBuffer; GLuint mDecodeFrameBuf; GLuint mLayerTempFrameBuf; GLuint mIdFrameBuf; GLuint mOutputFrameBuf; GLuint mIdColorBuf; GLuint mIdDepthBuf; GLuint mFullscreenVAO; GLuint mGlobalParamsUBO; GLuint mDecodeProgram; GLuint mDecodeVertexShader; GLuint mDecodeFragmentShader; GLsizeiptr mGlobalParamsUBOSize; int mViewWidth; int mViewHeight; std::unique_ptr mRuntimeHost; std::unique_ptr mControlServer; std::unique_ptr mOscServer; struct LayerProgram { struct TextureBinding { std::string samplerName; std::filesystem::path sourcePath; GLuint texture = 0; }; struct TextBinding { std::string parameterId; std::string samplerName; std::string fontId; GLuint texture = 0; std::string renderedText; unsigned renderedWidth = 0; unsigned renderedHeight = 0; }; std::string layerId; std::string shaderId; GLuint shaderTextureBase = 0; GLuint program = 0; GLuint vertexShader = 0; GLuint fragmentShader = 0; std::vector textureBindings; std::vector textBindings; }; std::vector mLayerPrograms; struct HistorySlot { GLuint texture = 0; GLuint framebuffer = 0; }; struct HistoryRing { std::vector slots; std::size_t nextWriteIndex = 0; std::size_t filledCount = 0; unsigned effectiveLength = 0; TemporalHistorySource historySource = TemporalHistorySource::None; }; HistoryRing mSourceHistoryRing; std::map mPreLayerHistoryByLayerId; bool mTemporalHistoryNeedsReset; bool InitOpenGLState(); bool compileLayerPrograms(int errorMessageSize, char* errorMessage); bool compileSingleLayerProgram(const RuntimeRenderState& state, LayerProgram& layerProgram, int errorMessageSize, char* errorMessage); bool compileDecodeShader(int errorMessageSize, char* errorMessage); void destroyLayerPrograms(); void destroySingleLayerProgram(LayerProgram& layerProgram); void destroyDecodeShaderProgram(); void renderDecodePass(); void renderShaderProgram(GLuint sourceTexture, GLuint destinationFrameBuffer, LayerProgram& layerProgram, const RuntimeRenderState& state); bool loadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error); bool renderTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error); void bindLayerTextureAssets(const LayerProgram& layerProgram); void renderEffect(); bool PollRuntimeChanges(); void broadcastRuntimeState(); bool updateGlobalParamsBuffer(const RuntimeRenderState& state, unsigned availableSourceHistoryLength, unsigned availableTemporalHistoryLength); bool validateTemporalTextureUnitBudget(const std::vector& layerStates, std::string& error) const; bool ensureTemporalHistoryResources(const std::vector& layerStates, std::string& error); bool createHistoryRing(HistoryRing& ring, unsigned effectiveLength, TemporalHistorySource historySource, std::string& error); void destroyHistoryRing(HistoryRing& ring); void destroyTemporalHistoryResources(); void resetTemporalHistoryState(); void pushFramebufferToHistoryRing(GLuint sourceFramebuffer, HistoryRing& ring); void bindHistorySamplers(const RuntimeRenderState& state, GLuint currentSourceTexture); GLuint resolveHistoryTexture(const HistoryRing& ring, GLuint fallbackTexture, std::size_t framesAgo) const; unsigned sourceHistoryAvailableCount() const; unsigned temporalHistoryAvailableCountForLayer(const std::string& layerId) const; }; #endif // __OPENGL_COMPOSITE_H__