Compare commits
4 Commits
v0.0.5
...
7f0f60c0e3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f0f60c0e3 | ||
|
|
739231d5a1 | ||
|
|
3629227aa9 | ||
|
|
618831d578 |
@@ -34,6 +34,8 @@ set(APP_SOURCES
|
|||||||
"${APP_DIR}/videoio/decklink/DeckLinkAPI_i.c"
|
"${APP_DIR}/videoio/decklink/DeckLinkAPI_i.c"
|
||||||
"${APP_DIR}/control/ControlServer.cpp"
|
"${APP_DIR}/control/ControlServer.cpp"
|
||||||
"${APP_DIR}/control/ControlServer.h"
|
"${APP_DIR}/control/ControlServer.h"
|
||||||
|
"${APP_DIR}/control/ControlServices.cpp"
|
||||||
|
"${APP_DIR}/control/ControlServices.h"
|
||||||
"${APP_DIR}/control/OscServer.cpp"
|
"${APP_DIR}/control/OscServer.cpp"
|
||||||
"${APP_DIR}/control/OscServer.h"
|
"${APP_DIR}/control/OscServer.h"
|
||||||
"${APP_DIR}/control/RuntimeControlBridge.cpp"
|
"${APP_DIR}/control/RuntimeControlBridge.cpp"
|
||||||
@@ -60,6 +62,8 @@ set(APP_SOURCES
|
|||||||
"${APP_DIR}/gl/OpenGLComposite.cpp"
|
"${APP_DIR}/gl/OpenGLComposite.cpp"
|
||||||
"${APP_DIR}/gl/OpenGLComposite.h"
|
"${APP_DIR}/gl/OpenGLComposite.h"
|
||||||
"${APP_DIR}/gl/OpenGLCompositeRuntimeControls.cpp"
|
"${APP_DIR}/gl/OpenGLCompositeRuntimeControls.cpp"
|
||||||
|
"${APP_DIR}/gl/RenderEngine.cpp"
|
||||||
|
"${APP_DIR}/gl/RenderEngine.h"
|
||||||
"${APP_DIR}/gl/pipeline/OpenGLRenderPass.cpp"
|
"${APP_DIR}/gl/pipeline/OpenGLRenderPass.cpp"
|
||||||
"${APP_DIR}/gl/pipeline/OpenGLRenderPass.h"
|
"${APP_DIR}/gl/pipeline/OpenGLRenderPass.h"
|
||||||
"${APP_DIR}/gl/pipeline/OpenGLRenderPipeline.cpp"
|
"${APP_DIR}/gl/pipeline/OpenGLRenderPipeline.cpp"
|
||||||
@@ -98,12 +102,18 @@ set(APP_SOURCES
|
|||||||
"${APP_DIR}/resource.h"
|
"${APP_DIR}/resource.h"
|
||||||
"${APP_DIR}/runtime/RuntimeHost.cpp"
|
"${APP_DIR}/runtime/RuntimeHost.cpp"
|
||||||
"${APP_DIR}/runtime/RuntimeHost.h"
|
"${APP_DIR}/runtime/RuntimeHost.h"
|
||||||
|
"${APP_DIR}/runtime/HealthTelemetry.cpp"
|
||||||
|
"${APP_DIR}/runtime/HealthTelemetry.h"
|
||||||
|
"${APP_DIR}/runtime/RuntimeSnapshotProvider.cpp"
|
||||||
|
"${APP_DIR}/runtime/RuntimeSnapshotProvider.h"
|
||||||
"${APP_DIR}/runtime/RuntimeClock.cpp"
|
"${APP_DIR}/runtime/RuntimeClock.cpp"
|
||||||
"${APP_DIR}/runtime/RuntimeClock.h"
|
"${APP_DIR}/runtime/RuntimeClock.h"
|
||||||
"${APP_DIR}/runtime/RuntimeJson.cpp"
|
"${APP_DIR}/runtime/RuntimeJson.cpp"
|
||||||
"${APP_DIR}/runtime/RuntimeJson.h"
|
"${APP_DIR}/runtime/RuntimeJson.h"
|
||||||
"${APP_DIR}/runtime/RuntimeParameterUtils.cpp"
|
"${APP_DIR}/runtime/RuntimeParameterUtils.cpp"
|
||||||
"${APP_DIR}/runtime/RuntimeParameterUtils.h"
|
"${APP_DIR}/runtime/RuntimeParameterUtils.h"
|
||||||
|
"${APP_DIR}/runtime/RuntimeStore.cpp"
|
||||||
|
"${APP_DIR}/runtime/RuntimeStore.h"
|
||||||
"${APP_DIR}/shader/ShaderCompiler.cpp"
|
"${APP_DIR}/shader/ShaderCompiler.cpp"
|
||||||
"${APP_DIR}/shader/ShaderCompiler.h"
|
"${APP_DIR}/shader/ShaderCompiler.h"
|
||||||
"${APP_DIR}/shader/ShaderPackageRegistry.cpp"
|
"${APP_DIR}/shader/ShaderPackageRegistry.cpp"
|
||||||
@@ -114,6 +124,8 @@ set(APP_SOURCES
|
|||||||
"${APP_DIR}/targetver.h"
|
"${APP_DIR}/targetver.h"
|
||||||
"${APP_DIR}/videoio/VideoIOFormat.cpp"
|
"${APP_DIR}/videoio/VideoIOFormat.cpp"
|
||||||
"${APP_DIR}/videoio/VideoIOFormat.h"
|
"${APP_DIR}/videoio/VideoIOFormat.h"
|
||||||
|
"${APP_DIR}/videoio/VideoBackend.cpp"
|
||||||
|
"${APP_DIR}/videoio/VideoBackend.h"
|
||||||
"${APP_DIR}/videoio/VideoIOTypes.h"
|
"${APP_DIR}/videoio/VideoIOTypes.h"
|
||||||
"${APP_DIR}/videoio/VideoPlayoutScheduler.cpp"
|
"${APP_DIR}/videoio/VideoPlayoutScheduler.cpp"
|
||||||
"${APP_DIR}/videoio/VideoPlayoutScheduler.h"
|
"${APP_DIR}/videoio/VideoPlayoutScheduler.h"
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>.;control;gl;gl\pipeline;gl\renderer;gl\shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>.;control;gl;gl\pipeline;gl\renderer;gl\shader;platform;runtime;shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>opengl32.lib;Glu32.lib;Windowscodecs.lib;Ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>opengl32.lib;Glu32.lib;Ws2_32.lib;Crypt32.lib;Advapi32.lib;Gdiplus.lib;Ole32.lib;Windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<TargetMachine>MachineX86</TargetMachine>
|
<TargetMachine>MachineX86</TargetMachine>
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
</Midl>
|
</Midl>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>.;control;gl;gl\pipeline;gl\renderer;gl\shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>.;control;gl;gl\pipeline;gl\renderer;gl\shader;platform;runtime;shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>opengl32.lib;Glu32.lib;Windowscodecs.lib;Ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>opengl32.lib;Glu32.lib;Ws2_32.lib;Crypt32.lib;Advapi32.lib;Gdiplus.lib;Ole32.lib;Windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<TargetMachine>MachineX64</TargetMachine>
|
<TargetMachine>MachineX64</TargetMachine>
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>.;control;gl;gl\pipeline;gl\renderer;gl\shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>.;control;gl;gl\pipeline;gl\renderer;gl\shader;platform;runtime;shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
@@ -141,7 +141,7 @@
|
|||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>opengl32.lib;Glu32.lib;Windowscodecs.lib;Ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>opengl32.lib;Glu32.lib;Ws2_32.lib;Crypt32.lib;Advapi32.lib;Gdiplus.lib;Ole32.lib;Windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>.;control;gl;gl\pipeline;gl\renderer;gl\shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>.;control;gl;gl\pipeline;gl\renderer;gl\shader;platform;runtime;shader;videoio;videoio\decklink;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
@@ -166,7 +166,7 @@
|
|||||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>opengl32.lib;Glu32.lib;Windowscodecs.lib;Ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>opengl32.lib;Glu32.lib;Ws2_32.lib;Crypt32.lib;Advapi32.lib;Gdiplus.lib;Ole32.lib;Windowscodecs.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
@@ -175,18 +175,32 @@
|
|||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="control\ControlServer.cpp" />
|
||||||
|
<ClCompile Include="control\ControlServices.cpp" />
|
||||||
|
<ClCompile Include="control\OscServer.cpp" />
|
||||||
|
<ClCompile Include="control\RuntimeControlBridge.cpp" />
|
||||||
|
<ClCompile Include="control\RuntimeServices.cpp" />
|
||||||
<ClCompile Include="gl\renderer\GLExtensions.cpp" />
|
<ClCompile Include="gl\renderer\GLExtensions.cpp" />
|
||||||
|
<ClCompile Include="gl\shader\GlobalParamsBuffer.cpp" />
|
||||||
|
<ClCompile Include="gl\shader\GlShaderSources.cpp" />
|
||||||
<ClCompile Include="LoopThroughWithOpenGLCompositing.cpp" />
|
<ClCompile Include="LoopThroughWithOpenGLCompositing.cpp" />
|
||||||
<ClCompile Include="gl\OpenGLComposite.cpp" />
|
<ClCompile Include="gl\OpenGLComposite.cpp" />
|
||||||
|
<ClCompile Include="gl\OpenGLCompositeRuntimeControls.cpp" />
|
||||||
|
<ClCompile Include="gl\RenderEngine.cpp" />
|
||||||
<ClCompile Include="gl\pipeline\OpenGLRenderPass.cpp" />
|
<ClCompile Include="gl\pipeline\OpenGLRenderPass.cpp" />
|
||||||
<ClCompile Include="gl\pipeline\OpenGLRenderPipeline.cpp" />
|
<ClCompile Include="gl\pipeline\OpenGLRenderPipeline.cpp" />
|
||||||
|
<ClCompile Include="gl\pipeline\ShaderFeedbackBuffers.cpp" />
|
||||||
<ClCompile Include="gl\renderer\OpenGLRenderer.cpp" />
|
<ClCompile Include="gl\renderer\OpenGLRenderer.cpp" />
|
||||||
<ClCompile Include="gl\renderer\RenderTargetPool.cpp" />
|
<ClCompile Include="gl\renderer\RenderTargetPool.cpp" />
|
||||||
|
<ClCompile Include="gl\pipeline\OpenGLVideoIOBridge.cpp" />
|
||||||
<ClCompile Include="gl\shader\OpenGLShaderPrograms.cpp" />
|
<ClCompile Include="gl\shader\OpenGLShaderPrograms.cpp" />
|
||||||
<ClCompile Include="gl\pipeline\PngScreenshotWriter.cpp" />
|
<ClCompile Include="gl\pipeline\PngScreenshotWriter.cpp" />
|
||||||
|
<ClCompile Include="gl\shader\ShaderProgramCompiler.cpp" />
|
||||||
<ClCompile Include="gl\shader\ShaderBuildQueue.cpp" />
|
<ClCompile Include="gl\shader\ShaderBuildQueue.cpp" />
|
||||||
|
<ClCompile Include="gl\shader\ShaderTextureBindings.cpp" />
|
||||||
|
<ClCompile Include="gl\shader\TextRasterizer.cpp" />
|
||||||
|
<ClCompile Include="gl\shader\TextureAssetLoader.cpp" />
|
||||||
<ClCompile Include="gl\pipeline\TemporalHistoryBuffers.cpp" />
|
<ClCompile Include="gl\pipeline\TemporalHistoryBuffers.cpp" />
|
||||||
<ClCompile Include="gl\pipeline\OpenGLVideoIOBridge.cpp" />
|
|
||||||
<ClCompile Include="stdafx.cpp">
|
<ClCompile Include="stdafx.cpp">
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||||
@@ -194,34 +208,74 @@
|
|||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="videoio\decklink\DeckLinkAPI_i.c" />
|
<ClCompile Include="videoio\decklink\DeckLinkAPI_i.c" />
|
||||||
<ClCompile Include="control\RuntimeServices.cpp" />
|
<ClCompile Include="videoio\decklink\DeckLinkDisplayMode.cpp" />
|
||||||
|
<ClCompile Include="videoio\decklink\DeckLinkFrameTransfer.cpp" />
|
||||||
<ClCompile Include="videoio\decklink\DeckLinkSession.cpp" />
|
<ClCompile Include="videoio\decklink\DeckLinkSession.cpp" />
|
||||||
<ClCompile Include="videoio\decklink\DeckLinkVideoIOFormat.cpp" />
|
<ClCompile Include="videoio\decklink\DeckLinkVideoIOFormat.cpp" />
|
||||||
|
<ClCompile Include="runtime\HealthTelemetry.cpp" />
|
||||||
<ClCompile Include="runtime\RuntimeClock.cpp" />
|
<ClCompile Include="runtime\RuntimeClock.cpp" />
|
||||||
|
<ClCompile Include="runtime\RuntimeHost.cpp" />
|
||||||
|
<ClCompile Include="runtime\RuntimeJson.cpp" />
|
||||||
|
<ClCompile Include="runtime\RuntimeParameterUtils.cpp" />
|
||||||
|
<ClCompile Include="runtime\RuntimeSnapshotProvider.cpp" />
|
||||||
|
<ClCompile Include="runtime\RuntimeStore.cpp" />
|
||||||
|
<ClCompile Include="shader\ShaderCompiler.cpp" />
|
||||||
|
<ClCompile Include="shader\ShaderPackageRegistry.cpp" />
|
||||||
|
<ClCompile Include="videoio\VideoBackend.cpp" />
|
||||||
<ClCompile Include="videoio\VideoIOFormat.cpp" />
|
<ClCompile Include="videoio\VideoIOFormat.cpp" />
|
||||||
<ClCompile Include="videoio\VideoPlayoutScheduler.cpp" />
|
<ClCompile Include="videoio\VideoPlayoutScheduler.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="control\ControlServer.h" />
|
||||||
|
<ClInclude Include="control\ControlServices.h" />
|
||||||
|
<ClInclude Include="control\OscServer.h" />
|
||||||
|
<ClInclude Include="control\RuntimeControlBridge.h" />
|
||||||
|
<ClInclude Include="control\RuntimeServices.h" />
|
||||||
<ClInclude Include="gl\renderer\GLExtensions.h" />
|
<ClInclude Include="gl\renderer\GLExtensions.h" />
|
||||||
|
<ClInclude Include="gl\shader\GlobalParamsBuffer.h" />
|
||||||
|
<ClInclude Include="gl\renderer\GlRenderConstants.h" />
|
||||||
|
<ClInclude Include="gl\renderer\GlScopedObjects.h" />
|
||||||
|
<ClInclude Include="gl\shader\GlShaderSources.h" />
|
||||||
<ClInclude Include="LoopThroughWithOpenGLCompositing.h" />
|
<ClInclude Include="LoopThroughWithOpenGLCompositing.h" />
|
||||||
<ClInclude Include="gl\OpenGLComposite.h" />
|
<ClInclude Include="gl\OpenGLComposite.h" />
|
||||||
|
<ClInclude Include="gl\RenderEngine.h" />
|
||||||
<ClInclude Include="gl\pipeline\OpenGLRenderPass.h" />
|
<ClInclude Include="gl\pipeline\OpenGLRenderPass.h" />
|
||||||
<ClInclude Include="gl\pipeline\OpenGLRenderPipeline.h" />
|
<ClInclude Include="gl\pipeline\OpenGLRenderPipeline.h" />
|
||||||
<ClInclude Include="gl\pipeline\RenderPassDescriptor.h" />
|
<ClInclude Include="gl\pipeline\RenderPassDescriptor.h" />
|
||||||
|
<ClInclude Include="gl\pipeline\ShaderFeedbackBuffers.h" />
|
||||||
<ClInclude Include="gl\renderer\OpenGLRenderer.h" />
|
<ClInclude Include="gl\renderer\OpenGLRenderer.h" />
|
||||||
<ClInclude Include="gl\renderer\RenderTargetPool.h" />
|
<ClInclude Include="gl\renderer\RenderTargetPool.h" />
|
||||||
|
<ClInclude Include="gl\pipeline\OpenGLVideoIOBridge.h" />
|
||||||
<ClInclude Include="gl\shader\OpenGLShaderPrograms.h" />
|
<ClInclude Include="gl\shader\OpenGLShaderPrograms.h" />
|
||||||
<ClInclude Include="gl\pipeline\PngScreenshotWriter.h" />
|
<ClInclude Include="gl\pipeline\PngScreenshotWriter.h" />
|
||||||
|
<ClInclude Include="gl\shader\ShaderProgramCompiler.h" />
|
||||||
<ClInclude Include="gl\shader\ShaderBuildQueue.h" />
|
<ClInclude Include="gl\shader\ShaderBuildQueue.h" />
|
||||||
|
<ClInclude Include="gl\shader\ShaderTextureBindings.h" />
|
||||||
|
<ClInclude Include="gl\shader\Std140Buffer.h" />
|
||||||
|
<ClInclude Include="gl\shader\TextRasterizer.h" />
|
||||||
|
<ClInclude Include="gl\shader\TextureAssetLoader.h" />
|
||||||
<ClInclude Include="gl\pipeline\TemporalHistoryBuffers.h" />
|
<ClInclude Include="gl\pipeline\TemporalHistoryBuffers.h" />
|
||||||
<ClInclude Include="gl\pipeline\OpenGLVideoIOBridge.h" />
|
<ClInclude Include="platform\NativeHandles.h" />
|
||||||
|
<ClInclude Include="platform\NativeSockets.h" />
|
||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
|
<ClInclude Include="runtime\HealthTelemetry.h" />
|
||||||
|
<ClInclude Include="runtime\RuntimeClock.h" />
|
||||||
|
<ClInclude Include="runtime\RuntimeHost.h" />
|
||||||
|
<ClInclude Include="runtime\RuntimeJson.h" />
|
||||||
|
<ClInclude Include="runtime\RuntimeParameterUtils.h" />
|
||||||
|
<ClInclude Include="runtime\RuntimeSnapshotProvider.h" />
|
||||||
|
<ClInclude Include="runtime\RuntimeStore.h" />
|
||||||
|
<ClInclude Include="shader\ShaderCompiler.h" />
|
||||||
|
<ClInclude Include="shader\ShaderPackageRegistry.h" />
|
||||||
|
<ClInclude Include="shader\ShaderTypes.h" />
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="stdafx.h" />
|
||||||
<ClInclude Include="targetver.h" />
|
<ClInclude Include="targetver.h" />
|
||||||
<ClInclude Include="control\RuntimeServices.h" />
|
<ClInclude Include="videoio\decklink\DeckLinkAPI_h.h" />
|
||||||
|
<ClInclude Include="videoio\decklink\DeckLinkDisplayMode.h" />
|
||||||
|
<ClInclude Include="videoio\decklink\DeckLinkFrameTransfer.h" />
|
||||||
<ClInclude Include="videoio\decklink\DeckLinkSession.h" />
|
<ClInclude Include="videoio\decklink\DeckLinkSession.h" />
|
||||||
<ClInclude Include="videoio\decklink\DeckLinkVideoIOFormat.h" />
|
<ClInclude Include="videoio\decklink\DeckLinkVideoIOFormat.h" />
|
||||||
<ClInclude Include="runtime\RuntimeClock.h" />
|
<ClInclude Include="videoio\VideoBackend.h" />
|
||||||
<ClInclude Include="videoio\VideoIOFormat.h" />
|
<ClInclude Include="videoio\VideoIOFormat.h" />
|
||||||
<ClInclude Include="videoio\VideoIOTypes.h" />
|
<ClInclude Include="videoio\VideoIOTypes.h" />
|
||||||
<ClInclude Include="videoio\VideoPlayoutScheduler.h" />
|
<ClInclude Include="videoio\VideoPlayoutScheduler.h" />
|
||||||
|
|||||||
@@ -18,21 +18,48 @@
|
|||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="control\ControlServer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="control\ControlServices.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="control\OscServer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="control\RuntimeControlBridge.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="gl\renderer\GLExtensions.cpp">
|
<ClCompile Include="gl\renderer\GLExtensions.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\shader\GlobalParamsBuffer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\shader\GlShaderSources.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="LoopThroughWithOpenGLCompositing.cpp">
|
<ClCompile Include="LoopThroughWithOpenGLCompositing.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="gl\OpenGLComposite.cpp">
|
<ClCompile Include="gl\OpenGLComposite.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\OpenGLCompositeRuntimeControls.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\RenderEngine.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="gl\pipeline\OpenGLRenderPass.cpp">
|
<ClCompile Include="gl\pipeline\OpenGLRenderPass.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="gl\pipeline\OpenGLRenderPipeline.cpp">
|
<ClCompile Include="gl\pipeline\OpenGLRenderPipeline.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\pipeline\ShaderFeedbackBuffers.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="gl\renderer\OpenGLRenderer.cpp">
|
<ClCompile Include="gl\renderer\OpenGLRenderer.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -45,9 +72,21 @@
|
|||||||
<ClCompile Include="gl\pipeline\PngScreenshotWriter.cpp">
|
<ClCompile Include="gl\pipeline\PngScreenshotWriter.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\shader\ShaderProgramCompiler.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="gl\shader\ShaderBuildQueue.cpp">
|
<ClCompile Include="gl\shader\ShaderBuildQueue.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\shader\ShaderTextureBindings.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\shader\TextRasterizer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="gl\shader\TextureAssetLoader.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="gl\pipeline\TemporalHistoryBuffers.cpp">
|
<ClCompile Include="gl\pipeline\TemporalHistoryBuffers.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -63,15 +102,48 @@
|
|||||||
<ClCompile Include="control\RuntimeServices.cpp">
|
<ClCompile Include="control\RuntimeServices.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="videoio\decklink\DeckLinkDisplayMode.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="videoio\decklink\DeckLinkFrameTransfer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="videoio\decklink\DeckLinkSession.cpp">
|
<ClCompile Include="videoio\decklink\DeckLinkSession.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="videoio\decklink\DeckLinkVideoIOFormat.cpp">
|
<ClCompile Include="videoio\decklink\DeckLinkVideoIOFormat.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="runtime\HealthTelemetry.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="runtime\RuntimeClock.cpp">
|
<ClCompile Include="runtime\RuntimeClock.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="runtime\RuntimeHost.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="runtime\RuntimeJson.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="runtime\RuntimeParameterUtils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="runtime\RuntimeSnapshotProvider.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="runtime\RuntimeStore.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="shader\ShaderCompiler.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="shader\ShaderPackageRegistry.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="videoio\VideoBackend.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="videoio\VideoIOFormat.cpp">
|
<ClCompile Include="videoio\VideoIOFormat.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -80,15 +152,42 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="control\ControlServer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="control\ControlServices.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="control\OscServer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="control\RuntimeControlBridge.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="gl\renderer\GLExtensions.h">
|
<ClInclude Include="gl\renderer\GLExtensions.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\shader\GlobalParamsBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\renderer\GlRenderConstants.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\renderer\GlScopedObjects.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\shader\GlShaderSources.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="LoopThroughWithOpenGLCompositing.h">
|
<ClInclude Include="LoopThroughWithOpenGLCompositing.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="gl\OpenGLComposite.h">
|
<ClInclude Include="gl\OpenGLComposite.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\RenderEngine.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="gl\pipeline\OpenGLRenderPass.h">
|
<ClInclude Include="gl\pipeline\OpenGLRenderPass.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -98,6 +197,9 @@
|
|||||||
<ClInclude Include="gl\pipeline\RenderPassDescriptor.h">
|
<ClInclude Include="gl\pipeline\RenderPassDescriptor.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\pipeline\ShaderFeedbackBuffers.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="gl\renderer\OpenGLRenderer.h">
|
<ClInclude Include="gl\renderer\OpenGLRenderer.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -110,18 +212,66 @@
|
|||||||
<ClInclude Include="gl\pipeline\PngScreenshotWriter.h">
|
<ClInclude Include="gl\pipeline\PngScreenshotWriter.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\shader\ShaderProgramCompiler.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="gl\shader\ShaderBuildQueue.h">
|
<ClInclude Include="gl\shader\ShaderBuildQueue.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\shader\ShaderTextureBindings.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\shader\Std140Buffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\shader\TextRasterizer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="gl\shader\TextureAssetLoader.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="gl\pipeline\TemporalHistoryBuffers.h">
|
<ClInclude Include="gl\pipeline\TemporalHistoryBuffers.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="gl\pipeline\OpenGLVideoIOBridge.h">
|
<ClInclude Include="gl\pipeline\OpenGLVideoIOBridge.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="platform\NativeHandles.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="platform\NativeSockets.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="resource.h">
|
<ClInclude Include="resource.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="runtime\HealthTelemetry.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="runtime\RuntimeHost.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="runtime\RuntimeJson.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="runtime\RuntimeParameterUtils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="runtime\RuntimeSnapshotProvider.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="runtime\RuntimeStore.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="shader\ShaderCompiler.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="shader\ShaderPackageRegistry.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="shader\ShaderTypes.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="stdafx.h">
|
<ClInclude Include="stdafx.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -137,6 +287,18 @@
|
|||||||
<ClInclude Include="videoio\decklink\DeckLinkVideoIOFormat.h">
|
<ClInclude Include="videoio\decklink\DeckLinkVideoIOFormat.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="videoio\decklink\DeckLinkAPI_h.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="videoio\decklink\DeckLinkDisplayMode.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="videoio\decklink\DeckLinkFrameTransfer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="videoio\VideoBackend.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="runtime\RuntimeClock.h">
|
<ClInclude Include="runtime\RuntimeClock.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|||||||
@@ -0,0 +1,247 @@
|
|||||||
|
#include "ControlServices.h"
|
||||||
|
|
||||||
|
#include "ControlServer.h"
|
||||||
|
#include "OscServer.h"
|
||||||
|
#include "RuntimeControlBridge.h"
|
||||||
|
#include "RuntimeHost.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
ControlServices::ControlServices() :
|
||||||
|
mControlServer(std::make_unique<ControlServer>()),
|
||||||
|
mOscServer(std::make_unique<OscServer>()),
|
||||||
|
mPollRunning(false),
|
||||||
|
mRegistryChanged(false),
|
||||||
|
mReloadRequested(false),
|
||||||
|
mPollFailed(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlServices::~ControlServices()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControlServices::Start(OpenGLComposite& composite, RuntimeHost& runtimeHost, std::string& error)
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
|
||||||
|
if (!StartControlServicesBoundary(composite, runtimeHost, *this, *mControlServer, *mOscServer, error))
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::BeginPolling(RuntimeHost& runtimeHost)
|
||||||
|
{
|
||||||
|
StartPolling(runtimeHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::Stop()
|
||||||
|
{
|
||||||
|
StopPolling();
|
||||||
|
|
||||||
|
if (mOscServer)
|
||||||
|
mOscServer->Stop();
|
||||||
|
|
||||||
|
if (mControlServer)
|
||||||
|
mControlServer->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::BroadcastState()
|
||||||
|
{
|
||||||
|
if (mControlServer)
|
||||||
|
mControlServer->BroadcastState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::RequestBroadcastState()
|
||||||
|
{
|
||||||
|
if (mControlServer)
|
||||||
|
mControlServer->RequestBroadcastState();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControlServices::QueueOscUpdate(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error)
|
||||||
|
{
|
||||||
|
(void)error;
|
||||||
|
|
||||||
|
PendingOscUpdate update;
|
||||||
|
update.layerKey = layerKey;
|
||||||
|
update.parameterKey = parameterKey;
|
||||||
|
update.valueJson = valueJson;
|
||||||
|
|
||||||
|
const std::string routeKey = layerKey + "\n" + parameterKey;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mPendingOscMutex);
|
||||||
|
mPendingOscUpdates[routeKey] = std::move(update);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControlServices::ApplyPendingOscUpdates(std::vector<AppliedOscUpdate>& appliedUpdates, std::string& error)
|
||||||
|
{
|
||||||
|
appliedUpdates.clear();
|
||||||
|
|
||||||
|
std::map<std::string, PendingOscUpdate> pending;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mPendingOscMutex);
|
||||||
|
if (mPendingOscUpdates.empty())
|
||||||
|
return true;
|
||||||
|
pending.swap(mPendingOscUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& entry : pending)
|
||||||
|
{
|
||||||
|
JsonValue targetValue;
|
||||||
|
std::string parseError;
|
||||||
|
if (!ParseJson(entry.second.valueJson, targetValue, parseError))
|
||||||
|
{
|
||||||
|
OutputDebugStringA(("OSC queued value parse failed: " + parseError + "\n").c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppliedOscUpdate appliedUpdate;
|
||||||
|
appliedUpdate.routeKey = entry.first;
|
||||||
|
appliedUpdate.layerKey = entry.second.layerKey;
|
||||||
|
appliedUpdate.parameterKey = entry.second.parameterKey;
|
||||||
|
appliedUpdate.targetValue = targetValue;
|
||||||
|
appliedUpdates.push_back(std::move(appliedUpdate));
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)error;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControlServices::QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, std::string& error)
|
||||||
|
{
|
||||||
|
(void)error;
|
||||||
|
|
||||||
|
PendingOscCommit commit;
|
||||||
|
commit.routeKey = routeKey;
|
||||||
|
commit.layerKey = layerKey;
|
||||||
|
commit.parameterKey = parameterKey;
|
||||||
|
commit.value = value;
|
||||||
|
commit.generation = generation;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mPendingOscCommitMutex);
|
||||||
|
mPendingOscCommits[routeKey] = std::move(commit);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::ClearOscState()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mPendingOscMutex);
|
||||||
|
mPendingOscUpdates.clear();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mPendingOscCommitMutex);
|
||||||
|
mPendingOscCommits.clear();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mCompletedOscCommitMutex);
|
||||||
|
mCompletedOscCommits.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>& completedCommits)
|
||||||
|
{
|
||||||
|
completedCommits.clear();
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(mCompletedOscCommitMutex);
|
||||||
|
if (mCompletedOscCommits.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
completedCommits.swap(mCompletedOscCommits);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimePollEvents ControlServices::ConsumePollEvents()
|
||||||
|
{
|
||||||
|
RuntimePollEvents events;
|
||||||
|
events.registryChanged = mRegistryChanged.exchange(false);
|
||||||
|
events.reloadRequested = mReloadRequested.exchange(false);
|
||||||
|
events.failed = mPollFailed.exchange(false);
|
||||||
|
|
||||||
|
if (events.failed)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mPollErrorMutex);
|
||||||
|
events.error = mPollError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::StartPolling(RuntimeHost& runtimeHost)
|
||||||
|
{
|
||||||
|
if (mPollRunning.exchange(true))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mPollThread = std::thread([this, &runtimeHost]() { PollLoop(runtimeHost); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::StopPolling()
|
||||||
|
{
|
||||||
|
if (!mPollRunning.exchange(false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mPollThread.joinable())
|
||||||
|
mPollThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlServices::PollLoop(RuntimeHost& runtimeHost)
|
||||||
|
{
|
||||||
|
while (mPollRunning)
|
||||||
|
{
|
||||||
|
std::map<std::string, PendingOscCommit> pendingCommits;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mPendingOscCommitMutex);
|
||||||
|
pendingCommits.swap(mPendingOscCommits);
|
||||||
|
}
|
||||||
|
for (const auto& entry : pendingCommits)
|
||||||
|
{
|
||||||
|
std::string commitError;
|
||||||
|
if (runtimeHost.UpdateLayerParameterByControlKey(
|
||||||
|
entry.second.layerKey,
|
||||||
|
entry.second.parameterKey,
|
||||||
|
entry.second.value,
|
||||||
|
false,
|
||||||
|
commitError))
|
||||||
|
{
|
||||||
|
CompletedOscCommit completedCommit;
|
||||||
|
completedCommit.routeKey = entry.second.routeKey;
|
||||||
|
completedCommit.generation = entry.second.generation;
|
||||||
|
std::lock_guard<std::mutex> lock(mCompletedOscCommitMutex);
|
||||||
|
mCompletedOscCommits.push_back(std::move(completedCommit));
|
||||||
|
}
|
||||||
|
else if (!commitError.empty())
|
||||||
|
{
|
||||||
|
OutputDebugStringA(("OSC commit failed: " + commitError + "\n").c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool registryChanged = false;
|
||||||
|
bool reloadRequested = false;
|
||||||
|
std::string runtimeError;
|
||||||
|
if (!runtimeHost.PollFileChanges(registryChanged, reloadRequested, runtimeError))
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mPollErrorMutex);
|
||||||
|
mPollError = runtimeError;
|
||||||
|
}
|
||||||
|
mPollFailed = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (registryChanged)
|
||||||
|
mRegistryChanged = true;
|
||||||
|
if (reloadRequested)
|
||||||
|
mReloadRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 25 && mPollRunning; ++i)
|
||||||
|
Sleep(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RuntimeJson.h"
|
||||||
|
#include "ShaderTypes.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class ControlServer;
|
||||||
|
class OpenGLComposite;
|
||||||
|
class OscServer;
|
||||||
|
class RuntimeHost;
|
||||||
|
|
||||||
|
struct RuntimePollEvents
|
||||||
|
{
|
||||||
|
bool registryChanged = false;
|
||||||
|
bool reloadRequested = false;
|
||||||
|
bool failed = false;
|
||||||
|
std::string error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ControlServices
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct AppliedOscUpdate
|
||||||
|
{
|
||||||
|
std::string routeKey;
|
||||||
|
std::string layerKey;
|
||||||
|
std::string parameterKey;
|
||||||
|
JsonValue targetValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompletedOscCommit
|
||||||
|
{
|
||||||
|
std::string routeKey;
|
||||||
|
uint64_t generation = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ControlServices();
|
||||||
|
~ControlServices();
|
||||||
|
|
||||||
|
bool Start(OpenGLComposite& composite, RuntimeHost& runtimeHost, std::string& error);
|
||||||
|
void BeginPolling(RuntimeHost& runtimeHost);
|
||||||
|
void Stop();
|
||||||
|
void BroadcastState();
|
||||||
|
void RequestBroadcastState();
|
||||||
|
bool QueueOscUpdate(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error);
|
||||||
|
bool ApplyPendingOscUpdates(std::vector<AppliedOscUpdate>& appliedUpdates, std::string& error);
|
||||||
|
bool QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, std::string& error);
|
||||||
|
void ClearOscState();
|
||||||
|
void ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>& completedCommits);
|
||||||
|
RuntimePollEvents ConsumePollEvents();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PendingOscUpdate
|
||||||
|
{
|
||||||
|
std::string layerKey;
|
||||||
|
std::string parameterKey;
|
||||||
|
std::string valueJson;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PendingOscCommit
|
||||||
|
{
|
||||||
|
std::string routeKey;
|
||||||
|
std::string layerKey;
|
||||||
|
std::string parameterKey;
|
||||||
|
JsonValue value;
|
||||||
|
uint64_t generation = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void StartPolling(RuntimeHost& runtimeHost);
|
||||||
|
void StopPolling();
|
||||||
|
void PollLoop(RuntimeHost& runtimeHost);
|
||||||
|
|
||||||
|
std::unique_ptr<ControlServer> mControlServer;
|
||||||
|
std::unique_ptr<OscServer> mOscServer;
|
||||||
|
std::thread mPollThread;
|
||||||
|
std::atomic<bool> mPollRunning;
|
||||||
|
std::atomic<bool> mRegistryChanged;
|
||||||
|
std::atomic<bool> mReloadRequested;
|
||||||
|
std::atomic<bool> mPollFailed;
|
||||||
|
std::mutex mPollErrorMutex;
|
||||||
|
std::string mPollError;
|
||||||
|
std::mutex mPendingOscMutex;
|
||||||
|
std::map<std::string, PendingOscUpdate> mPendingOscUpdates;
|
||||||
|
std::mutex mPendingOscCommitMutex;
|
||||||
|
std::map<std::string, PendingOscCommit> mPendingOscCommits;
|
||||||
|
std::mutex mCompletedOscCommitMutex;
|
||||||
|
std::vector<CompletedOscCommit> mCompletedOscCommits;
|
||||||
|
};
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
#include "RuntimeControlBridge.h"
|
#include "RuntimeControlBridge.h"
|
||||||
|
|
||||||
|
#include "ControlServices.h"
|
||||||
#include "ControlServer.h"
|
#include "ControlServer.h"
|
||||||
#include "OpenGLComposite.h"
|
#include "OpenGLComposite.h"
|
||||||
#include "OscServer.h"
|
#include "OscServer.h"
|
||||||
#include "RuntimeHost.h"
|
#include "RuntimeHost.h"
|
||||||
#include "RuntimeServices.h"
|
|
||||||
|
|
||||||
bool StartRuntimeControlServices(
|
bool StartControlServicesBoundary(
|
||||||
OpenGLComposite& composite,
|
OpenGLComposite& composite,
|
||||||
RuntimeHost& runtimeHost,
|
RuntimeHost& runtimeHost,
|
||||||
RuntimeServices& runtimeServices,
|
ControlServices& controlServices,
|
||||||
ControlServer& controlServer,
|
ControlServer& controlServer,
|
||||||
OscServer& oscServer,
|
OscServer& oscServer,
|
||||||
std::string& error)
|
std::string& error)
|
||||||
@@ -43,8 +43,8 @@ bool StartRuntimeControlServices(
|
|||||||
runtimeHost.SetServerPort(controlServer.GetPort());
|
runtimeHost.SetServerPort(controlServer.GetPort());
|
||||||
|
|
||||||
OscServer::Callbacks oscCallbacks;
|
OscServer::Callbacks oscCallbacks;
|
||||||
oscCallbacks.updateParameter = [&runtimeServices](const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& actionError) {
|
oscCallbacks.updateParameter = [&controlServices](const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& actionError) {
|
||||||
return runtimeServices.QueueOscUpdate(layerKey, parameterKey, valueJson, actionError);
|
return controlServices.QueueOscUpdate(layerKey, parameterKey, valueJson, actionError);
|
||||||
};
|
};
|
||||||
if (runtimeHost.GetOscPort() > 0 && !oscServer.Start(runtimeHost.GetOscBindAddress(), runtimeHost.GetOscPort(), oscCallbacks, error))
|
if (runtimeHost.GetOscPort() > 0 && !oscServer.Start(runtimeHost.GetOscBindAddress(), runtimeHost.GetOscPort(), oscCallbacks, error))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class ControlServer;
|
class ControlServer;
|
||||||
|
class ControlServices;
|
||||||
class OpenGLComposite;
|
class OpenGLComposite;
|
||||||
class OscServer;
|
class OscServer;
|
||||||
class RuntimeHost;
|
class RuntimeHost;
|
||||||
class RuntimeServices;
|
|
||||||
|
|
||||||
bool StartRuntimeControlServices(
|
bool StartControlServicesBoundary(
|
||||||
OpenGLComposite& composite,
|
OpenGLComposite& composite,
|
||||||
RuntimeHost& runtimeHost,
|
RuntimeHost& runtimeHost,
|
||||||
RuntimeServices& runtimeServices,
|
ControlServices& controlServices,
|
||||||
ControlServer& controlServer,
|
ControlServer& controlServer,
|
||||||
OscServer& oscServer,
|
OscServer& oscServer,
|
||||||
std::string& error);
|
std::string& error);
|
||||||
|
|||||||
@@ -1,18 +1,7 @@
|
|||||||
#include "RuntimeServices.h"
|
#include "RuntimeServices.h"
|
||||||
|
|
||||||
#include "ControlServer.h"
|
|
||||||
#include "OscServer.h"
|
|
||||||
#include "RuntimeControlBridge.h"
|
|
||||||
#include "RuntimeHost.h"
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
RuntimeServices::RuntimeServices() :
|
RuntimeServices::RuntimeServices() :
|
||||||
mControlServer(std::make_unique<ControlServer>()),
|
mControlServices(std::make_unique<ControlServices>())
|
||||||
mOscServer(std::make_unique<OscServer>()),
|
|
||||||
mPollRunning(false),
|
|
||||||
mRegistryChanged(false),
|
|
||||||
mReloadRequested(false),
|
|
||||||
mPollFailed(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,225 +12,72 @@ RuntimeServices::~RuntimeServices()
|
|||||||
|
|
||||||
bool RuntimeServices::Start(OpenGLComposite& composite, RuntimeHost& runtimeHost, std::string& error)
|
bool RuntimeServices::Start(OpenGLComposite& composite, RuntimeHost& runtimeHost, std::string& error)
|
||||||
{
|
{
|
||||||
Stop();
|
return mControlServices && mControlServices->Start(composite, runtimeHost, error);
|
||||||
|
|
||||||
if (!StartRuntimeControlServices(composite, runtimeHost, *this, *mControlServer, *mOscServer, error))
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeServices::BeginPolling(RuntimeHost& runtimeHost)
|
void RuntimeServices::BeginPolling(RuntimeHost& runtimeHost)
|
||||||
{
|
{
|
||||||
StartPolling(runtimeHost);
|
if (mControlServices)
|
||||||
|
mControlServices->BeginPolling(runtimeHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeServices::Stop()
|
void RuntimeServices::Stop()
|
||||||
{
|
{
|
||||||
StopPolling();
|
if (mControlServices)
|
||||||
|
mControlServices->Stop();
|
||||||
if (mOscServer)
|
|
||||||
mOscServer->Stop();
|
|
||||||
|
|
||||||
if (mControlServer)
|
|
||||||
mControlServer->Stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeServices::BroadcastState()
|
void RuntimeServices::BroadcastState()
|
||||||
{
|
{
|
||||||
if (mControlServer)
|
if (mControlServices)
|
||||||
mControlServer->BroadcastState();
|
mControlServices->BroadcastState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeServices::RequestBroadcastState()
|
void RuntimeServices::RequestBroadcastState()
|
||||||
{
|
{
|
||||||
if (mControlServer)
|
if (mControlServices)
|
||||||
mControlServer->RequestBroadcastState();
|
mControlServices->RequestBroadcastState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeServices::QueueOscUpdate(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error)
|
bool RuntimeServices::QueueOscUpdate(const std::string& layerKey, const std::string& parameterKey, const std::string& valueJson, std::string& error)
|
||||||
{
|
{
|
||||||
(void)error;
|
return mControlServices && mControlServices->QueueOscUpdate(layerKey, parameterKey, valueJson, error);
|
||||||
|
|
||||||
PendingOscUpdate update;
|
|
||||||
update.layerKey = layerKey;
|
|
||||||
update.parameterKey = parameterKey;
|
|
||||||
update.valueJson = valueJson;
|
|
||||||
|
|
||||||
const std::string routeKey = layerKey + "\n" + parameterKey;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mPendingOscMutex);
|
|
||||||
mPendingOscUpdates[routeKey] = std::move(update);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeServices::ApplyPendingOscUpdates(std::vector<AppliedOscUpdate>& appliedUpdates, std::string& error)
|
bool RuntimeServices::ApplyPendingOscUpdates(std::vector<AppliedOscUpdate>& appliedUpdates, std::string& error)
|
||||||
{
|
{
|
||||||
appliedUpdates.clear();
|
if (!mControlServices)
|
||||||
|
|
||||||
std::map<std::string, PendingOscUpdate> pending;
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mPendingOscMutex);
|
appliedUpdates.clear();
|
||||||
if (mPendingOscUpdates.empty())
|
return true;
|
||||||
return true;
|
|
||||||
pending.swap(mPendingOscUpdates);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& entry : pending)
|
return mControlServices->ApplyPendingOscUpdates(appliedUpdates, error);
|
||||||
{
|
|
||||||
JsonValue targetValue;
|
|
||||||
std::string parseError;
|
|
||||||
if (!ParseJson(entry.second.valueJson, targetValue, parseError))
|
|
||||||
{
|
|
||||||
OutputDebugStringA(("OSC queued value parse failed: " + parseError + "\n").c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppliedOscUpdate appliedUpdate;
|
|
||||||
appliedUpdate.routeKey = entry.first;
|
|
||||||
appliedUpdate.layerKey = entry.second.layerKey;
|
|
||||||
appliedUpdate.parameterKey = entry.second.parameterKey;
|
|
||||||
appliedUpdate.targetValue = targetValue;
|
|
||||||
appliedUpdates.push_back(std::move(appliedUpdate));
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)error;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeServices::QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, std::string& error)
|
bool RuntimeServices::QueueOscCommit(const std::string& routeKey, const std::string& layerKey, const std::string& parameterKey, const JsonValue& value, uint64_t generation, std::string& error)
|
||||||
{
|
{
|
||||||
(void)error;
|
return mControlServices && mControlServices->QueueOscCommit(routeKey, layerKey, parameterKey, value, generation, error);
|
||||||
|
|
||||||
PendingOscCommit commit;
|
|
||||||
commit.routeKey = routeKey;
|
|
||||||
commit.layerKey = layerKey;
|
|
||||||
commit.parameterKey = parameterKey;
|
|
||||||
commit.value = value;
|
|
||||||
commit.generation = generation;
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mPendingOscCommitMutex);
|
|
||||||
mPendingOscCommits[routeKey] = std::move(commit);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeServices::ClearOscState()
|
void RuntimeServices::ClearOscState()
|
||||||
{
|
{
|
||||||
{
|
if (mControlServices)
|
||||||
std::lock_guard<std::mutex> lock(mPendingOscMutex);
|
mControlServices->ClearOscState();
|
||||||
mPendingOscUpdates.clear();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mPendingOscCommitMutex);
|
|
||||||
mPendingOscCommits.clear();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mCompletedOscCommitMutex);
|
|
||||||
mCompletedOscCommits.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeServices::ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>& completedCommits)
|
void RuntimeServices::ConsumeCompletedOscCommits(std::vector<CompletedOscCommit>& completedCommits)
|
||||||
{
|
{
|
||||||
completedCommits.clear();
|
if (!mControlServices)
|
||||||
|
{
|
||||||
std::lock_guard<std::mutex> lock(mCompletedOscCommitMutex);
|
completedCommits.clear();
|
||||||
if (mCompletedOscCommits.empty())
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
completedCommits.swap(mCompletedOscCommits);
|
mControlServices->ConsumeCompletedOscCommits(completedCommits);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimePollEvents RuntimeServices::ConsumePollEvents()
|
RuntimePollEvents RuntimeServices::ConsumePollEvents()
|
||||||
{
|
{
|
||||||
RuntimePollEvents events;
|
return mControlServices ? mControlServices->ConsumePollEvents() : RuntimePollEvents{};
|
||||||
events.registryChanged = mRegistryChanged.exchange(false);
|
|
||||||
events.reloadRequested = mReloadRequested.exchange(false);
|
|
||||||
events.failed = mPollFailed.exchange(false);
|
|
||||||
|
|
||||||
if (events.failed)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mPollErrorMutex);
|
|
||||||
events.error = mPollError;
|
|
||||||
}
|
|
||||||
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeServices::StartPolling(RuntimeHost& runtimeHost)
|
|
||||||
{
|
|
||||||
if (mPollRunning.exchange(true))
|
|
||||||
return;
|
|
||||||
|
|
||||||
mPollThread = std::thread([this, &runtimeHost]() { PollLoop(runtimeHost); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeServices::StopPolling()
|
|
||||||
{
|
|
||||||
if (!mPollRunning.exchange(false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mPollThread.joinable())
|
|
||||||
mPollThread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeServices::PollLoop(RuntimeHost& runtimeHost)
|
|
||||||
{
|
|
||||||
while (mPollRunning)
|
|
||||||
{
|
|
||||||
std::map<std::string, PendingOscCommit> pendingCommits;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mPendingOscCommitMutex);
|
|
||||||
pendingCommits.swap(mPendingOscCommits);
|
|
||||||
}
|
|
||||||
for (const auto& entry : pendingCommits)
|
|
||||||
{
|
|
||||||
std::string commitError;
|
|
||||||
if (runtimeHost.UpdateLayerParameterByControlKey(
|
|
||||||
entry.second.layerKey,
|
|
||||||
entry.second.parameterKey,
|
|
||||||
entry.second.value,
|
|
||||||
false,
|
|
||||||
commitError))
|
|
||||||
{
|
|
||||||
CompletedOscCommit completedCommit;
|
|
||||||
completedCommit.routeKey = entry.second.routeKey;
|
|
||||||
completedCommit.generation = entry.second.generation;
|
|
||||||
std::lock_guard<std::mutex> lock(mCompletedOscCommitMutex);
|
|
||||||
mCompletedOscCommits.push_back(std::move(completedCommit));
|
|
||||||
}
|
|
||||||
else if (!commitError.empty())
|
|
||||||
{
|
|
||||||
OutputDebugStringA(("OSC commit failed: " + commitError + "\n").c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool registryChanged = false;
|
|
||||||
bool reloadRequested = false;
|
|
||||||
std::string runtimeError;
|
|
||||||
if (!runtimeHost.PollFileChanges(registryChanged, reloadRequested, runtimeError))
|
|
||||||
{
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mPollErrorMutex);
|
|
||||||
mPollError = runtimeError;
|
|
||||||
}
|
|
||||||
mPollFailed = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (registryChanged)
|
|
||||||
mRegistryChanged = true;
|
|
||||||
if (reloadRequested)
|
|
||||||
mReloadRequested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 25 && mPollRunning; ++i)
|
|
||||||
Sleep(10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "RuntimeJson.h"
|
#include "ControlServices.h"
|
||||||
#include "ShaderTypes.h"
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
class ControlServer;
|
|
||||||
class OpenGLComposite;
|
class OpenGLComposite;
|
||||||
class OscServer;
|
|
||||||
class RuntimeHost;
|
class RuntimeHost;
|
||||||
|
|
||||||
struct RuntimePollEvents
|
|
||||||
{
|
|
||||||
bool registryChanged = false;
|
|
||||||
bool reloadRequested = false;
|
|
||||||
bool failed = false;
|
|
||||||
std::string error;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RuntimeServices
|
class RuntimeServices
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct AppliedOscUpdate
|
using AppliedOscUpdate = ControlServices::AppliedOscUpdate;
|
||||||
{
|
using CompletedOscCommit = ControlServices::CompletedOscCommit;
|
||||||
std::string routeKey;
|
|
||||||
std::string layerKey;
|
|
||||||
std::string parameterKey;
|
|
||||||
JsonValue targetValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CompletedOscCommit
|
|
||||||
{
|
|
||||||
std::string routeKey;
|
|
||||||
uint64_t generation = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
RuntimeServices();
|
RuntimeServices();
|
||||||
~RuntimeServices();
|
~RuntimeServices();
|
||||||
@@ -56,39 +29,5 @@ public:
|
|||||||
RuntimePollEvents ConsumePollEvents();
|
RuntimePollEvents ConsumePollEvents();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct PendingOscUpdate
|
std::unique_ptr<ControlServices> mControlServices;
|
||||||
{
|
|
||||||
std::string layerKey;
|
|
||||||
std::string parameterKey;
|
|
||||||
std::string valueJson;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PendingOscCommit
|
|
||||||
{
|
|
||||||
std::string routeKey;
|
|
||||||
std::string layerKey;
|
|
||||||
std::string parameterKey;
|
|
||||||
JsonValue value;
|
|
||||||
uint64_t generation = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
void StartPolling(RuntimeHost& runtimeHost);
|
|
||||||
void StopPolling();
|
|
||||||
void PollLoop(RuntimeHost& runtimeHost);
|
|
||||||
|
|
||||||
std::unique_ptr<ControlServer> mControlServer;
|
|
||||||
std::unique_ptr<OscServer> mOscServer;
|
|
||||||
std::thread mPollThread;
|
|
||||||
std::atomic<bool> mPollRunning;
|
|
||||||
std::atomic<bool> mRegistryChanged;
|
|
||||||
std::atomic<bool> mReloadRequested;
|
|
||||||
std::atomic<bool> mPollFailed;
|
|
||||||
std::mutex mPollErrorMutex;
|
|
||||||
std::string mPollError;
|
|
||||||
std::mutex mPendingOscMutex;
|
|
||||||
std::map<std::string, PendingOscUpdate> mPendingOscUpdates;
|
|
||||||
std::mutex mPendingOscCommitMutex;
|
|
||||||
std::map<std::string, PendingOscCommit> mPendingOscCommits;
|
|
||||||
std::mutex mCompletedOscCommitMutex;
|
|
||||||
std::vector<CompletedOscCommit> mCompletedOscCommits;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
#include "DeckLinkDisplayMode.h"
|
#include "DeckLinkDisplayMode.h"
|
||||||
#include "DeckLinkSession.h"
|
|
||||||
#include "OpenGLComposite.h"
|
#include "OpenGLComposite.h"
|
||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
#include "GlRenderConstants.h"
|
#include "GlRenderConstants.h"
|
||||||
#include "OpenGLRenderPass.h"
|
|
||||||
#include "OpenGLRenderPipeline.h"
|
|
||||||
#include "OpenGLShaderPrograms.h"
|
|
||||||
#include "OpenGLVideoIOBridge.h"
|
|
||||||
#include "PngScreenshotWriter.h"
|
#include "PngScreenshotWriter.h"
|
||||||
|
#include "RenderEngine.h"
|
||||||
#include "RuntimeParameterUtils.h"
|
#include "RuntimeParameterUtils.h"
|
||||||
#include "RuntimeServices.h"
|
#include "RuntimeServices.h"
|
||||||
#include "ShaderBuildQueue.h"
|
#include "ShaderBuildQueue.h"
|
||||||
|
#include "VideoBackend.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@@ -97,30 +94,24 @@ JsonValue BuildOscCommitValue(const ShaderParameterDefinition& definition, const
|
|||||||
|
|
||||||
OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
OpenGLComposite::OpenGLComposite(HWND hWnd, HDC hDC, HGLRC hRC) :
|
||||||
hGLWnd(hWnd), hGLDC(hDC), hGLRC(hRC),
|
hGLWnd(hWnd), hGLDC(hDC), hGLRC(hRC),
|
||||||
mVideoIO(std::make_unique<DeckLinkSession>()),
|
|
||||||
mRenderer(std::make_unique<OpenGLRenderer>()),
|
|
||||||
mUseCommittedLayerStates(false),
|
mUseCommittedLayerStates(false),
|
||||||
mScreenshotRequested(false)
|
mScreenshotRequested(false)
|
||||||
{
|
{
|
||||||
InitializeCriticalSection(&pMutex);
|
InitializeCriticalSection(&pMutex);
|
||||||
mRuntimeHost = std::make_unique<RuntimeHost>();
|
mRuntimeHost = std::make_unique<RuntimeHost>();
|
||||||
mRenderPipeline = std::make_unique<OpenGLRenderPipeline>(
|
mRuntimeStore = std::make_unique<RuntimeStore>(*mRuntimeHost);
|
||||||
*mRenderer,
|
mRuntimeSnapshotProvider = std::make_unique<RuntimeSnapshotProvider>(*mRuntimeHost);
|
||||||
|
mRenderEngine = std::make_unique<RenderEngine>(
|
||||||
*mRuntimeHost,
|
*mRuntimeHost,
|
||||||
|
*mRuntimeSnapshotProvider,
|
||||||
|
pMutex,
|
||||||
|
hGLDC,
|
||||||
|
hGLRC,
|
||||||
[this]() { renderEffect(); },
|
[this]() { renderEffect(); },
|
||||||
[this]() { ProcessScreenshotRequest(); },
|
[this]() { ProcessScreenshotRequest(); },
|
||||||
[this]() { paintGL(false); });
|
[this]() { paintGL(false); });
|
||||||
mVideoIOBridge = std::make_unique<OpenGLVideoIOBridge>(
|
mVideoBackend = std::make_unique<VideoBackend>(*mRenderEngine, mRuntimeHost->GetHealthTelemetry());
|
||||||
*mVideoIO,
|
mShaderBuildQueue = std::make_unique<ShaderBuildQueue>(*mRuntimeSnapshotProvider);
|
||||||
*mRenderer,
|
|
||||||
*mRenderPipeline,
|
|
||||||
*mRuntimeHost,
|
|
||||||
pMutex,
|
|
||||||
hGLDC,
|
|
||||||
hGLRC);
|
|
||||||
mRenderPass = std::make_unique<OpenGLRenderPass>(*mRenderer);
|
|
||||||
mShaderPrograms = std::make_unique<OpenGLShaderPrograms>(*mRenderer, *mRuntimeHost);
|
|
||||||
mShaderBuildQueue = std::make_unique<ShaderBuildQueue>(*mRuntimeHost);
|
|
||||||
mRuntimeServices = std::make_unique<RuntimeServices>();
|
mRuntimeServices = std::make_unique<RuntimeServices>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,8 +121,8 @@ OpenGLComposite::~OpenGLComposite()
|
|||||||
mRuntimeServices->Stop();
|
mRuntimeServices->Stop();
|
||||||
if (mShaderBuildQueue)
|
if (mShaderBuildQueue)
|
||||||
mShaderBuildQueue->Stop();
|
mShaderBuildQueue->Stop();
|
||||||
mVideoIO->ReleaseResources();
|
if (mVideoBackend)
|
||||||
mRenderer->DestroyResources();
|
mVideoBackend->ReleaseResources();
|
||||||
|
|
||||||
DeleteCriticalSection(&pMutex);
|
DeleteCriticalSection(&pMutex);
|
||||||
}
|
}
|
||||||
@@ -146,23 +137,23 @@ bool OpenGLComposite::InitVideoIO()
|
|||||||
VideoFormatSelection videoModes;
|
VideoFormatSelection videoModes;
|
||||||
std::string initFailureReason;
|
std::string initFailureReason;
|
||||||
|
|
||||||
if (mRuntimeHost && mRuntimeHost->GetRepoRoot().empty())
|
if (mRuntimeStore && mRuntimeStore->GetRuntimeRepositoryRoot().empty())
|
||||||
{
|
{
|
||||||
std::string runtimeError;
|
std::string runtimeError;
|
||||||
if (!mRuntimeHost->Initialize(runtimeError))
|
if (!mRuntimeStore->InitializeStore(runtimeError))
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL, runtimeError.c_str(), "Runtime host failed to initialize", MB_OK);
|
MessageBoxA(NULL, runtimeError.c_str(), "Runtime host failed to initialize", MB_OK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mRuntimeHost)
|
if (mRuntimeStore)
|
||||||
{
|
{
|
||||||
if (!ResolveConfiguredVideoFormats(
|
if (!ResolveConfiguredVideoFormats(
|
||||||
mRuntimeHost->GetInputVideoFormat(),
|
mRuntimeStore->GetConfiguredInputVideoFormat(),
|
||||||
mRuntimeHost->GetInputFrameRate(),
|
mRuntimeStore->GetConfiguredInputFrameRate(),
|
||||||
mRuntimeHost->GetOutputVideoFormat(),
|
mRuntimeStore->GetConfiguredOutputVideoFormat(),
|
||||||
mRuntimeHost->GetOutputFrameRate(),
|
mRuntimeStore->GetConfiguredOutputFrameRate(),
|
||||||
videoModes,
|
videoModes,
|
||||||
initFailureReason))
|
initFailureReason))
|
||||||
{
|
{
|
||||||
@@ -171,7 +162,7 @@ bool OpenGLComposite::InitVideoIO()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mVideoIO->DiscoverDevicesAndModes(videoModes, initFailureReason))
|
if (!mVideoBackend->DiscoverDevicesAndModes(videoModes, initFailureReason))
|
||||||
{
|
{
|
||||||
const char* title = initFailureReason == "Please install the Blackmagic DeckLink drivers to use the features of this application."
|
const char* title = initFailureReason == "Please install the Blackmagic DeckLink drivers to use the features of this application."
|
||||||
? "This application requires the DeckLink drivers installed."
|
? "This application requires the DeckLink drivers installed."
|
||||||
@@ -179,8 +170,8 @@ bool OpenGLComposite::InitVideoIO()
|
|||||||
MessageBoxA(NULL, initFailureReason.c_str(), title, MB_OK | MB_ICONERROR);
|
MessageBoxA(NULL, initFailureReason.c_str(), title, MB_OK | MB_ICONERROR);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const bool outputAlphaRequired = mRuntimeHost && mRuntimeHost->ExternalKeyingEnabled();
|
const bool outputAlphaRequired = mRuntimeStore && mRuntimeStore->IsExternalKeyingConfigured();
|
||||||
if (!mVideoIO->SelectPreferredFormats(videoModes, outputAlphaRequired, initFailureReason))
|
if (!mVideoBackend->SelectPreferredFormats(videoModes, outputAlphaRequired, initFailureReason))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (! CheckOpenGLExtensions())
|
if (! CheckOpenGLExtensions())
|
||||||
@@ -195,38 +186,38 @@ bool OpenGLComposite::InitVideoIO()
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
PublishVideoIOStatus(mVideoIO->OutputModelName().empty()
|
PublishVideoIOStatus(mVideoBackend->OutputModelName().empty()
|
||||||
? "DeckLink output device selected."
|
? "DeckLink output device selected."
|
||||||
: ("Selected output device: " + mVideoIO->OutputModelName()));
|
: ("Selected output device: " + mVideoBackend->OutputModelName()));
|
||||||
|
|
||||||
// Resize window to match output video frame, but scale large formats down by half for viewing.
|
// Resize window to match output video frame, but scale large formats down by half for viewing.
|
||||||
if (mVideoIO->OutputFrameWidth() < 1920)
|
if (mVideoBackend->OutputFrameWidth() < 1920)
|
||||||
resizeWindow(mVideoIO->OutputFrameWidth(), mVideoIO->OutputFrameHeight());
|
resizeWindow(mVideoBackend->OutputFrameWidth(), mVideoBackend->OutputFrameHeight());
|
||||||
else
|
else
|
||||||
resizeWindow(mVideoIO->OutputFrameWidth() / 2, mVideoIO->OutputFrameHeight() / 2);
|
resizeWindow(mVideoBackend->OutputFrameWidth() / 2, mVideoBackend->OutputFrameHeight() / 2);
|
||||||
|
|
||||||
if (!mVideoIO->ConfigureInput([this](const VideoIOFrame& frame) { mVideoIOBridge->VideoFrameArrived(frame); }, videoModes.input, initFailureReason))
|
if (!mVideoBackend->ConfigureInput(videoModes.input, initFailureReason))
|
||||||
{
|
{
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (!mVideoIO->HasInputDevice() && mRuntimeHost)
|
if (!mVideoBackend->HasInputDevice() && mRuntimeHost)
|
||||||
{
|
{
|
||||||
mRuntimeHost->SetSignalStatus(false, mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight(), mVideoIO->InputDisplayModeName());
|
mRuntimeHost->SetSignalStatus(false, mVideoBackend->InputFrameWidth(), mVideoBackend->InputFrameHeight(), mVideoBackend->InputDisplayModeName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mVideoIO->ConfigureOutput([this](const VideoIOCompletion& completion) { mVideoIOBridge->PlayoutFrameCompleted(completion); }, videoModes.output, mRuntimeHost && mRuntimeHost->ExternalKeyingEnabled(), initFailureReason))
|
if (!mVideoBackend->ConfigureOutput(videoModes.output, mRuntimeStore && mRuntimeStore->IsExternalKeyingConfigured(), initFailureReason))
|
||||||
{
|
{
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
PublishVideoIOStatus(mVideoIO->StatusMessage());
|
PublishVideoIOStatus(mVideoBackend->StatusMessage());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (!initFailureReason.empty())
|
if (!initFailureReason.empty())
|
||||||
MessageBoxA(NULL, initFailureReason.c_str(), "DeckLink initialization failed", MB_OK | MB_ICONERROR);
|
MessageBoxA(NULL, initFailureReason.c_str(), "DeckLink initialization failed", MB_OK | MB_ICONERROR);
|
||||||
mVideoIO->ReleaseResources();
|
mVideoBackend->ReleaseResources();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +228,7 @@ void OpenGLComposite::paintGL(bool force)
|
|||||||
if (IsIconic(hGLWnd))
|
if (IsIconic(hGLWnd))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const unsigned previewFps = mRuntimeHost ? mRuntimeHost->GetPreviewFps() : 30u;
|
const unsigned previewFps = mRuntimeStore ? mRuntimeStore->GetConfiguredPreviewFps() : 30u;
|
||||||
if (previewFps == 0)
|
if (previewFps == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -250,23 +241,21 @@ void OpenGLComposite::paintGL(bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryEnterCriticalSection(&pMutex))
|
if (!mRenderEngine->TryPresentToWindow(mVideoBackend->OutputFrameWidth(), mVideoBackend->OutputFrameHeight()))
|
||||||
{
|
{
|
||||||
ValidateRect(hGLWnd, NULL);
|
ValidateRect(hGLWnd, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mRenderer->PresentToWindow(hGLDC, mVideoIO->OutputFrameWidth(), mVideoIO->OutputFrameHeight());
|
|
||||||
mLastPreviewPresentTime = std::chrono::steady_clock::now();
|
mLastPreviewPresentTime = std::chrono::steady_clock::now();
|
||||||
ValidateRect(hGLWnd, NULL);
|
ValidateRect(hGLWnd, NULL);
|
||||||
LeaveCriticalSection(&pMutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLComposite::resizeGL(WORD width, WORD height)
|
void OpenGLComposite::resizeGL(WORD width, WORD height)
|
||||||
{
|
{
|
||||||
// We don't set the project or model matrices here since the window data is copied directly from
|
// We don't set the project or model matrices here since the window data is copied directly from
|
||||||
// an off-screen FBO in paintGL(). Just save the width and height for use in paintGL().
|
// an off-screen FBO in paintGL(). Just save the width and height for use in paintGL().
|
||||||
mRenderer->ResizeView(width, height);
|
mRenderEngine->ResizeView(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLComposite::resizeWindow(int width, int height)
|
void OpenGLComposite::resizeWindow(int width, int height)
|
||||||
@@ -284,17 +273,17 @@ void OpenGLComposite::PublishVideoIOStatus(const std::string& statusMessage)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!statusMessage.empty())
|
if (!statusMessage.empty())
|
||||||
mVideoIO->SetStatusMessage(statusMessage);
|
mVideoBackend->SetStatusMessage(statusMessage);
|
||||||
|
|
||||||
mRuntimeHost->SetVideoIOStatus(
|
mRuntimeHost->SetVideoIOStatus(
|
||||||
"decklink",
|
"decklink",
|
||||||
mVideoIO->OutputModelName(),
|
mVideoBackend->OutputModelName(),
|
||||||
mVideoIO->SupportsInternalKeying(),
|
mVideoBackend->SupportsInternalKeying(),
|
||||||
mVideoIO->SupportsExternalKeying(),
|
mVideoBackend->SupportsExternalKeying(),
|
||||||
mVideoIO->KeyerInterfaceAvailable(),
|
mVideoBackend->KeyerInterfaceAvailable(),
|
||||||
mRuntimeHost->ExternalKeyingEnabled(),
|
mRuntimeStore ? mRuntimeStore->IsExternalKeyingConfigured() : false,
|
||||||
mVideoIO->ExternalKeyingActive(),
|
mVideoBackend->ExternalKeyingActive(),
|
||||||
mVideoIO->StatusMessage());
|
mVideoBackend->StatusMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLComposite::InitOpenGLState()
|
bool OpenGLComposite::InitOpenGLState()
|
||||||
@@ -303,7 +292,7 @@ bool OpenGLComposite::InitOpenGLState()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::string runtimeError;
|
std::string runtimeError;
|
||||||
if (mRuntimeHost->GetRepoRoot().empty() && !mRuntimeHost->Initialize(runtimeError))
|
if (mRuntimeStore->GetRuntimeRepositoryRoot().empty() && !mRuntimeStore->InitializeStore(runtimeError))
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL, runtimeError.c_str(), "Runtime host failed to initialize", MB_OK);
|
MessageBoxA(NULL, runtimeError.c_str(), "Runtime host failed to initialize", MB_OK);
|
||||||
return false;
|
return false;
|
||||||
@@ -317,41 +306,41 @@ bool OpenGLComposite::InitOpenGLState()
|
|||||||
|
|
||||||
// Prepare the runtime shader program generated from the active shader package.
|
// Prepare the runtime shader program generated from the active shader package.
|
||||||
char compilerErrorMessage[1024];
|
char compilerErrorMessage[1024];
|
||||||
if (!mShaderPrograms->CompileDecodeShader(sizeof(compilerErrorMessage), compilerErrorMessage))
|
if (!mRenderEngine->CompileDecodeShader(sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL, compilerErrorMessage, "OpenGL decode shader failed to load or compile", MB_OK);
|
MessageBoxA(NULL, compilerErrorMessage, "OpenGL decode shader failed to load or compile", MB_OK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!mShaderPrograms->CompileOutputPackShader(sizeof(compilerErrorMessage), compilerErrorMessage))
|
if (!mRenderEngine->CompileOutputPackShader(sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL, compilerErrorMessage, "OpenGL output pack shader failed to load or compile", MB_OK);
|
MessageBoxA(NULL, compilerErrorMessage, "OpenGL output pack shader failed to load or compile", MB_OK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rendererError;
|
std::string rendererError;
|
||||||
if (!mRenderer->InitializeResources(
|
if (!mRenderEngine->InitializeResources(
|
||||||
mVideoIO->InputFrameWidth(),
|
mVideoBackend->InputFrameWidth(),
|
||||||
mVideoIO->InputFrameHeight(),
|
mVideoBackend->InputFrameHeight(),
|
||||||
mVideoIO->CaptureTextureWidth(),
|
mVideoBackend->CaptureTextureWidth(),
|
||||||
mVideoIO->OutputFrameWidth(),
|
mVideoBackend->OutputFrameWidth(),
|
||||||
mVideoIO->OutputFrameHeight(),
|
mVideoBackend->OutputFrameHeight(),
|
||||||
mVideoIO->OutputPackTextureWidth(),
|
mVideoBackend->OutputPackTextureWidth(),
|
||||||
rendererError))
|
rendererError))
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL, rendererError.c_str(), "OpenGL initialization error.", MB_OK);
|
MessageBoxA(NULL, rendererError.c_str(), "OpenGL initialization error.", MB_OK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mShaderPrograms->CompileLayerPrograms(mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight(), sizeof(compilerErrorMessage), compilerErrorMessage))
|
if (!mRenderEngine->CompileLayerPrograms(mVideoBackend->InputFrameWidth(), mVideoBackend->InputFrameHeight(), sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||||
{
|
{
|
||||||
MessageBoxA(NULL, compilerErrorMessage, "OpenGL shader failed to load or compile", MB_OK);
|
MessageBoxA(NULL, compilerErrorMessage, "OpenGL shader failed to load or compile", MB_OK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mCachedLayerRenderStates = mShaderPrograms->CommittedLayerStates();
|
mCachedLayerRenderStates = mRenderEngine->CommittedLayerStates();
|
||||||
mUseCommittedLayerStates = false;
|
mUseCommittedLayerStates = false;
|
||||||
|
|
||||||
mShaderPrograms->ResetTemporalHistoryState();
|
mRenderEngine->ResetTemporalHistoryState();
|
||||||
mShaderPrograms->ResetShaderFeedbackState();
|
mRenderEngine->ResetShaderFeedbackState();
|
||||||
|
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
mRuntimeServices->BeginPolling(*mRuntimeHost);
|
mRuntimeServices->BeginPolling(*mRuntimeHost);
|
||||||
@@ -360,7 +349,7 @@ bool OpenGLComposite::InitOpenGLState()
|
|||||||
|
|
||||||
bool OpenGLComposite::Start()
|
bool OpenGLComposite::Start()
|
||||||
{
|
{
|
||||||
return mVideoIO->Start();
|
return mVideoBackend->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLComposite::Stop()
|
bool OpenGLComposite::Stop()
|
||||||
@@ -368,8 +357,8 @@ bool OpenGLComposite::Stop()
|
|||||||
if (mRuntimeServices)
|
if (mRuntimeServices)
|
||||||
mRuntimeServices->Stop();
|
mRuntimeServices->Stop();
|
||||||
|
|
||||||
const bool wasExternalKeyingActive = mVideoIO->ExternalKeyingActive();
|
const bool wasExternalKeyingActive = mVideoBackend->ExternalKeyingActive();
|
||||||
mVideoIO->Stop();
|
mVideoBackend->Stop();
|
||||||
if (wasExternalKeyingActive)
|
if (wasExternalKeyingActive)
|
||||||
PublishVideoIOStatus("External keying has been disabled.");
|
PublishVideoIOStatus("External keying has been disabled.");
|
||||||
|
|
||||||
@@ -381,8 +370,8 @@ bool OpenGLComposite::ReloadShader(bool preserveFeedbackState)
|
|||||||
mPreserveFeedbackOnNextShaderBuild = preserveFeedbackState;
|
mPreserveFeedbackOnNextShaderBuild = preserveFeedbackState;
|
||||||
if (mRuntimeHost)
|
if (mRuntimeHost)
|
||||||
{
|
{
|
||||||
mRuntimeHost->SetCompileStatus(true, "Shader rebuild queued.");
|
mRuntimeStore->SetCompileStatus(true, "Shader rebuild queued.");
|
||||||
mRuntimeHost->ClearReloadRequest();
|
mRuntimeStore->ClearReloadRequest();
|
||||||
}
|
}
|
||||||
RequestShaderBuild();
|
RequestShaderBuild();
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
@@ -456,7 +445,7 @@ void OpenGLComposite::renderEffect()
|
|||||||
if (states.empty() || mOscOverlayStates.empty() || !mRuntimeHost)
|
if (states.empty() || mOscOverlayStates.empty() || !mRuntimeHost)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const double smoothing = ClampOscAlpha(mRuntimeHost->GetOscSmoothing());
|
const double smoothing = ClampOscAlpha(mRuntimeStore ? mRuntimeStore->GetConfiguredOscSmoothing() : 0.0);
|
||||||
std::vector<std::string> overlayKeysToRemove;
|
std::vector<std::string> overlayKeysToRemove;
|
||||||
for (auto& item : mOscOverlayStates)
|
for (auto& item : mOscOverlayStates)
|
||||||
{
|
{
|
||||||
@@ -585,48 +574,57 @@ void OpenGLComposite::renderEffect()
|
|||||||
mOscOverlayStates.erase(overlayKey);
|
mOscOverlayStates.erase(overlayKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
const bool hasInputSource = mVideoIO->HasInputSource();
|
const bool hasInputSource = mVideoBackend->HasInputSource();
|
||||||
std::vector<RuntimeRenderState> layerStates;
|
std::vector<RuntimeRenderState> layerStates;
|
||||||
if (mUseCommittedLayerStates)
|
if (mUseCommittedLayerStates)
|
||||||
{
|
{
|
||||||
layerStates = mShaderPrograms->CommittedLayerStates();
|
layerStates = mRenderEngine->CommittedLayerStates();
|
||||||
applyOscOverlays(layerStates, false);
|
applyOscOverlays(layerStates, false);
|
||||||
if (mRuntimeHost)
|
if (mRuntimeSnapshotProvider)
|
||||||
mRuntimeHost->RefreshDynamicRenderStateFields(layerStates);
|
mRuntimeSnapshotProvider->RefreshDynamicRenderStateFields(layerStates);
|
||||||
}
|
}
|
||||||
else if (mRuntimeHost)
|
else if (mRuntimeSnapshotProvider)
|
||||||
{
|
{
|
||||||
const unsigned renderWidth = mVideoIO->InputFrameWidth();
|
const unsigned renderWidth = mVideoBackend->InputFrameWidth();
|
||||||
const unsigned renderHeight = mVideoIO->InputFrameHeight();
|
const unsigned renderHeight = mVideoBackend->InputFrameHeight();
|
||||||
const uint64_t renderStateVersion = mRuntimeHost->GetRenderStateVersion();
|
const RuntimeSnapshotVersions versions = mRuntimeSnapshotProvider->GetVersions();
|
||||||
const uint64_t parameterStateVersion = mRuntimeHost->GetParameterStateVersion();
|
|
||||||
const bool renderStateCacheValid =
|
const bool renderStateCacheValid =
|
||||||
!mCachedLayerRenderStates.empty() &&
|
!mCachedLayerRenderStates.empty() &&
|
||||||
mCachedRenderStateVersion == renderStateVersion &&
|
mCachedRenderStateVersion == versions.renderStateVersion &&
|
||||||
mCachedRenderStateWidth == renderWidth &&
|
mCachedRenderStateWidth == renderWidth &&
|
||||||
mCachedRenderStateHeight == renderHeight;
|
mCachedRenderStateHeight == renderHeight;
|
||||||
|
|
||||||
if (renderStateCacheValid)
|
if (renderStateCacheValid)
|
||||||
{
|
{
|
||||||
applyOscOverlays(mCachedLayerRenderStates, true);
|
RuntimeRenderStateSnapshot renderSnapshot;
|
||||||
if (mCachedParameterStateVersion != parameterStateVersion &&
|
renderSnapshot.outputWidth = renderWidth;
|
||||||
mRuntimeHost->TryRefreshCachedLayerStates(mCachedLayerRenderStates))
|
renderSnapshot.outputHeight = renderHeight;
|
||||||
|
renderSnapshot.versions.renderStateVersion = mCachedRenderStateVersion;
|
||||||
|
renderSnapshot.versions.parameterStateVersion = mCachedParameterStateVersion;
|
||||||
|
renderSnapshot.states = mCachedLayerRenderStates;
|
||||||
|
|
||||||
|
applyOscOverlays(renderSnapshot.states, true);
|
||||||
|
if (mCachedParameterStateVersion != versions.parameterStateVersion &&
|
||||||
|
mRuntimeSnapshotProvider->TryRefreshSnapshotParameters(renderSnapshot))
|
||||||
{
|
{
|
||||||
mCachedParameterStateVersion = parameterStateVersion;
|
mCachedParameterStateVersion = renderSnapshot.versions.parameterStateVersion;
|
||||||
applyOscOverlays(mCachedLayerRenderStates, true);
|
applyOscOverlays(renderSnapshot.states, true);
|
||||||
}
|
}
|
||||||
layerStates = mCachedLayerRenderStates;
|
|
||||||
mRuntimeHost->RefreshDynamicRenderStateFields(layerStates);
|
mCachedLayerRenderStates = renderSnapshot.states;
|
||||||
|
layerStates = renderSnapshot.states;
|
||||||
|
mRuntimeSnapshotProvider->RefreshDynamicRenderStateFields(layerStates);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mRuntimeHost->TryGetLayerRenderStates(renderWidth, renderHeight, layerStates))
|
RuntimeRenderStateSnapshot renderSnapshot;
|
||||||
|
if (mRuntimeSnapshotProvider->TryGetRenderStateSnapshot(renderWidth, renderHeight, renderSnapshot))
|
||||||
{
|
{
|
||||||
mCachedLayerRenderStates = layerStates;
|
mCachedLayerRenderStates = renderSnapshot.states;
|
||||||
mCachedRenderStateVersion = renderStateVersion;
|
mCachedRenderStateVersion = renderSnapshot.versions.renderStateVersion;
|
||||||
mCachedParameterStateVersion = parameterStateVersion;
|
mCachedParameterStateVersion = renderSnapshot.versions.parameterStateVersion;
|
||||||
mCachedRenderStateWidth = renderWidth;
|
mCachedRenderStateWidth = renderSnapshot.outputWidth;
|
||||||
mCachedRenderStateHeight = renderHeight;
|
mCachedRenderStateHeight = renderSnapshot.outputHeight;
|
||||||
applyOscOverlays(mCachedLayerRenderStates, true);
|
applyOscOverlays(mCachedLayerRenderStates, true);
|
||||||
layerStates = mCachedLayerRenderStates;
|
layerStates = mCachedLayerRenderStates;
|
||||||
}
|
}
|
||||||
@@ -634,25 +632,19 @@ void OpenGLComposite::renderEffect()
|
|||||||
{
|
{
|
||||||
applyOscOverlays(mCachedLayerRenderStates, true);
|
applyOscOverlays(mCachedLayerRenderStates, true);
|
||||||
layerStates = mCachedLayerRenderStates;
|
layerStates = mCachedLayerRenderStates;
|
||||||
mRuntimeHost->RefreshDynamicRenderStateFields(layerStates);
|
mRuntimeSnapshotProvider->RefreshDynamicRenderStateFields(layerStates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const unsigned historyCap = mRuntimeHost ? mRuntimeHost->GetMaxTemporalHistoryFrames() : 0;
|
const unsigned historyCap = mRuntimeStore ? mRuntimeStore->GetConfiguredMaxTemporalHistoryFrames() : 0;
|
||||||
mRenderPass->Render(
|
mRenderEngine->RenderLayerStack(
|
||||||
hasInputSource,
|
hasInputSource,
|
||||||
layerStates,
|
layerStates,
|
||||||
mVideoIO->InputFrameWidth(),
|
mVideoBackend->InputFrameWidth(),
|
||||||
mVideoIO->InputFrameHeight(),
|
mVideoBackend->InputFrameHeight(),
|
||||||
mVideoIO->CaptureTextureWidth(),
|
mVideoBackend->CaptureTextureWidth(),
|
||||||
mVideoIO->InputPixelFormat(),
|
mVideoBackend->InputPixelFormat(),
|
||||||
historyCap,
|
historyCap);
|
||||||
[this](const RuntimeRenderState& state, 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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLComposite::ProcessScreenshotRequest()
|
void OpenGLComposite::ProcessScreenshotRequest()
|
||||||
@@ -660,21 +652,16 @@ void OpenGLComposite::ProcessScreenshotRequest()
|
|||||||
if (!mScreenshotRequested.exchange(false))
|
if (!mScreenshotRequested.exchange(false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const unsigned width = mVideoIO ? mVideoIO->OutputFrameWidth() : 0;
|
const unsigned width = mVideoBackend ? mVideoBackend->OutputFrameWidth() : 0;
|
||||||
const unsigned height = mVideoIO ? mVideoIO->OutputFrameHeight() : 0;
|
const unsigned height = mVideoBackend ? mVideoBackend->OutputFrameHeight() : 0;
|
||||||
if (width == 0 || height == 0)
|
if (width == 0 || height == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<unsigned char> bottomUpPixels(static_cast<std::size_t>(width) * height * 4);
|
std::vector<unsigned char> bottomUpPixels;
|
||||||
|
if (!mRenderEngine->ReadOutputFrameRgba(width, height, bottomUpPixels))
|
||||||
|
return;
|
||||||
std::vector<unsigned char> topDownPixels(bottomUpPixels.size());
|
std::vector<unsigned char> topDownPixels(bottomUpPixels.size());
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
const std::size_t rowBytes = static_cast<std::size_t>(width) * 4;
|
const std::size_t rowBytes = static_cast<std::size_t>(width) * 4;
|
||||||
for (unsigned y = 0; y < height; ++y)
|
for (unsigned y = 0; y < height; ++y)
|
||||||
{
|
{
|
||||||
@@ -699,8 +686,8 @@ void OpenGLComposite::ProcessScreenshotRequest()
|
|||||||
|
|
||||||
std::filesystem::path OpenGLComposite::BuildScreenshotPath() const
|
std::filesystem::path OpenGLComposite::BuildScreenshotPath() const
|
||||||
{
|
{
|
||||||
const std::filesystem::path root = mRuntimeHost && !mRuntimeHost->GetRuntimeRoot().empty()
|
const std::filesystem::path root = mRuntimeStore && !mRuntimeStore->GetRuntimeDataRoot().empty()
|
||||||
? mRuntimeHost->GetRuntimeRoot()
|
? mRuntimeStore->GetRuntimeDataRoot()
|
||||||
: std::filesystem::current_path();
|
: std::filesystem::current_path();
|
||||||
|
|
||||||
const auto now = std::chrono::system_clock::now();
|
const auto now = std::chrono::system_clock::now();
|
||||||
@@ -726,7 +713,7 @@ bool OpenGLComposite::ProcessRuntimePollResults()
|
|||||||
const RuntimePollEvents events = mRuntimeServices->ConsumePollEvents();
|
const RuntimePollEvents events = mRuntimeServices->ConsumePollEvents();
|
||||||
if (events.failed)
|
if (events.failed)
|
||||||
{
|
{
|
||||||
mRuntimeHost->SetCompileStatus(false, events.error);
|
mRuntimeStore->SetCompileStatus(false, events.error);
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -741,9 +728,9 @@ bool OpenGLComposite::ProcessRuntimePollResults()
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
char compilerErrorMessage[1024] = {};
|
char compilerErrorMessage[1024] = {};
|
||||||
if (!mShaderPrograms->CommitPreparedLayerPrograms(readyBuild, mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight(), sizeof(compilerErrorMessage), compilerErrorMessage))
|
if (!mRenderEngine->CommitPreparedLayerPrograms(readyBuild, mVideoBackend->InputFrameWidth(), mVideoBackend->InputFrameHeight(), sizeof(compilerErrorMessage), compilerErrorMessage))
|
||||||
{
|
{
|
||||||
mRuntimeHost->SetCompileStatus(false, compilerErrorMessage);
|
mRuntimeStore->SetCompileStatus(false, compilerErrorMessage);
|
||||||
mUseCommittedLayerStates = true;
|
mUseCommittedLayerStates = true;
|
||||||
mPreserveFeedbackOnNextShaderBuild = false;
|
mPreserveFeedbackOnNextShaderBuild = false;
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
@@ -751,16 +738,16 @@ bool OpenGLComposite::ProcessRuntimePollResults()
|
|||||||
}
|
}
|
||||||
|
|
||||||
mUseCommittedLayerStates = false;
|
mUseCommittedLayerStates = false;
|
||||||
mCachedLayerRenderStates = mShaderPrograms->CommittedLayerStates();
|
mCachedLayerRenderStates = mRenderEngine->CommittedLayerStates();
|
||||||
mShaderPrograms->ResetTemporalHistoryState();
|
mRenderEngine->ResetTemporalHistoryState();
|
||||||
if (!mPreserveFeedbackOnNextShaderBuild)
|
if (!mPreserveFeedbackOnNextShaderBuild)
|
||||||
mShaderPrograms->ResetShaderFeedbackState();
|
mRenderEngine->ResetShaderFeedbackState();
|
||||||
mPreserveFeedbackOnNextShaderBuild = false;
|
mPreserveFeedbackOnNextShaderBuild = false;
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mRuntimeHost->SetCompileStatus(true, "Shader rebuild queued.");
|
mRuntimeStore->SetCompileStatus(true, "Shader rebuild queued.");
|
||||||
mPreserveFeedbackOnNextShaderBuild = false;
|
mPreserveFeedbackOnNextShaderBuild = false;
|
||||||
RequestShaderBuild();
|
RequestShaderBuild();
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
@@ -769,13 +756,13 @@ bool OpenGLComposite::ProcessRuntimePollResults()
|
|||||||
|
|
||||||
void OpenGLComposite::RequestShaderBuild()
|
void OpenGLComposite::RequestShaderBuild()
|
||||||
{
|
{
|
||||||
if (!mShaderBuildQueue || !mVideoIO)
|
if (!mShaderBuildQueue || !mVideoBackend)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mUseCommittedLayerStates = true;
|
mUseCommittedLayerStates = true;
|
||||||
if (mRuntimeHost)
|
if (mRuntimeHost)
|
||||||
mRuntimeHost->ClearReloadRequest();
|
mRuntimeStore->ClearReloadRequest();
|
||||||
mShaderBuildQueue->RequestBuild(mVideoIO->InputFrameWidth(), mVideoIO->InputFrameHeight());
|
mShaderBuildQueue->RequestBuild(mVideoBackend->InputFrameWidth(), mVideoBackend->InputFrameHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLComposite::broadcastRuntimeState()
|
void OpenGLComposite::broadcastRuntimeState()
|
||||||
@@ -786,8 +773,8 @@ void OpenGLComposite::broadcastRuntimeState()
|
|||||||
|
|
||||||
void OpenGLComposite::resetTemporalHistoryState()
|
void OpenGLComposite::resetTemporalHistoryState()
|
||||||
{
|
{
|
||||||
mShaderPrograms->ResetTemporalHistoryState();
|
mRenderEngine->ResetTemporalHistoryState();
|
||||||
mShaderPrograms->ResetShaderFeedbackState();
|
mRenderEngine->ResetShaderFeedbackState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLComposite::CheckOpenGLExtensions()
|
bool OpenGLComposite::CheckOpenGLExtensions()
|
||||||
|
|||||||
@@ -12,8 +12,9 @@
|
|||||||
#include <comutil.h>
|
#include <comutil.h>
|
||||||
|
|
||||||
#include "GLExtensions.h"
|
#include "GLExtensions.h"
|
||||||
#include "OpenGLRenderer.h"
|
|
||||||
#include "RuntimeHost.h"
|
#include "RuntimeHost.h"
|
||||||
|
#include "RuntimeSnapshotProvider.h"
|
||||||
|
#include "RuntimeStore.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -25,13 +26,10 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
class VideoIODevice;
|
class RenderEngine;
|
||||||
class OpenGLVideoIOBridge;
|
|
||||||
class OpenGLRenderPass;
|
|
||||||
class OpenGLRenderPipeline;
|
|
||||||
class OpenGLShaderPrograms;
|
|
||||||
class RuntimeServices;
|
class RuntimeServices;
|
||||||
class ShaderBuildQueue;
|
class ShaderBuildQueue;
|
||||||
|
class VideoBackend;
|
||||||
|
|
||||||
|
|
||||||
class OpenGLComposite
|
class OpenGLComposite
|
||||||
@@ -72,7 +70,6 @@ private:
|
|||||||
void resizeWindow(int width, int height);
|
void resizeWindow(int width, int height);
|
||||||
bool CheckOpenGLExtensions();
|
bool CheckOpenGLExtensions();
|
||||||
void PublishVideoIOStatus(const std::string& statusMessage);
|
void PublishVideoIOStatus(const std::string& statusMessage);
|
||||||
using LayerProgram = OpenGLRenderer::LayerProgram;
|
|
||||||
struct OscOverlayState
|
struct OscOverlayState
|
||||||
{
|
{
|
||||||
std::string layerKey;
|
std::string layerKey;
|
||||||
@@ -92,15 +89,13 @@ private:
|
|||||||
HGLRC hGLRC;
|
HGLRC hGLRC;
|
||||||
CRITICAL_SECTION pMutex;
|
CRITICAL_SECTION pMutex;
|
||||||
|
|
||||||
std::unique_ptr<VideoIODevice> mVideoIO;
|
|
||||||
std::unique_ptr<OpenGLRenderer> mRenderer;
|
|
||||||
std::unique_ptr<RuntimeHost> mRuntimeHost;
|
std::unique_ptr<RuntimeHost> mRuntimeHost;
|
||||||
std::unique_ptr<OpenGLVideoIOBridge> mVideoIOBridge;
|
std::unique_ptr<RuntimeStore> mRuntimeStore;
|
||||||
std::unique_ptr<OpenGLRenderPass> mRenderPass;
|
std::unique_ptr<RuntimeSnapshotProvider> mRuntimeSnapshotProvider;
|
||||||
std::unique_ptr<OpenGLRenderPipeline> mRenderPipeline;
|
std::unique_ptr<RenderEngine> mRenderEngine;
|
||||||
std::unique_ptr<OpenGLShaderPrograms> mShaderPrograms;
|
|
||||||
std::unique_ptr<ShaderBuildQueue> mShaderBuildQueue;
|
std::unique_ptr<ShaderBuildQueue> mShaderBuildQueue;
|
||||||
std::unique_ptr<RuntimeServices> mRuntimeServices;
|
std::unique_ptr<RuntimeServices> mRuntimeServices;
|
||||||
|
std::unique_ptr<VideoBackend> mVideoBackend;
|
||||||
std::vector<RuntimeRenderState> mCachedLayerRenderStates;
|
std::vector<RuntimeRenderState> mCachedLayerRenderStates;
|
||||||
uint64_t mCachedRenderStateVersion = 0;
|
uint64_t mCachedRenderStateVersion = 0;
|
||||||
uint64_t mCachedParameterStateVersion = 0;
|
uint64_t mCachedParameterStateVersion = 0;
|
||||||
|
|||||||
@@ -3,22 +3,22 @@
|
|||||||
|
|
||||||
std::string OpenGLComposite::GetRuntimeStateJson() const
|
std::string OpenGLComposite::GetRuntimeStateJson() const
|
||||||
{
|
{
|
||||||
return mRuntimeHost ? mRuntimeHost->BuildStateJson() : "{}";
|
return mRuntimeStore ? mRuntimeStore->BuildPersistentStateJson() : "{}";
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short OpenGLComposite::GetControlServerPort() const
|
unsigned short OpenGLComposite::GetControlServerPort() const
|
||||||
{
|
{
|
||||||
return mRuntimeHost ? mRuntimeHost->GetServerPort() : 0;
|
return mRuntimeStore ? mRuntimeStore->GetConfiguredControlServerPort() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short OpenGLComposite::GetOscPort() const
|
unsigned short OpenGLComposite::GetOscPort() const
|
||||||
{
|
{
|
||||||
return mRuntimeHost ? mRuntimeHost->GetOscPort() : 0;
|
return mRuntimeStore ? mRuntimeStore->GetConfiguredOscPort() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string OpenGLComposite::GetOscBindAddress() const
|
std::string OpenGLComposite::GetOscBindAddress() const
|
||||||
{
|
{
|
||||||
return mRuntimeHost ? mRuntimeHost->GetOscBindAddress() : "127.0.0.1";
|
return mRuntimeStore ? mRuntimeStore->GetConfiguredOscBindAddress() : "127.0.0.1";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string OpenGLComposite::GetControlUrl() const
|
std::string OpenGLComposite::GetControlUrl() const
|
||||||
@@ -38,7 +38,7 @@ std::string OpenGLComposite::GetOscAddress() const
|
|||||||
|
|
||||||
bool OpenGLComposite::AddLayer(const std::string& shaderId, std::string& error)
|
bool OpenGLComposite::AddLayer(const std::string& shaderId, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->AddLayer(shaderId, error))
|
if (!mRuntimeStore->CreateStoredLayer(shaderId, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ReloadShader(true);
|
ReloadShader(true);
|
||||||
@@ -48,7 +48,7 @@ bool OpenGLComposite::AddLayer(const std::string& shaderId, std::string& error)
|
|||||||
|
|
||||||
bool OpenGLComposite::RemoveLayer(const std::string& layerId, std::string& error)
|
bool OpenGLComposite::RemoveLayer(const std::string& layerId, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->RemoveLayer(layerId, error))
|
if (!mRuntimeStore->DeleteStoredLayer(layerId, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ReloadShader(true);
|
ReloadShader(true);
|
||||||
@@ -58,7 +58,7 @@ bool OpenGLComposite::RemoveLayer(const std::string& layerId, std::string& error
|
|||||||
|
|
||||||
bool OpenGLComposite::MoveLayer(const std::string& layerId, int direction, std::string& error)
|
bool OpenGLComposite::MoveLayer(const std::string& layerId, int direction, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->MoveLayer(layerId, direction, error))
|
if (!mRuntimeStore->MoveStoredLayer(layerId, direction, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ReloadShader(true);
|
ReloadShader(true);
|
||||||
@@ -68,7 +68,7 @@ bool OpenGLComposite::MoveLayer(const std::string& layerId, int direction, std::
|
|||||||
|
|
||||||
bool OpenGLComposite::MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
|
bool OpenGLComposite::MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->MoveLayerToIndex(layerId, targetIndex, error))
|
if (!mRuntimeStore->MoveStoredLayerToIndex(layerId, targetIndex, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ReloadShader(true);
|
ReloadShader(true);
|
||||||
@@ -78,7 +78,7 @@ bool OpenGLComposite::MoveLayerToIndex(const std::string& layerId, std::size_t t
|
|||||||
|
|
||||||
bool OpenGLComposite::SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error)
|
bool OpenGLComposite::SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->SetLayerBypass(layerId, bypassed, error))
|
if (!mRuntimeStore->SetStoredLayerBypassState(layerId, bypassed, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ReloadShader();
|
ReloadShader();
|
||||||
@@ -88,7 +88,7 @@ bool OpenGLComposite::SetLayerBypass(const std::string& layerId, bool bypassed,
|
|||||||
|
|
||||||
bool OpenGLComposite::SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error)
|
bool OpenGLComposite::SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->SetLayerShader(layerId, shaderId, error))
|
if (!mRuntimeStore->SetStoredLayerShaderSelection(layerId, shaderId, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ReloadShader();
|
ReloadShader();
|
||||||
@@ -102,7 +102,7 @@ bool OpenGLComposite::UpdateLayerParameterJson(const std::string& layerId, const
|
|||||||
if (!ParseJson(valueJson, parsedValue, error))
|
if (!ParseJson(valueJson, parsedValue, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!mRuntimeHost->UpdateLayerParameter(layerId, parameterId, parsedValue, error))
|
if (!mRuntimeStore->SetStoredParameterValue(layerId, parameterId, parsedValue, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
@@ -115,7 +115,7 @@ bool OpenGLComposite::UpdateLayerParameterByControlKeyJson(const std::string& la
|
|||||||
if (!ParseJson(valueJson, parsedValue, error))
|
if (!ParseJson(valueJson, parsedValue, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!mRuntimeHost->UpdateLayerParameterByControlKey(layerKey, parameterKey, parsedValue, error))
|
if (!mRuntimeStore->SetStoredParameterValueByControlKey(layerKey, parameterKey, parsedValue, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
@@ -124,7 +124,7 @@ bool OpenGLComposite::UpdateLayerParameterByControlKeyJson(const std::string& la
|
|||||||
|
|
||||||
bool OpenGLComposite::ResetLayerParameters(const std::string& layerId, std::string& error)
|
bool OpenGLComposite::ResetLayerParameters(const std::string& layerId, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->ResetLayerParameters(layerId, error))
|
if (!mRuntimeStore->ResetStoredLayerParameterValues(layerId, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mOscOverlayStates.clear();
|
mOscOverlayStates.clear();
|
||||||
@@ -138,7 +138,7 @@ bool OpenGLComposite::ResetLayerParameters(const std::string& layerId, std::stri
|
|||||||
|
|
||||||
bool OpenGLComposite::SaveStackPreset(const std::string& presetName, std::string& error)
|
bool OpenGLComposite::SaveStackPreset(const std::string& presetName, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->SaveStackPreset(presetName, error))
|
if (!mRuntimeStore->SaveStackPresetSnapshot(presetName, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
broadcastRuntimeState();
|
broadcastRuntimeState();
|
||||||
@@ -147,7 +147,7 @@ bool OpenGLComposite::SaveStackPreset(const std::string& presetName, std::string
|
|||||||
|
|
||||||
bool OpenGLComposite::LoadStackPreset(const std::string& presetName, std::string& error)
|
bool OpenGLComposite::LoadStackPreset(const std::string& presetName, std::string& error)
|
||||||
{
|
{
|
||||||
if (!mRuntimeHost->LoadStackPreset(presetName, error))
|
if (!mRuntimeStore->LoadStackPresetSnapshot(presetName, error))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ReloadShader();
|
ReloadShader();
|
||||||
|
|||||||
180
apps/LoopThroughWithOpenGLCompositing/gl/RenderEngine.cpp
Normal file
180
apps/LoopThroughWithOpenGLCompositing/gl/RenderEngine.cpp
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
#include "RenderEngine.h"
|
||||||
|
|
||||||
|
#include <gl/gl.h>
|
||||||
|
|
||||||
|
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<RuntimeRenderState>& 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<long>(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<RuntimeRenderState>& 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<unsigned char>& bottomUpPixels)
|
||||||
|
{
|
||||||
|
if (width == 0 || height == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
EnterCriticalSection(&mMutex);
|
||||||
|
wglMakeCurrent(mHdc, mHglrc);
|
||||||
|
|
||||||
|
bottomUpPixels.resize(static_cast<std::size_t>(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;
|
||||||
|
}
|
||||||
72
apps/LoopThroughWithOpenGLCompositing/gl/RenderEngine.h
Normal file
72
apps/LoopThroughWithOpenGLCompositing/gl/RenderEngine.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "OpenGLRenderPass.h"
|
||||||
|
#include "OpenGLRenderPipeline.h"
|
||||||
|
#include "OpenGLRenderer.h"
|
||||||
|
#include "OpenGLShaderPrograms.h"
|
||||||
|
#include "RuntimeHost.h"
|
||||||
|
#include "RuntimeSnapshotProvider.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class RenderEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using RenderEffectCallback = std::function<void()>;
|
||||||
|
using ScreenshotCallback = std::function<void()>;
|
||||||
|
using PreviewPaintCallback = std::function<void()>;
|
||||||
|
|
||||||
|
RenderEngine(
|
||||||
|
RuntimeHost& runtimeHost,
|
||||||
|
RuntimeSnapshotProvider& runtimeSnapshotProvider,
|
||||||
|
CRITICAL_SECTION& mutex,
|
||||||
|
HDC hdc,
|
||||||
|
HGLRC hglrc,
|
||||||
|
RenderEffectCallback renderEffect,
|
||||||
|
ScreenshotCallback screenshotReady,
|
||||||
|
PreviewPaintCallback previewPaint);
|
||||||
|
~RenderEngine();
|
||||||
|
|
||||||
|
bool CompileDecodeShader(int errorMessageSize, char* errorMessage);
|
||||||
|
bool CompileOutputPackShader(int errorMessageSize, char* errorMessage);
|
||||||
|
bool InitializeResources(
|
||||||
|
unsigned inputFrameWidth,
|
||||||
|
unsigned inputFrameHeight,
|
||||||
|
unsigned captureTextureWidth,
|
||||||
|
unsigned outputFrameWidth,
|
||||||
|
unsigned outputFrameHeight,
|
||||||
|
unsigned outputPackTextureWidth,
|
||||||
|
std::string& error);
|
||||||
|
bool CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage);
|
||||||
|
bool CommitPreparedLayerPrograms(const PreparedShaderBuild& preparedBuild, unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage);
|
||||||
|
|
||||||
|
const std::vector<RuntimeRenderState>& CommittedLayerStates() const;
|
||||||
|
void ResetTemporalHistoryState();
|
||||||
|
void ResetShaderFeedbackState();
|
||||||
|
void ResizeView(int width, int height);
|
||||||
|
bool TryPresentToWindow(unsigned outputFrameWidth, unsigned outputFrameHeight);
|
||||||
|
bool TryUploadInputFrame(const VideoIOFrame& inputFrame, const VideoIOState& videoState);
|
||||||
|
bool RenderOutputFrame(const RenderPipelineFrameContext& context, VideoIOOutputFrame& outputFrame);
|
||||||
|
void RenderLayerStack(
|
||||||
|
bool hasInputSource,
|
||||||
|
const std::vector<RuntimeRenderState>& layerStates,
|
||||||
|
unsigned inputFrameWidth,
|
||||||
|
unsigned inputFrameHeight,
|
||||||
|
unsigned captureTextureWidth,
|
||||||
|
VideoIOPixelFormat inputPixelFormat,
|
||||||
|
unsigned historyCap);
|
||||||
|
bool ReadOutputFrameRgba(unsigned width, unsigned height, std::vector<unsigned char>& bottomUpPixels);
|
||||||
|
|
||||||
|
private:
|
||||||
|
OpenGLRenderer mRenderer;
|
||||||
|
OpenGLRenderPass mRenderPass;
|
||||||
|
OpenGLRenderPipeline mRenderPipeline;
|
||||||
|
OpenGLShaderPrograms mShaderPrograms;
|
||||||
|
CRITICAL_SECTION& mMutex;
|
||||||
|
HDC mHdc;
|
||||||
|
HGLRC mHglrc;
|
||||||
|
};
|
||||||
@@ -47,7 +47,7 @@ bool OpenGLRenderPipeline::RenderFrame(const RenderPipelineFrameContext& context
|
|||||||
|
|
||||||
const auto renderEndTime = std::chrono::steady_clock::now();
|
const auto renderEndTime = std::chrono::steady_clock::now();
|
||||||
const double renderMilliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(renderEndTime - renderStartTime).count();
|
const double renderMilliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(renderEndTime - renderStartTime).count();
|
||||||
mRuntimeHost.TrySetPerformanceStats(state.frameBudgetMilliseconds, renderMilliseconds);
|
mRuntimeHost.GetHealthTelemetry().TryRecordPerformanceStats(state.frameBudgetMilliseconds, renderMilliseconds);
|
||||||
mRuntimeHost.TryAdvanceFrame();
|
mRuntimeHost.TryAdvanceFrame();
|
||||||
|
|
||||||
ReadOutputFrame(state, outputFrame);
|
ReadOutputFrame(state, outputFrame);
|
||||||
|
|||||||
@@ -1,26 +1,17 @@
|
|||||||
#include "OpenGLVideoIOBridge.h"
|
#include "OpenGLVideoIOBridge.h"
|
||||||
|
|
||||||
#include "OpenGLRenderer.h"
|
#include "HealthTelemetry.h"
|
||||||
#include "RuntimeHost.h"
|
#include "RenderEngine.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <gl/gl.h>
|
|
||||||
|
|
||||||
OpenGLVideoIOBridge::OpenGLVideoIOBridge(
|
OpenGLVideoIOBridge::OpenGLVideoIOBridge(
|
||||||
VideoIODevice& videoIO,
|
VideoIODevice& videoIO,
|
||||||
OpenGLRenderer& renderer,
|
RenderEngine& renderEngine,
|
||||||
OpenGLRenderPipeline& renderPipeline,
|
HealthTelemetry& healthTelemetry) :
|
||||||
RuntimeHost& runtimeHost,
|
|
||||||
CRITICAL_SECTION& mutex,
|
|
||||||
HDC hdc,
|
|
||||||
HGLRC hglrc) :
|
|
||||||
mVideoIO(videoIO),
|
mVideoIO(videoIO),
|
||||||
mRenderer(renderer),
|
mRenderEngine(renderEngine),
|
||||||
mRenderPipeline(renderPipeline),
|
mHealthTelemetry(healthTelemetry)
|
||||||
mRuntimeHost(runtimeHost),
|
|
||||||
mMutex(mutex),
|
|
||||||
mHdc(hdc),
|
|
||||||
mHglrc(hglrc)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +37,7 @@ void OpenGLVideoIOBridge::RecordFramePacing(VideoIOCompletionResult completionRe
|
|||||||
else if (completionResult == VideoIOCompletionResult::Flushed)
|
else if (completionResult == VideoIOCompletionResult::Flushed)
|
||||||
++mFlushedFrameCount;
|
++mFlushedFrameCount;
|
||||||
|
|
||||||
mRuntimeHost.TrySetFramePacingStats(
|
mHealthTelemetry.TryRecordFramePacingStats(
|
||||||
mCompletionIntervalMilliseconds,
|
mCompletionIntervalMilliseconds,
|
||||||
mSmoothedCompletionIntervalMilliseconds,
|
mSmoothedCompletionIntervalMilliseconds,
|
||||||
mMaxCompletionIntervalMilliseconds,
|
mMaxCompletionIntervalMilliseconds,
|
||||||
@@ -58,38 +49,12 @@ void OpenGLVideoIOBridge::RecordFramePacing(VideoIOCompletionResult completionRe
|
|||||||
void OpenGLVideoIOBridge::VideoFrameArrived(const VideoIOFrame& inputFrame)
|
void OpenGLVideoIOBridge::VideoFrameArrived(const VideoIOFrame& inputFrame)
|
||||||
{
|
{
|
||||||
const VideoIOState& state = mVideoIO.State();
|
const VideoIOState& state = mVideoIO.State();
|
||||||
mRuntimeHost.TrySetSignalStatus(!inputFrame.hasNoInputSource, state.inputFrameSize.width, state.inputFrameSize.height, state.inputDisplayModeName);
|
mHealthTelemetry.TryReportSignalStatus(!inputFrame.hasNoInputSource, state.inputFrameSize.width, state.inputFrameSize.height, state.inputDisplayModeName);
|
||||||
|
|
||||||
if (inputFrame.hasNoInputSource || inputFrame.bytes == nullptr)
|
if (inputFrame.hasNoInputSource || inputFrame.bytes == nullptr)
|
||||||
return; // don't transfer texture when there's no input
|
return; // don't transfer texture when there's no input
|
||||||
|
|
||||||
const long textureSize = inputFrame.rowBytes * static_cast<long>(inputFrame.height);
|
mRenderEngine.TryUploadInputFrame(inputFrame, state);
|
||||||
|
|
||||||
// Never let input upload stall the playout/render callback. If the GL bridge
|
|
||||||
// is busy producing an output frame, skip this upload and use the next input.
|
|
||||||
if (!TryEnterCriticalSection(&mMutex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
wglMakeCurrent(mHdc, mHglrc); // make OpenGL context current in this thread
|
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
// NULL for last arg indicates use current GL_PIXEL_UNPACK_BUFFER target as texture data.
|
|
||||||
if (inputFrame.pixelFormat == VideoIOPixelFormat::V210)
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, state.captureTextureWidth, state.inputFrameSize.height, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
else
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, state.captureTextureWidth, state.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLVideoIOBridge::PlayoutFrameCompleted(const VideoIOCompletion& completion)
|
void OpenGLVideoIOBridge::PlayoutFrameCompleted(const VideoIOCompletion& completion)
|
||||||
@@ -104,15 +69,7 @@ void OpenGLVideoIOBridge::PlayoutFrameCompleted(const VideoIOCompletion& complet
|
|||||||
frameContext.videoState = state;
|
frameContext.videoState = state;
|
||||||
frameContext.completion = completion;
|
frameContext.completion = completion;
|
||||||
|
|
||||||
EnterCriticalSection(&mMutex);
|
mRenderEngine.RenderOutputFrame(frameContext, outputFrame);
|
||||||
|
|
||||||
// make GL context current in this thread
|
|
||||||
wglMakeCurrent(mHdc, mHglrc);
|
|
||||||
|
|
||||||
mRenderPipeline.RenderFrame(frameContext, outputFrame);
|
|
||||||
wglMakeCurrent(NULL, NULL);
|
|
||||||
|
|
||||||
LeaveCriticalSection(&mMutex);
|
|
||||||
|
|
||||||
mVideoIO.EndOutputFrame(outputFrame);
|
mVideoIO.EndOutputFrame(outputFrame);
|
||||||
|
|
||||||
|
|||||||
@@ -2,24 +2,19 @@
|
|||||||
|
|
||||||
#include "OpenGLRenderPipeline.h"
|
#include "OpenGLRenderPipeline.h"
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
class RuntimeHost;
|
class HealthTelemetry;
|
||||||
|
class RenderEngine;
|
||||||
|
|
||||||
class OpenGLVideoIOBridge
|
class OpenGLVideoIOBridge
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpenGLVideoIOBridge(
|
OpenGLVideoIOBridge(
|
||||||
VideoIODevice& videoIO,
|
VideoIODevice& videoIO,
|
||||||
OpenGLRenderer& renderer,
|
RenderEngine& renderEngine,
|
||||||
OpenGLRenderPipeline& renderPipeline,
|
HealthTelemetry& healthTelemetry);
|
||||||
RuntimeHost& runtimeHost,
|
|
||||||
CRITICAL_SECTION& mutex,
|
|
||||||
HDC hdc,
|
|
||||||
HGLRC hglrc);
|
|
||||||
|
|
||||||
void VideoFrameArrived(const VideoIOFrame& inputFrame);
|
void VideoFrameArrived(const VideoIOFrame& inputFrame);
|
||||||
void PlayoutFrameCompleted(const VideoIOCompletion& completion);
|
void PlayoutFrameCompleted(const VideoIOCompletion& completion);
|
||||||
@@ -28,12 +23,8 @@ private:
|
|||||||
void RecordFramePacing(VideoIOCompletionResult completionResult);
|
void RecordFramePacing(VideoIOCompletionResult completionResult);
|
||||||
|
|
||||||
VideoIODevice& mVideoIO;
|
VideoIODevice& mVideoIO;
|
||||||
OpenGLRenderer& mRenderer;
|
RenderEngine& mRenderEngine;
|
||||||
OpenGLRenderPipeline& mRenderPipeline;
|
HealthTelemetry& mHealthTelemetry;
|
||||||
RuntimeHost& mRuntimeHost;
|
|
||||||
CRITICAL_SECTION& mMutex;
|
|
||||||
HDC mHdc;
|
|
||||||
HGLRC mHglrc;
|
|
||||||
std::chrono::steady_clock::time_point mLastPlayoutCompletionTime;
|
std::chrono::steady_clock::time_point mLastPlayoutCompletionTime;
|
||||||
double mCompletionIntervalMilliseconds = 0.0;
|
double mCompletionIntervalMilliseconds = 0.0;
|
||||||
double mSmoothedCompletionIntervalMilliseconds = 0.0;
|
double mSmoothedCompletionIntervalMilliseconds = 0.0;
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ std::size_t RequiredTemporaryRenderTargets(const std::vector<OpenGLRenderer::Lay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLShaderPrograms::OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost& runtimeHost) :
|
OpenGLShaderPrograms::OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost& runtimeHost, RuntimeSnapshotProvider& runtimeSnapshotProvider) :
|
||||||
mRenderer(renderer),
|
mRenderer(renderer),
|
||||||
mRuntimeHost(runtimeHost),
|
mRuntimeHost(runtimeHost),
|
||||||
|
mRuntimeSnapshotProvider(runtimeSnapshotProvider),
|
||||||
mGlobalParamsBuffer(renderer),
|
mGlobalParamsBuffer(renderer),
|
||||||
mCompiler(renderer, runtimeHost, mTextureBindings)
|
mCompiler(renderer, runtimeHost, mTextureBindings)
|
||||||
{
|
{
|
||||||
@@ -39,7 +40,9 @@ OpenGLShaderPrograms::OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost
|
|||||||
|
|
||||||
bool OpenGLShaderPrograms::CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage)
|
bool OpenGLShaderPrograms::CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage)
|
||||||
{
|
{
|
||||||
const std::vector<RuntimeRenderState> layerStates = mRuntimeHost.GetLayerRenderStates(inputFrameWidth, inputFrameHeight);
|
const RuntimeRenderStateSnapshot renderSnapshot =
|
||||||
|
mRuntimeSnapshotProvider.GetRenderStateSnapshot(inputFrameWidth, inputFrameHeight);
|
||||||
|
const std::vector<RuntimeRenderState>& layerStates = renderSnapshot.states;
|
||||||
std::string temporalError;
|
std::string temporalError;
|
||||||
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
|
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
|
||||||
if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(layerStates, historyCap, temporalError))
|
if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(layerStates, historyCap, temporalError))
|
||||||
@@ -87,7 +90,7 @@ bool OpenGLShaderPrograms::CompileLayerPrograms(unsigned inputFrameWidth, unsign
|
|||||||
|
|
||||||
DestroyLayerPrograms();
|
DestroyLayerPrograms();
|
||||||
mRenderer.ReplaceLayerPrograms(newPrograms);
|
mRenderer.ReplaceLayerPrograms(newPrograms);
|
||||||
mCommittedLayerStates = layerStates;
|
mCommittedLayerStates = renderSnapshot.states;
|
||||||
|
|
||||||
mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully.");
|
mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully.");
|
||||||
mRuntimeHost.ClearReloadRequest();
|
mRuntimeHost.ClearReloadRequest();
|
||||||
@@ -105,18 +108,18 @@ bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild
|
|||||||
|
|
||||||
std::string temporalError;
|
std::string temporalError;
|
||||||
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
|
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
|
||||||
if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(preparedBuild.layerStates, historyCap, temporalError))
|
if (!mRenderer.TemporalHistory().ValidateTextureUnitBudget(preparedBuild.renderSnapshot.states, historyCap, temporalError))
|
||||||
{
|
{
|
||||||
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!mRenderer.TemporalHistory().EnsureResources(preparedBuild.layerStates, historyCap, inputFrameWidth, inputFrameHeight, temporalError))
|
if (!mRenderer.TemporalHistory().EnsureResources(preparedBuild.renderSnapshot.states, historyCap, inputFrameWidth, inputFrameHeight, temporalError))
|
||||||
{
|
{
|
||||||
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mRenderer.ResourcesInitialized() &&
|
if (mRenderer.ResourcesInitialized() &&
|
||||||
!mRenderer.FeedbackBuffers().EnsureResources(preparedBuild.layerStates, inputFrameWidth, inputFrameHeight, temporalError))
|
!mRenderer.FeedbackBuffers().EnsureResources(preparedBuild.renderSnapshot.states, inputFrameWidth, inputFrameHeight, temporalError))
|
||||||
{
|
{
|
||||||
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
CopyErrorMessage(temporalError, errorMessageSize, errorMessage);
|
||||||
return false;
|
return false;
|
||||||
@@ -150,7 +153,7 @@ bool OpenGLShaderPrograms::CommitPreparedLayerPrograms(const PreparedShaderBuild
|
|||||||
|
|
||||||
DestroyLayerPrograms();
|
DestroyLayerPrograms();
|
||||||
mRenderer.ReplaceLayerPrograms(newPrograms);
|
mRenderer.ReplaceLayerPrograms(newPrograms);
|
||||||
mCommittedLayerStates = preparedBuild.layerStates;
|
mCommittedLayerStates = preparedBuild.renderSnapshot.states;
|
||||||
|
|
||||||
mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully.");
|
mRuntimeHost.SetCompileStatus(true, "Shader layers compiled successfully.");
|
||||||
mRuntimeHost.ClearReloadRequest();
|
mRuntimeHost.ClearReloadRequest();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "GlobalParamsBuffer.h"
|
#include "GlobalParamsBuffer.h"
|
||||||
#include "OpenGLRenderer.h"
|
#include "OpenGLRenderer.h"
|
||||||
#include "RuntimeHost.h"
|
#include "RuntimeHost.h"
|
||||||
|
#include "RuntimeSnapshotProvider.h"
|
||||||
#include "ShaderBuildQueue.h"
|
#include "ShaderBuildQueue.h"
|
||||||
#include "ShaderTypes.h"
|
#include "ShaderTypes.h"
|
||||||
#include "ShaderProgramCompiler.h"
|
#include "ShaderProgramCompiler.h"
|
||||||
@@ -15,7 +16,7 @@ class OpenGLShaderPrograms
|
|||||||
public:
|
public:
|
||||||
using LayerProgram = OpenGLRenderer::LayerProgram;
|
using LayerProgram = OpenGLRenderer::LayerProgram;
|
||||||
|
|
||||||
OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost& runtimeHost);
|
OpenGLShaderPrograms(OpenGLRenderer& renderer, RuntimeHost& runtimeHost, RuntimeSnapshotProvider& runtimeSnapshotProvider);
|
||||||
|
|
||||||
bool CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage);
|
bool CompileLayerPrograms(unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage);
|
||||||
bool CommitPreparedLayerPrograms(const PreparedShaderBuild& preparedBuild, unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage);
|
bool CommitPreparedLayerPrograms(const PreparedShaderBuild& preparedBuild, unsigned inputFrameWidth, unsigned inputFrameHeight, int errorMessageSize, char* errorMessage);
|
||||||
@@ -33,6 +34,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
OpenGLRenderer& mRenderer;
|
OpenGLRenderer& mRenderer;
|
||||||
RuntimeHost& mRuntimeHost;
|
RuntimeHost& mRuntimeHost;
|
||||||
|
RuntimeSnapshotProvider& mRuntimeSnapshotProvider;
|
||||||
ShaderTextureBindings mTextureBindings;
|
ShaderTextureBindings mTextureBindings;
|
||||||
GlobalParamsBuffer mGlobalParamsBuffer;
|
GlobalParamsBuffer mGlobalParamsBuffer;
|
||||||
ShaderProgramCompiler mCompiler;
|
ShaderProgramCompiler mCompiler;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "ShaderBuildQueue.h"
|
#include "ShaderBuildQueue.h"
|
||||||
|
|
||||||
#include "RuntimeHost.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -10,8 +8,8 @@ namespace
|
|||||||
constexpr auto kShaderBuildDebounce = std::chrono::milliseconds(400);
|
constexpr auto kShaderBuildDebounce = std::chrono::milliseconds(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderBuildQueue::ShaderBuildQueue(RuntimeHost& runtimeHost) :
|
ShaderBuildQueue::ShaderBuildQueue(RuntimeSnapshotProvider& runtimeSnapshotProvider) :
|
||||||
mRuntimeHost(runtimeHost),
|
mRuntimeSnapshotProvider(runtimeSnapshotProvider),
|
||||||
mWorkerThread([this]() { WorkerLoop(); })
|
mWorkerThread([this]() { WorkerLoop(); })
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -113,14 +111,14 @@ PreparedShaderBuild ShaderBuildQueue::Build(uint64_t generation, unsigned output
|
|||||||
{
|
{
|
||||||
PreparedShaderBuild build;
|
PreparedShaderBuild build;
|
||||||
build.generation = generation;
|
build.generation = generation;
|
||||||
build.layerStates = mRuntimeHost.GetLayerRenderStates(outputWidth, outputHeight);
|
build.renderSnapshot = mRuntimeSnapshotProvider.GetRenderStateSnapshot(outputWidth, outputHeight);
|
||||||
build.layers.reserve(build.layerStates.size());
|
build.layers.reserve(build.renderSnapshot.states.size());
|
||||||
|
|
||||||
for (const RuntimeRenderState& state : build.layerStates)
|
for (const RuntimeRenderState& state : build.renderSnapshot.states)
|
||||||
{
|
{
|
||||||
PreparedLayerShader layer;
|
PreparedLayerShader layer;
|
||||||
layer.state = state;
|
layer.state = state;
|
||||||
if (!mRuntimeHost.BuildLayerPassFragmentShaderSources(state.layerId, layer.passes, build.message))
|
if (!mRuntimeSnapshotProvider.BuildLayerPassFragmentShaderSources(state.layerId, layer.passes, build.message))
|
||||||
{
|
{
|
||||||
build.succeeded = false;
|
build.succeeded = false;
|
||||||
return build;
|
return build;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "RuntimeSnapshotProvider.h"
|
||||||
#include "ShaderTypes.h"
|
#include "ShaderTypes.h"
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
@@ -9,8 +10,6 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class RuntimeHost;
|
|
||||||
|
|
||||||
struct PreparedLayerShader
|
struct PreparedLayerShader
|
||||||
{
|
{
|
||||||
RuntimeRenderState state;
|
RuntimeRenderState state;
|
||||||
@@ -22,14 +21,14 @@ struct PreparedShaderBuild
|
|||||||
uint64_t generation = 0;
|
uint64_t generation = 0;
|
||||||
bool succeeded = false;
|
bool succeeded = false;
|
||||||
std::string message;
|
std::string message;
|
||||||
std::vector<RuntimeRenderState> layerStates;
|
RuntimeRenderStateSnapshot renderSnapshot;
|
||||||
std::vector<PreparedLayerShader> layers;
|
std::vector<PreparedLayerShader> layers;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderBuildQueue
|
class ShaderBuildQueue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ShaderBuildQueue(RuntimeHost& runtimeHost);
|
explicit ShaderBuildQueue(RuntimeSnapshotProvider& runtimeSnapshotProvider);
|
||||||
~ShaderBuildQueue();
|
~ShaderBuildQueue();
|
||||||
|
|
||||||
ShaderBuildQueue(const ShaderBuildQueue&) = delete;
|
ShaderBuildQueue(const ShaderBuildQueue&) = delete;
|
||||||
@@ -43,7 +42,7 @@ private:
|
|||||||
void WorkerLoop();
|
void WorkerLoop();
|
||||||
PreparedShaderBuild Build(uint64_t generation, unsigned outputWidth, unsigned outputHeight);
|
PreparedShaderBuild Build(uint64_t generation, unsigned outputWidth, unsigned outputHeight);
|
||||||
|
|
||||||
RuntimeHost& mRuntimeHost;
|
RuntimeSnapshotProvider& mRuntimeSnapshotProvider;
|
||||||
std::thread mWorkerThread;
|
std::thread mWorkerThread;
|
||||||
std::mutex mMutex;
|
std::mutex mMutex;
|
||||||
std::condition_variable mCondition;
|
std::condition_variable mCondition;
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "HealthTelemetry.h"
|
||||||
|
|
||||||
|
#include "RuntimeHost.h"
|
||||||
|
|
||||||
|
HealthTelemetry::HealthTelemetry(RuntimeHost& runtimeHost) :
|
||||||
|
mRuntimeHost(runtimeHost)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void HealthTelemetry::ReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName)
|
||||||
|
{
|
||||||
|
mRuntimeHost.WriteSignalStatus(hasSignal, width, height, modeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HealthTelemetry::TryReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.TryWriteSignalStatus(hasSignal, width, height, modeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HealthTelemetry::RecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds)
|
||||||
|
{
|
||||||
|
mRuntimeHost.WritePerformanceStats(frameBudgetMilliseconds, renderMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HealthTelemetry::TryRecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.TryWritePerformanceStats(frameBudgetMilliseconds, renderMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HealthTelemetry::RecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount)
|
||||||
|
{
|
||||||
|
mRuntimeHost.WriteFramePacingStats(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds,
|
||||||
|
maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HealthTelemetry::TryRecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.TryWriteFramePacingStats(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds,
|
||||||
|
maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount);
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RuntimeHost;
|
||||||
|
|
||||||
|
// Phase 1 compatibility seam for status and timing reporting. The current
|
||||||
|
// implementation still writes through RuntimeHost, but callers can now target
|
||||||
|
// HealthTelemetry as the home for operational visibility work.
|
||||||
|
class HealthTelemetry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit HealthTelemetry(RuntimeHost& runtimeHost);
|
||||||
|
|
||||||
|
void ReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
|
||||||
|
bool TryReportSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
|
||||||
|
|
||||||
|
void RecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds);
|
||||||
|
bool TryRecordPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds);
|
||||||
|
|
||||||
|
void RecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
|
||||||
|
bool TryRecordFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
RuntimeHost& mRuntimeHost;
|
||||||
|
};
|
||||||
@@ -699,7 +699,8 @@ bool ParseParameterDefinitions(const JsonValue& manifestJson, ShaderPackage& sha
|
|||||||
}
|
}
|
||||||
|
|
||||||
RuntimeHost::RuntimeHost()
|
RuntimeHost::RuntimeHost()
|
||||||
: mReloadRequested(false),
|
: mHealthTelemetry(*this),
|
||||||
|
mReloadRequested(false),
|
||||||
mCompileSucceeded(false),
|
mCompileSucceeded(false),
|
||||||
mHasSignal(false),
|
mHasSignal(false),
|
||||||
mSignalWidth(0),
|
mSignalWidth(0),
|
||||||
@@ -1351,12 +1352,22 @@ void RuntimeHost::SetCompileStatus(bool succeeded, const std::string& message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeHost::SetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName)
|
void RuntimeHost::SetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName)
|
||||||
|
{
|
||||||
|
mHealthTelemetry.ReportSignalStatus(hasSignal, width, height, modeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeHost::TrySetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName)
|
||||||
|
{
|
||||||
|
return mHealthTelemetry.TryReportSignalStatus(hasSignal, width, height, modeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeHost::WriteSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
SetSignalStatusLocked(hasSignal, width, height, modeName);
|
SetSignalStatusLocked(hasSignal, width, height, modeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeHost::TrySetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName)
|
bool RuntimeHost::TryWriteSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mMutex, std::try_to_lock);
|
std::unique_lock<std::mutex> lock(mMutex, std::try_to_lock);
|
||||||
if (!lock.owns_lock())
|
if (!lock.owns_lock())
|
||||||
@@ -1413,12 +1424,22 @@ void RuntimeHost::SetVideoIOStatus(const std::string& backendName, const std::st
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RuntimeHost::SetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds)
|
void RuntimeHost::SetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds)
|
||||||
|
{
|
||||||
|
mHealthTelemetry.RecordPerformanceStats(frameBudgetMilliseconds, renderMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeHost::TrySetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds)
|
||||||
|
{
|
||||||
|
return mHealthTelemetry.TryRecordPerformanceStats(frameBudgetMilliseconds, renderMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeHost::WritePerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
SetPerformanceStatsLocked(frameBudgetMilliseconds, renderMilliseconds);
|
SetPerformanceStatsLocked(frameBudgetMilliseconds, renderMilliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeHost::TrySetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds)
|
bool RuntimeHost::TryWritePerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mMutex, std::try_to_lock);
|
std::unique_lock<std::mutex> lock(mMutex, std::try_to_lock);
|
||||||
if (!lock.owns_lock())
|
if (!lock.owns_lock())
|
||||||
@@ -1440,13 +1461,27 @@ void RuntimeHost::SetPerformanceStatsLocked(double frameBudgetMilliseconds, doub
|
|||||||
|
|
||||||
void RuntimeHost::SetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
void RuntimeHost::SetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount)
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount)
|
||||||
|
{
|
||||||
|
mHealthTelemetry.RecordFramePacingStats(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds,
|
||||||
|
maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeHost::TrySetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount)
|
||||||
|
{
|
||||||
|
return mHealthTelemetry.TryRecordFramePacingStats(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds,
|
||||||
|
maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeHost::WriteFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
SetFramePacingStatsLocked(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds,
|
SetFramePacingStatsLocked(completionIntervalMilliseconds, smoothedCompletionIntervalMilliseconds,
|
||||||
maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount);
|
maxCompletionIntervalMilliseconds, lateFrameCount, droppedFrameCount, flushedFrameCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeHost::TrySetFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
bool RuntimeHost::TryWriteFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount)
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mMutex, std::try_to_lock);
|
std::unique_lock<std::mutex> lock(mMutex, std::try_to_lock);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "HealthTelemetry.h"
|
||||||
#include "RuntimeJson.h"
|
#include "RuntimeJson.h"
|
||||||
#include "ShaderTypes.h"
|
#include "ShaderTypes.h"
|
||||||
|
|
||||||
@@ -52,6 +53,8 @@ public:
|
|||||||
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
|
||||||
void AdvanceFrame();
|
void AdvanceFrame();
|
||||||
bool TryAdvanceFrame();
|
bool TryAdvanceFrame();
|
||||||
|
HealthTelemetry& GetHealthTelemetry() { return mHealthTelemetry; }
|
||||||
|
const HealthTelemetry& GetHealthTelemetry() const { return mHealthTelemetry; }
|
||||||
|
|
||||||
bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<ShaderPassBuildSource>& passSources, std::string& error);
|
bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<ShaderPassBuildSource>& passSources, std::string& error);
|
||||||
std::vector<RuntimeRenderState> GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const;
|
std::vector<RuntimeRenderState> GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const;
|
||||||
@@ -145,14 +148,24 @@ private:
|
|||||||
LayerPersistentState* FindLayerById(const std::string& layerId);
|
LayerPersistentState* FindLayerById(const std::string& layerId);
|
||||||
const LayerPersistentState* FindLayerById(const std::string& layerId) const;
|
const LayerPersistentState* FindLayerById(const std::string& layerId) const;
|
||||||
std::string GenerateLayerId();
|
std::string GenerateLayerId();
|
||||||
|
void WriteSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
|
||||||
|
bool TryWriteSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
|
||||||
void SetSignalStatusLocked(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
|
void SetSignalStatusLocked(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
|
||||||
void MarkRenderStateDirtyLocked();
|
void MarkRenderStateDirtyLocked();
|
||||||
void MarkParameterStateDirtyLocked();
|
void MarkParameterStateDirtyLocked();
|
||||||
|
void WritePerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds);
|
||||||
|
bool TryWritePerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds);
|
||||||
void SetPerformanceStatsLocked(double frameBudgetMilliseconds, double renderMilliseconds);
|
void SetPerformanceStatsLocked(double frameBudgetMilliseconds, double renderMilliseconds);
|
||||||
|
void WriteFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
|
||||||
|
bool TryWriteFramePacingStats(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
|
||||||
void SetFramePacingStatsLocked(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
void SetFramePacingStatsLocked(double completionIntervalMilliseconds, double smoothedCompletionIntervalMilliseconds,
|
||||||
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
|
double maxCompletionIntervalMilliseconds, uint64_t lateFrameCount, uint64_t droppedFrameCount, uint64_t flushedFrameCount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class HealthTelemetry;
|
||||||
|
HealthTelemetry mHealthTelemetry;
|
||||||
mutable std::mutex mMutex;
|
mutable std::mutex mMutex;
|
||||||
AppConfig mConfig;
|
AppConfig mConfig;
|
||||||
PersistentState mPersistentState;
|
PersistentState mPersistentState;
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
#include "RuntimeSnapshotProvider.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
RuntimeSnapshotProvider::RuntimeSnapshotProvider(RuntimeHost& runtimeHost) :
|
||||||
|
mRuntimeHost(runtimeHost)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeSnapshotProvider::BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<ShaderPassBuildSource>& passSources, std::string& error) const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.BuildLayerPassFragmentShaderSources(layerId, passSources, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeSnapshotVersions RuntimeSnapshotProvider::GetVersions() const
|
||||||
|
{
|
||||||
|
RuntimeSnapshotVersions versions;
|
||||||
|
versions.renderStateVersion = mRuntimeHost.GetRenderStateVersion();
|
||||||
|
versions.parameterStateVersion = mRuntimeHost.GetParameterStateVersion();
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeRenderFrameContext RuntimeSnapshotProvider::GetFrameContext() const
|
||||||
|
{
|
||||||
|
std::vector<RuntimeRenderState> stateScratch(1);
|
||||||
|
mRuntimeHost.RefreshDynamicRenderStateFields(stateScratch);
|
||||||
|
|
||||||
|
RuntimeRenderFrameContext frameContext;
|
||||||
|
const RuntimeRenderState& state = stateScratch.front();
|
||||||
|
frameContext.timeSeconds = state.timeSeconds;
|
||||||
|
frameContext.utcTimeSeconds = state.utcTimeSeconds;
|
||||||
|
frameContext.utcOffsetSeconds = state.utcOffsetSeconds;
|
||||||
|
frameContext.startupRandom = state.startupRandom;
|
||||||
|
frameContext.frameCount = state.frameCount;
|
||||||
|
return frameContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeRenderStateSnapshot RuntimeSnapshotProvider::GetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight) const
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const RuntimeSnapshotVersions versionsBefore = GetVersions();
|
||||||
|
|
||||||
|
RuntimeRenderStateSnapshot snapshot;
|
||||||
|
snapshot.outputWidth = outputWidth;
|
||||||
|
snapshot.outputHeight = outputHeight;
|
||||||
|
snapshot.states = mRuntimeHost.GetLayerRenderStates(outputWidth, outputHeight);
|
||||||
|
|
||||||
|
const RuntimeSnapshotVersions versionsAfter = GetVersions();
|
||||||
|
if (versionsBefore.renderStateVersion == versionsAfter.renderStateVersion &&
|
||||||
|
versionsBefore.parameterStateVersion == versionsAfter.parameterStateVersion)
|
||||||
|
{
|
||||||
|
snapshot.versions = versionsAfter;
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeSnapshotProvider::TryGetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight, RuntimeRenderStateSnapshot& snapshot) const
|
||||||
|
{
|
||||||
|
const RuntimeSnapshotVersions versionsBefore = GetVersions();
|
||||||
|
|
||||||
|
std::vector<RuntimeRenderState> states;
|
||||||
|
if (!mRuntimeHost.TryGetLayerRenderStates(outputWidth, outputHeight, states))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const RuntimeSnapshotVersions versionsAfter = GetVersions();
|
||||||
|
if (versionsBefore.renderStateVersion != versionsAfter.renderStateVersion ||
|
||||||
|
versionsBefore.parameterStateVersion != versionsAfter.parameterStateVersion)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot.outputWidth = outputWidth;
|
||||||
|
snapshot.outputHeight = outputHeight;
|
||||||
|
snapshot.versions = versionsAfter;
|
||||||
|
snapshot.states = std::move(states);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeSnapshotProvider::TryRefreshSnapshotParameters(RuntimeRenderStateSnapshot& snapshot) const
|
||||||
|
{
|
||||||
|
const uint64_t expectedRenderStateVersion = snapshot.versions.renderStateVersion;
|
||||||
|
if (!mRuntimeHost.TryRefreshCachedLayerStates(snapshot.states))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const RuntimeSnapshotVersions versions = GetVersions();
|
||||||
|
if (versions.renderStateVersion != expectedRenderStateVersion)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
snapshot.versions = versions;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeSnapshotProvider::ApplyFrameContext(std::vector<RuntimeRenderState>& states, const RuntimeRenderFrameContext& frameContext) const
|
||||||
|
{
|
||||||
|
for (RuntimeRenderState& state : states)
|
||||||
|
{
|
||||||
|
state.timeSeconds = frameContext.timeSeconds;
|
||||||
|
state.utcTimeSeconds = frameContext.utcTimeSeconds;
|
||||||
|
state.utcOffsetSeconds = frameContext.utcOffsetSeconds;
|
||||||
|
state.startupRandom = frameContext.startupRandom;
|
||||||
|
state.frameCount = frameContext.frameCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeSnapshotProvider::ApplyFrameContext(RuntimeRenderStateSnapshot& snapshot, const RuntimeRenderFrameContext& frameContext) const
|
||||||
|
{
|
||||||
|
ApplyFrameContext(snapshot.states, frameContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RuntimeRenderState> RuntimeSnapshotProvider::GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const
|
||||||
|
{
|
||||||
|
return GetRenderStateSnapshot(outputWidth, outputHeight).states;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeSnapshotProvider::TryGetLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
RuntimeRenderStateSnapshot snapshot;
|
||||||
|
if (!TryGetRenderStateSnapshot(outputWidth, outputHeight, snapshot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
states = std::move(snapshot.states);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeSnapshotProvider::TryRefreshCachedLayerStates(std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
RuntimeRenderStateSnapshot snapshot;
|
||||||
|
snapshot.versions.renderStateVersion = mRuntimeHost.GetRenderStateVersion();
|
||||||
|
snapshot.versions.parameterStateVersion = mRuntimeHost.GetParameterStateVersion();
|
||||||
|
snapshot.states = states;
|
||||||
|
if (!TryRefreshSnapshotParameters(snapshot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
states = std::move(snapshot.states);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeSnapshotProvider::RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const
|
||||||
|
{
|
||||||
|
ApplyFrameContext(states, GetFrameContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t RuntimeSnapshotProvider::GetRenderStateVersion() const
|
||||||
|
{
|
||||||
|
return GetVersions().renderStateVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t RuntimeSnapshotProvider::GetParameterStateVersion() const
|
||||||
|
{
|
||||||
|
return GetVersions().parameterStateVersion;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RuntimeHost.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct RuntimeSnapshotVersions
|
||||||
|
{
|
||||||
|
uint64_t renderStateVersion = 0;
|
||||||
|
uint64_t parameterStateVersion = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RuntimeRenderFrameContext
|
||||||
|
{
|
||||||
|
double timeSeconds = 0.0;
|
||||||
|
double utcTimeSeconds = 0.0;
|
||||||
|
double utcOffsetSeconds = 0.0;
|
||||||
|
double startupRandom = 0.0;
|
||||||
|
double frameCount = 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RuntimeRenderStateSnapshot
|
||||||
|
{
|
||||||
|
RuntimeSnapshotVersions versions;
|
||||||
|
unsigned outputWidth = 0;
|
||||||
|
unsigned outputHeight = 0;
|
||||||
|
std::vector<RuntimeRenderState> states;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RuntimeSnapshotProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit RuntimeSnapshotProvider(RuntimeHost& runtimeHost);
|
||||||
|
|
||||||
|
bool BuildLayerPassFragmentShaderSources(const std::string& layerId, std::vector<ShaderPassBuildSource>& passSources, std::string& error) const;
|
||||||
|
RuntimeSnapshotVersions GetVersions() const;
|
||||||
|
RuntimeRenderFrameContext GetFrameContext() const;
|
||||||
|
RuntimeRenderStateSnapshot GetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight) const;
|
||||||
|
bool TryGetRenderStateSnapshot(unsigned outputWidth, unsigned outputHeight, RuntimeRenderStateSnapshot& snapshot) const;
|
||||||
|
bool TryRefreshSnapshotParameters(RuntimeRenderStateSnapshot& snapshot) const;
|
||||||
|
void ApplyFrameContext(std::vector<RuntimeRenderState>& states, const RuntimeRenderFrameContext& frameContext) const;
|
||||||
|
void ApplyFrameContext(RuntimeRenderStateSnapshot& snapshot, const RuntimeRenderFrameContext& frameContext) const;
|
||||||
|
|
||||||
|
std::vector<RuntimeRenderState> GetLayerRenderStates(unsigned outputWidth, unsigned outputHeight) const;
|
||||||
|
bool TryGetLayerRenderStates(unsigned outputWidth, unsigned outputHeight, std::vector<RuntimeRenderState>& states) const;
|
||||||
|
bool TryRefreshCachedLayerStates(std::vector<RuntimeRenderState>& states) const;
|
||||||
|
void RefreshDynamicRenderStateFields(std::vector<RuntimeRenderState>& states) const;
|
||||||
|
uint64_t GetRenderStateVersion() const;
|
||||||
|
uint64_t GetParameterStateVersion() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RuntimeHost& mRuntimeHost;
|
||||||
|
};
|
||||||
161
apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.cpp
Normal file
161
apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.cpp
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
#include "RuntimeStore.h"
|
||||||
|
|
||||||
|
RuntimeStore::RuntimeStore(RuntimeHost& runtimeHost) :
|
||||||
|
mRuntimeHost(runtimeHost)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::InitializeStore(std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.Initialize(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RuntimeStore::BuildPersistentStateJson() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.BuildStateJson();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::CreateStoredLayer(const std::string& shaderId, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.AddLayer(shaderId, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::DeleteStoredLayer(const std::string& layerId, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.RemoveLayer(layerId, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::MoveStoredLayer(const std::string& layerId, int direction, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.MoveLayer(layerId, direction, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.MoveLayerToIndex(layerId, targetIndex, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.SetLayerBypass(layerId, bypassed, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.SetLayerShader(layerId, shaderId, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.UpdateLayerParameter(layerId, parameterId, newValue, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.UpdateLayerParameterByControlKey(layerKey, parameterKey, newValue, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.UpdateLayerParameterByControlKey(layerKey, parameterKey, newValue, persistState, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::ResetStoredLayerParameterValues(const std::string& layerId, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.ResetLayerParameters(layerId, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.SaveStackPreset(presetName, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::LoadStackPresetSnapshot(const std::string& presetName, std::string& error)
|
||||||
|
{
|
||||||
|
return mRuntimeHost.LoadStackPreset(presetName, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path& RuntimeStore::GetRuntimeRepositoryRoot() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetRepoRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path& RuntimeStore::GetRuntimeUiRoot() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetUiRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path& RuntimeStore::GetRuntimeDocsRoot() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetDocsRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path& RuntimeStore::GetRuntimeDataRoot() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetRuntimeRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short RuntimeStore::GetConfiguredControlServerPort() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetServerPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short RuntimeStore::GetConfiguredOscPort() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetOscPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& RuntimeStore::GetConfiguredOscBindAddress() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetOscBindAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
double RuntimeStore::GetConfiguredOscSmoothing() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetOscSmoothing();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned RuntimeStore::GetConfiguredMaxTemporalHistoryFrames() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetMaxTemporalHistoryFrames();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned RuntimeStore::GetConfiguredPreviewFps() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetPreviewFps();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeStore::IsExternalKeyingConfigured() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.ExternalKeyingEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& RuntimeStore::GetConfiguredInputVideoFormat() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetInputVideoFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& RuntimeStore::GetConfiguredInputFrameRate() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetInputFrameRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& RuntimeStore::GetConfiguredOutputVideoFormat() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetOutputVideoFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& RuntimeStore::GetConfiguredOutputFrameRate() const
|
||||||
|
{
|
||||||
|
return mRuntimeHost.GetOutputFrameRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::SetCompileStatus(bool succeeded, const std::string& message)
|
||||||
|
{
|
||||||
|
mRuntimeHost.SetCompileStatus(succeeded, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RuntimeStore::ClearReloadRequest()
|
||||||
|
{
|
||||||
|
mRuntimeHost.ClearReloadRequest();
|
||||||
|
}
|
||||||
50
apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.h
Normal file
50
apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeStore.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RuntimeHost.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RuntimeStore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit RuntimeStore(RuntimeHost& runtimeHost);
|
||||||
|
|
||||||
|
bool InitializeStore(std::string& error);
|
||||||
|
std::string BuildPersistentStateJson() const;
|
||||||
|
|
||||||
|
bool CreateStoredLayer(const std::string& shaderId, std::string& error);
|
||||||
|
bool DeleteStoredLayer(const std::string& layerId, std::string& error);
|
||||||
|
bool MoveStoredLayer(const std::string& layerId, int direction, std::string& error);
|
||||||
|
bool MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error);
|
||||||
|
bool SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error);
|
||||||
|
bool SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error);
|
||||||
|
bool SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error);
|
||||||
|
bool SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error);
|
||||||
|
bool SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, std::string& error);
|
||||||
|
bool ResetStoredLayerParameterValues(const std::string& layerId, std::string& error);
|
||||||
|
bool SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const;
|
||||||
|
bool LoadStackPresetSnapshot(const std::string& presetName, std::string& error);
|
||||||
|
|
||||||
|
const std::filesystem::path& GetRuntimeRepositoryRoot() const;
|
||||||
|
const std::filesystem::path& GetRuntimeUiRoot() const;
|
||||||
|
const std::filesystem::path& GetRuntimeDocsRoot() const;
|
||||||
|
const std::filesystem::path& GetRuntimeDataRoot() const;
|
||||||
|
unsigned short GetConfiguredControlServerPort() const;
|
||||||
|
unsigned short GetConfiguredOscPort() const;
|
||||||
|
const std::string& GetConfiguredOscBindAddress() const;
|
||||||
|
double GetConfiguredOscSmoothing() const;
|
||||||
|
unsigned GetConfiguredMaxTemporalHistoryFrames() const;
|
||||||
|
unsigned GetConfiguredPreviewFps() const;
|
||||||
|
bool IsExternalKeyingConfigured() const;
|
||||||
|
const std::string& GetConfiguredInputVideoFormat() const;
|
||||||
|
const std::string& GetConfiguredInputFrameRate() const;
|
||||||
|
const std::string& GetConfiguredOutputVideoFormat() const;
|
||||||
|
const std::string& GetConfiguredOutputFrameRate() const;
|
||||||
|
|
||||||
|
void SetCompileStatus(bool succeeded, const std::string& message);
|
||||||
|
void ClearReloadRequest();
|
||||||
|
|
||||||
|
private:
|
||||||
|
RuntimeHost& mRuntimeHost;
|
||||||
|
};
|
||||||
175
apps/LoopThroughWithOpenGLCompositing/videoio/VideoBackend.cpp
Normal file
175
apps/LoopThroughWithOpenGLCompositing/videoio/VideoBackend.cpp
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
#include "VideoBackend.h"
|
||||||
|
|
||||||
|
#include "DeckLinkSession.h"
|
||||||
|
#include "OpenGLVideoIOBridge.h"
|
||||||
|
#include "RenderEngine.h"
|
||||||
|
#include "HealthTelemetry.h"
|
||||||
|
|
||||||
|
VideoBackend::VideoBackend(RenderEngine& renderEngine, HealthTelemetry& healthTelemetry) :
|
||||||
|
mVideoIODevice(std::make_unique<DeckLinkSession>()),
|
||||||
|
mBridge(std::make_unique<OpenGLVideoIOBridge>(*mVideoIODevice, renderEngine, healthTelemetry))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoBackend::~VideoBackend()
|
||||||
|
{
|
||||||
|
ReleaseResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBackend::ReleaseResources()
|
||||||
|
{
|
||||||
|
if (mVideoIODevice)
|
||||||
|
mVideoIODevice->ReleaseResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::DiscoverDevicesAndModes(const VideoFormatSelection& videoModes, std::string& error)
|
||||||
|
{
|
||||||
|
return mVideoIODevice->DiscoverDevicesAndModes(videoModes, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::SelectPreferredFormats(const VideoFormatSelection& videoModes, bool outputAlphaRequired, std::string& error)
|
||||||
|
{
|
||||||
|
return mVideoIODevice->SelectPreferredFormats(videoModes, outputAlphaRequired, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::ConfigureInput(const VideoFormat& inputVideoMode, std::string& error)
|
||||||
|
{
|
||||||
|
return mVideoIODevice->ConfigureInput(
|
||||||
|
[this](const VideoIOFrame& frame) { mBridge->VideoFrameArrived(frame); },
|
||||||
|
inputVideoMode,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::ConfigureOutput(const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error)
|
||||||
|
{
|
||||||
|
return mVideoIODevice->ConfigureOutput(
|
||||||
|
[this](const VideoIOCompletion& completion) { mBridge->PlayoutFrameCompleted(completion); },
|
||||||
|
outputVideoMode,
|
||||||
|
externalKeyingEnabled,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::Start()
|
||||||
|
{
|
||||||
|
return mVideoIODevice->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::Stop()
|
||||||
|
{
|
||||||
|
return mVideoIODevice->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const VideoIOState& VideoBackend::State() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->State();
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoIOState& VideoBackend::MutableState()
|
||||||
|
{
|
||||||
|
return mVideoIODevice->MutableState();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::BeginOutputFrame(VideoIOOutputFrame& frame)
|
||||||
|
{
|
||||||
|
return mVideoIODevice->BeginOutputFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBackend::EndOutputFrame(VideoIOOutputFrame& frame)
|
||||||
|
{
|
||||||
|
mVideoIODevice->EndOutputFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::ScheduleOutputFrame(const VideoIOOutputFrame& frame)
|
||||||
|
{
|
||||||
|
return mVideoIODevice->ScheduleOutputFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBackend::AccountForCompletionResult(VideoIOCompletionResult result)
|
||||||
|
{
|
||||||
|
mVideoIODevice->AccountForCompletionResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::HasInputDevice() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->HasInputDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::HasInputSource() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->HasInputSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned VideoBackend::InputFrameWidth() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->InputFrameWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned VideoBackend::InputFrameHeight() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->InputFrameHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned VideoBackend::OutputFrameWidth() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->OutputFrameWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned VideoBackend::OutputFrameHeight() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->OutputFrameHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned VideoBackend::CaptureTextureWidth() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->CaptureTextureWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned VideoBackend::OutputPackTextureWidth() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->OutputPackTextureWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoIOPixelFormat VideoBackend::InputPixelFormat() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->InputPixelFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& VideoBackend::InputDisplayModeName() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->InputDisplayModeName();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& VideoBackend::OutputModelName() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->OutputModelName();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::SupportsInternalKeying() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->SupportsInternalKeying();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::SupportsExternalKeying() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->SupportsExternalKeying();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::KeyerInterfaceAvailable() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->KeyerInterfaceAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoBackend::ExternalKeyingActive() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->ExternalKeyingActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& VideoBackend::StatusMessage() const
|
||||||
|
{
|
||||||
|
return mVideoIODevice->StatusMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBackend::SetStatusMessage(const std::string& message)
|
||||||
|
{
|
||||||
|
mVideoIODevice->SetStatusMessage(message);
|
||||||
|
}
|
||||||
55
apps/LoopThroughWithOpenGLCompositing/videoio/VideoBackend.h
Normal file
55
apps/LoopThroughWithOpenGLCompositing/videoio/VideoBackend.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "VideoIOTypes.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class HealthTelemetry;
|
||||||
|
class OpenGLVideoIOBridge;
|
||||||
|
class RenderEngine;
|
||||||
|
class VideoIODevice;
|
||||||
|
|
||||||
|
class VideoBackend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VideoBackend(RenderEngine& renderEngine, HealthTelemetry& healthTelemetry);
|
||||||
|
~VideoBackend();
|
||||||
|
|
||||||
|
void ReleaseResources();
|
||||||
|
bool DiscoverDevicesAndModes(const VideoFormatSelection& videoModes, std::string& error);
|
||||||
|
bool SelectPreferredFormats(const VideoFormatSelection& videoModes, bool outputAlphaRequired, std::string& error);
|
||||||
|
bool ConfigureInput(const VideoFormat& inputVideoMode, std::string& error);
|
||||||
|
bool ConfigureOutput(const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error);
|
||||||
|
bool Start();
|
||||||
|
bool Stop();
|
||||||
|
|
||||||
|
const VideoIOState& State() const;
|
||||||
|
VideoIOState& MutableState();
|
||||||
|
bool BeginOutputFrame(VideoIOOutputFrame& frame);
|
||||||
|
void EndOutputFrame(VideoIOOutputFrame& frame);
|
||||||
|
bool ScheduleOutputFrame(const VideoIOOutputFrame& frame);
|
||||||
|
void AccountForCompletionResult(VideoIOCompletionResult result);
|
||||||
|
|
||||||
|
bool HasInputDevice() const;
|
||||||
|
bool HasInputSource() const;
|
||||||
|
unsigned InputFrameWidth() const;
|
||||||
|
unsigned InputFrameHeight() const;
|
||||||
|
unsigned OutputFrameWidth() const;
|
||||||
|
unsigned OutputFrameHeight() const;
|
||||||
|
unsigned CaptureTextureWidth() const;
|
||||||
|
unsigned OutputPackTextureWidth() const;
|
||||||
|
VideoIOPixelFormat InputPixelFormat() const;
|
||||||
|
const std::string& InputDisplayModeName() const;
|
||||||
|
const std::string& OutputModelName() const;
|
||||||
|
bool SupportsInternalKeying() const;
|
||||||
|
bool SupportsExternalKeying() const;
|
||||||
|
bool KeyerInterfaceAvailable() const;
|
||||||
|
bool ExternalKeyingActive() const;
|
||||||
|
const std::string& StatusMessage() const;
|
||||||
|
void SetStatusMessage(const std::string& message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<VideoIODevice> mVideoIODevice;
|
||||||
|
std::unique_ptr<OpenGLVideoIOBridge> mBridge;
|
||||||
|
};
|
||||||
@@ -393,6 +393,8 @@ Suggested deliverables:
|
|||||||
- a short architecture diagram
|
- a short architecture diagram
|
||||||
- a responsibility table for each subsystem
|
- a responsibility table for each subsystem
|
||||||
- a list of allowed dependencies between subsystems
|
- a list of allowed dependencies between subsystems
|
||||||
|
- a dedicated Phase 1 design note:
|
||||||
|
- [PHASE_1_SUBSYSTEM_BOUNDARIES_DESIGN.md](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/docs/PHASE_1_SUBSYSTEM_BOUNDARIES_DESIGN.md)
|
||||||
|
|
||||||
### Phase 2. Introduce an internal event model
|
### Phase 2. Introduce an internal event model
|
||||||
|
|
||||||
|
|||||||
609
docs/PHASE_1_SUBSYSTEM_BOUNDARIES_DESIGN.md
Normal file
609
docs/PHASE_1_SUBSYSTEM_BOUNDARIES_DESIGN.md
Normal file
@@ -0,0 +1,609 @@
|
|||||||
|
# Phase 1 Design: Subsystem Boundaries and Target Architecture
|
||||||
|
|
||||||
|
This document expands Phase 1 of [ARCHITECTURE_RESILIENCE_REVIEW.md](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/docs/ARCHITECTURE_RESILIENCE_REVIEW.md) into a concrete target design. Its purpose is to define the long-term subsystem split before later phases introduce a full event model, split `RuntimeHost`, and move rendering onto a sole-owner render thread.
|
||||||
|
|
||||||
|
The main goal of Phase 1 is not to immediately rewrite the app. It is to establish clear ownership boundaries so later refactors all move toward the same architecture instead of solving local problems in conflicting ways.
|
||||||
|
|
||||||
|
## Why Phase 1 Exists
|
||||||
|
|
||||||
|
Today the app works, but too many responsibilities still converge in a few places:
|
||||||
|
|
||||||
|
- `RuntimeHost` owns persistence, live layer state, shader package access, status reporting, and mutation entrypoints.
|
||||||
|
- `OpenGLComposite` coordinates runtime setup, render state retrieval, shader rebuild handling, transient OSC overlay behavior, and video backend integration.
|
||||||
|
- DeckLink callback-driven playout still reaches directly into render-facing work.
|
||||||
|
- Background services rely on polling and shared mutable state more than explicit subsystem contracts.
|
||||||
|
|
||||||
|
Those are exactly the kinds of overlaps that make timing issues, state regressions, and recovery edge cases harder to solve cleanly.
|
||||||
|
|
||||||
|
Phase 1 creates a map for where each responsibility should eventually live.
|
||||||
|
|
||||||
|
## Design Goals
|
||||||
|
|
||||||
|
The target architecture should optimize for:
|
||||||
|
|
||||||
|
- live timing isolation
|
||||||
|
- explicit state ownership
|
||||||
|
- predictable recovery behavior
|
||||||
|
- clear boundaries between persistent state and transient live state
|
||||||
|
- easier testing of non-GL and non-hardware logic
|
||||||
|
- fewer cross-thread shared mutable objects
|
||||||
|
- a playout model that can evolve toward producer/consumer scheduling
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
|
||||||
|
Phase 1 does not itself require:
|
||||||
|
|
||||||
|
- replacing every direct call with events immediately
|
||||||
|
- moving all rendering to a new thread yet
|
||||||
|
- redesigning the shader contract again
|
||||||
|
- changing DeckLink behavior in place
|
||||||
|
- removing all existing classes before replacements exist
|
||||||
|
|
||||||
|
This phase is the target design and the dependency rules. Later phases perform the actual extraction.
|
||||||
|
|
||||||
|
## Current Pressure Points
|
||||||
|
|
||||||
|
The following current code paths are the strongest evidence for the split proposed here:
|
||||||
|
|
||||||
|
- `RuntimeHost` is both store and live authority:
|
||||||
|
- [RuntimeHost.h](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.h:15)
|
||||||
|
- [RuntimeHost.cpp](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/runtime/RuntimeHost.cpp:726)
|
||||||
|
- `OpenGLComposite` is both app orchestrator and render/runtime coordinator:
|
||||||
|
- [OpenGLComposite.cpp](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp:106)
|
||||||
|
- [OpenGLComposite.cpp](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/gl/OpenGLComposite.cpp:283)
|
||||||
|
- `RuntimeServices` mixes service orchestration with polling and deferred state work:
|
||||||
|
- [RuntimeServices.h](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.h:46)
|
||||||
|
- [RuntimeServices.cpp](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/control/RuntimeServices.cpp:194)
|
||||||
|
- Playout is still callback-coupled to render-facing work:
|
||||||
|
- [OpenGLVideoIOBridge.cpp](/c:/Users/Aiden/Documents/GitHub/video-shader-toys/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLVideoIOBridge.cpp:68)
|
||||||
|
|
||||||
|
## Target Subsystems
|
||||||
|
|
||||||
|
The long-term architecture should converge on six primary subsystems:
|
||||||
|
|
||||||
|
1. `RuntimeStore`
|
||||||
|
2. `RuntimeCoordinator`
|
||||||
|
3. `RuntimeSnapshotProvider`
|
||||||
|
4. `ControlServices`
|
||||||
|
5. `RenderEngine`
|
||||||
|
6. `VideoBackend`
|
||||||
|
7. `HealthTelemetry`
|
||||||
|
|
||||||
|
The split below is intentionally sharper than the current code. The point is to make ownership obvious.
|
||||||
|
|
||||||
|
## Subsystem Responsibilities
|
||||||
|
|
||||||
|
### `RuntimeStore`
|
||||||
|
|
||||||
|
`RuntimeStore` owns persisted and operator-authored state.
|
||||||
|
|
||||||
|
It is the source of truth for:
|
||||||
|
|
||||||
|
- runtime config loaded from disk
|
||||||
|
- persisted layer stack structure
|
||||||
|
- persisted parameter values
|
||||||
|
- stack preset serialization/deserialization
|
||||||
|
- shader/package metadata that must survive across renders
|
||||||
|
|
||||||
|
It should not be responsible for:
|
||||||
|
|
||||||
|
- render-thread timing
|
||||||
|
- GL resource lifetime
|
||||||
|
- live transient overlays
|
||||||
|
- hardware callback coordination
|
||||||
|
- UI/websocket broadcasting policy
|
||||||
|
|
||||||
|
Design rules:
|
||||||
|
|
||||||
|
- disk I/O belongs here or in its dedicated writer helper
|
||||||
|
- values here are authoritative for saved state
|
||||||
|
- writes may be debounced later, but the data model itself belongs here
|
||||||
|
|
||||||
|
### `RuntimeCoordinator`
|
||||||
|
|
||||||
|
`RuntimeCoordinator` is the mutation and policy layer.
|
||||||
|
|
||||||
|
It is responsible for:
|
||||||
|
|
||||||
|
- receiving valid mutation requests from controls, services, or automation
|
||||||
|
- validating requested changes against shader definitions and config rules
|
||||||
|
- resolving how persisted state, committed live state, and transient overlays should interact
|
||||||
|
- requesting snapshot publication when state changes affect render
|
||||||
|
- requesting persistence when stored state changes
|
||||||
|
|
||||||
|
It should not be responsible for:
|
||||||
|
|
||||||
|
- direct disk serialization details
|
||||||
|
- direct GL work
|
||||||
|
- hardware device lifecycle
|
||||||
|
- polling loops
|
||||||
|
|
||||||
|
Design rules:
|
||||||
|
|
||||||
|
- all non-render mutations should eventually flow through this layer
|
||||||
|
- this layer decides whether a change is persisted, transient, or both
|
||||||
|
- this layer owns state policy, not device policy
|
||||||
|
|
||||||
|
### `RuntimeSnapshotProvider`
|
||||||
|
|
||||||
|
`RuntimeSnapshotProvider` publishes render-facing snapshots.
|
||||||
|
|
||||||
|
It is responsible for:
|
||||||
|
|
||||||
|
- building immutable or near-immutable render snapshots
|
||||||
|
- translating runtime state into render-ready structures
|
||||||
|
- publishing versioned snapshots
|
||||||
|
- serving the render side without large mutable shared locks
|
||||||
|
|
||||||
|
It should not be responsible for:
|
||||||
|
|
||||||
|
- deciding whether a mutation is allowed
|
||||||
|
- directly applying UI/OSC requests
|
||||||
|
- persistence
|
||||||
|
- shader compilation orchestration
|
||||||
|
|
||||||
|
Design rules:
|
||||||
|
|
||||||
|
- render consumes snapshots, not live mutable store objects
|
||||||
|
- snapshots should be cheap to read and explicit about version changes
|
||||||
|
- dynamic frame-only values may still be attached later, but the snapshot shape should stay stable
|
||||||
|
|
||||||
|
### `ControlServices`
|
||||||
|
|
||||||
|
`ControlServices` is the ingress boundary for non-render control sources.
|
||||||
|
|
||||||
|
It is responsible for:
|
||||||
|
|
||||||
|
- OSC receive and route resolution
|
||||||
|
- REST/websocket/control UI ingress
|
||||||
|
- file-watch or reload request ingress
|
||||||
|
- translating external inputs into typed internal actions/events
|
||||||
|
- low-cost buffering/coalescing where appropriate
|
||||||
|
|
||||||
|
It should not be responsible for:
|
||||||
|
|
||||||
|
- persistence decisions
|
||||||
|
- render snapshot building
|
||||||
|
- hardware playout policy
|
||||||
|
- direct long-lived state ownership beyond ingress-specific queues
|
||||||
|
|
||||||
|
Design rules:
|
||||||
|
|
||||||
|
- external inputs enter here and are normalized before they touch core state
|
||||||
|
- service-specific timing concerns stay here unless they affect whole-app policy
|
||||||
|
- no service should directly mutate render-facing state structures
|
||||||
|
|
||||||
|
### `RenderEngine`
|
||||||
|
|
||||||
|
`RenderEngine` is the owner of live rendering behavior.
|
||||||
|
|
||||||
|
It is responsible for:
|
||||||
|
|
||||||
|
- sole ownership of GL work in the target architecture
|
||||||
|
- shader program lifecycle once compilation outputs are available
|
||||||
|
- texture upload scheduling
|
||||||
|
- render-pass execution
|
||||||
|
- temporal history and shader feedback resources
|
||||||
|
- transient render-only overlays
|
||||||
|
- preview production as a subordinate output
|
||||||
|
- output-frame production for the video backend
|
||||||
|
|
||||||
|
It should not be responsible for:
|
||||||
|
|
||||||
|
- persistence
|
||||||
|
- user-facing control normalization
|
||||||
|
- hardware discovery/configuration
|
||||||
|
- high-level runtime mutation policy
|
||||||
|
|
||||||
|
Design rules:
|
||||||
|
|
||||||
|
- render consumes snapshots plus render-local transient state
|
||||||
|
- render-local state is allowed if it stays render-local
|
||||||
|
- preview must be treated as best-effort relative to playout
|
||||||
|
|
||||||
|
### `VideoBackend`
|
||||||
|
|
||||||
|
`VideoBackend` owns input/output device lifecycle and playout policy.
|
||||||
|
|
||||||
|
It is responsible for:
|
||||||
|
|
||||||
|
- input device configuration and callbacks
|
||||||
|
- output device configuration and callbacks
|
||||||
|
- frame scheduling policy
|
||||||
|
- buffer-pool ownership
|
||||||
|
- playout headroom policy
|
||||||
|
- input signal status
|
||||||
|
- backend state transitions and recovery logic
|
||||||
|
|
||||||
|
It should not be responsible for:
|
||||||
|
|
||||||
|
- composing frames
|
||||||
|
- owning GL contexts long-term
|
||||||
|
- validating shader parameter changes
|
||||||
|
- persistence
|
||||||
|
|
||||||
|
Design rules:
|
||||||
|
|
||||||
|
- this subsystem is the consumer of rendered output frames, not the owner of frame composition policy
|
||||||
|
- it should evolve toward producer/consumer playout rather than callback-driven rendering
|
||||||
|
- backend state should be explicit and reportable
|
||||||
|
|
||||||
|
### `HealthTelemetry`
|
||||||
|
|
||||||
|
`HealthTelemetry` owns structured operational visibility.
|
||||||
|
|
||||||
|
It is responsible for:
|
||||||
|
|
||||||
|
- logging
|
||||||
|
- warning/error counters
|
||||||
|
- timing traces
|
||||||
|
- subsystem health state
|
||||||
|
- degraded-mode reporting
|
||||||
|
- operator-visible health summaries
|
||||||
|
|
||||||
|
It should not be responsible for:
|
||||||
|
|
||||||
|
- deciding core app behavior
|
||||||
|
- owning render or backend state
|
||||||
|
- persistence policy
|
||||||
|
|
||||||
|
Design rules:
|
||||||
|
|
||||||
|
- all major subsystems publish health information here
|
||||||
|
- health visibility should outlive UI connection state
|
||||||
|
- modal dialogs should not be the main operational surface
|
||||||
|
|
||||||
|
## Target Dependency Rules
|
||||||
|
|
||||||
|
The architecture should follow these rules as closely as possible.
|
||||||
|
|
||||||
|
Allowed dependency directions:
|
||||||
|
|
||||||
|
- `ControlServices -> RuntimeCoordinator`
|
||||||
|
- `RuntimeCoordinator -> RuntimeStore`
|
||||||
|
- `RuntimeCoordinator -> RuntimeSnapshotProvider`
|
||||||
|
- `RuntimeCoordinator -> HealthTelemetry`
|
||||||
|
- `RuntimeSnapshotProvider -> RuntimeStore`
|
||||||
|
- `RenderEngine -> RuntimeSnapshotProvider`
|
||||||
|
- `RenderEngine -> HealthTelemetry`
|
||||||
|
- `VideoBackend -> RenderEngine`
|
||||||
|
- `VideoBackend -> HealthTelemetry`
|
||||||
|
|
||||||
|
Conditionally allowed during migration:
|
||||||
|
|
||||||
|
- `ControlServices -> HealthTelemetry`
|
||||||
|
- `ControlServices -> RuntimeStore` only through temporary compatibility shims
|
||||||
|
|
||||||
|
Not allowed in the target design:
|
||||||
|
|
||||||
|
- `RenderEngine -> RuntimeStore`
|
||||||
|
- `RenderEngine -> ControlServices`
|
||||||
|
- `VideoBackend -> RuntimeStore`
|
||||||
|
- `ControlServices -> RenderEngine` for direct mutation
|
||||||
|
- `RuntimeStore -> RenderEngine`
|
||||||
|
- `HealthTelemetry -> any subsystem` for control flow
|
||||||
|
|
||||||
|
The key principle is:
|
||||||
|
|
||||||
|
- store owns durable data
|
||||||
|
- coordinator owns mutation policy
|
||||||
|
- snapshot provider owns render-facing state publication
|
||||||
|
- render owns live GPU execution
|
||||||
|
- backend owns device timing
|
||||||
|
- telemetry observes all of them
|
||||||
|
|
||||||
|
## State Ownership Model
|
||||||
|
|
||||||
|
The app has several different kinds of state, and Phase 1 should name them explicitly.
|
||||||
|
|
||||||
|
### Persisted State
|
||||||
|
|
||||||
|
Owned by `RuntimeStore`.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- layer stack structure
|
||||||
|
- selected shader ids
|
||||||
|
- saved parameter values
|
||||||
|
- runtime host config
|
||||||
|
- stack presets
|
||||||
|
|
||||||
|
### Committed Live State
|
||||||
|
|
||||||
|
Owned logically by `RuntimeCoordinator`, stored in the store or a live-state companion depending on future implementation.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- current operator-selected parameter values
|
||||||
|
- current bypass state
|
||||||
|
- current selected shader for each layer
|
||||||
|
|
||||||
|
This is state that should normally survive until explicitly changed and can be persisted if policy says so.
|
||||||
|
|
||||||
|
### Transient Live Overlay State
|
||||||
|
|
||||||
|
Owned by the subsystem that consumes it, not by the persisted store.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- active OSC overlay targets while automation is flowing
|
||||||
|
- shader feedback buffers
|
||||||
|
- temporal history textures
|
||||||
|
- queued input frames
|
||||||
|
- in-flight preview state
|
||||||
|
- playout queue state
|
||||||
|
|
||||||
|
This is where many current issues come from. The design rule is:
|
||||||
|
|
||||||
|
- transient state may influence output
|
||||||
|
- transient state should not masquerade as persisted truth
|
||||||
|
|
||||||
|
### Health and Timing State
|
||||||
|
|
||||||
|
Owned by `HealthTelemetry`.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- frame pacing stats
|
||||||
|
- render timing
|
||||||
|
- late/dropped frame counters
|
||||||
|
- queue depths
|
||||||
|
- warning states
|
||||||
|
|
||||||
|
## Target Runtime Flow
|
||||||
|
|
||||||
|
This section describes the intended long-term flow once later phases are in place.
|
||||||
|
|
||||||
|
### Control Mutation Flow
|
||||||
|
|
||||||
|
1. OSC/UI/file-watch input enters `ControlServices`.
|
||||||
|
2. `ControlServices` normalizes it into an internal action or event.
|
||||||
|
3. `RuntimeCoordinator` validates and classifies the action.
|
||||||
|
4. If the action changes durable state, `RuntimeStore` is updated.
|
||||||
|
5. If the action changes render-facing state, `RuntimeSnapshotProvider` publishes a new snapshot.
|
||||||
|
6. If the action requires persistence, a persistence request is queued.
|
||||||
|
7. Health/timing observations are emitted separately.
|
||||||
|
|
||||||
|
### Render Flow
|
||||||
|
|
||||||
|
1. `RenderEngine` consumes the latest published snapshot.
|
||||||
|
2. `RenderEngine` combines that snapshot with render-local transient state.
|
||||||
|
3. `RenderEngine` performs uploads, pass execution, feedback/history maintenance, and output production.
|
||||||
|
4. `RenderEngine` produces:
|
||||||
|
- preview-ready output
|
||||||
|
- video-backend-ready output frames
|
||||||
|
- render timing and warning signals
|
||||||
|
|
||||||
|
### Video Output Flow
|
||||||
|
|
||||||
|
Target long-term flow:
|
||||||
|
|
||||||
|
1. `RenderEngine` produces completed output frames ahead of demand.
|
||||||
|
2. `VideoBackend` consumes those frames from a bounded queue or ring buffer.
|
||||||
|
3. Device callbacks only drive dequeue/schedule/accounting behavior.
|
||||||
|
4. `HealthTelemetry` records queue depth, lateness, underruns, and recovery events.
|
||||||
|
|
||||||
|
### Reload / Shader Rebuild Flow
|
||||||
|
|
||||||
|
1. file-watch or manual reload enters through `ControlServices`
|
||||||
|
2. `RuntimeCoordinator` classifies the reload request
|
||||||
|
3. `RuntimeStore` and shader/package metadata are refreshed if needed
|
||||||
|
4. `RuntimeSnapshotProvider` republishes affected snapshot state
|
||||||
|
5. `RenderEngine` rebuilds render-local resources from the new snapshot/build outputs
|
||||||
|
|
||||||
|
The important boundary here is that reload is not "a render concern that also touches persistence." It is a coordinated runtime concern with a render-local execution phase.
|
||||||
|
|
||||||
|
## Suggested Public Interfaces
|
||||||
|
|
||||||
|
These are not final class signatures, but they show the shape the architecture should move toward.
|
||||||
|
|
||||||
|
### `RuntimeStore`
|
||||||
|
|
||||||
|
Core responsibilities:
|
||||||
|
|
||||||
|
- `LoadConfig()`
|
||||||
|
- `LoadPersistentState()`
|
||||||
|
- `SavePersistentStateSnapshot(...)`
|
||||||
|
- `GetStoredLayerStack()`
|
||||||
|
- `SetStoredLayerStack(...)`
|
||||||
|
- `GetStackPresetNames()`
|
||||||
|
- `SaveStackPreset(...)`
|
||||||
|
- `LoadStackPreset(...)`
|
||||||
|
|
||||||
|
### `RuntimeCoordinator`
|
||||||
|
|
||||||
|
Core responsibilities:
|
||||||
|
|
||||||
|
- `ApplyControlMutation(...)`
|
||||||
|
- `ApplyAutomationTarget(...)`
|
||||||
|
- `ResetLayer(...)`
|
||||||
|
- `RequestReload(...)`
|
||||||
|
- `CommitOverlayState(...)`
|
||||||
|
- `PublishSnapshotIfNeeded()`
|
||||||
|
- `RequestPersistenceIfNeeded()`
|
||||||
|
|
||||||
|
### `RuntimeSnapshotProvider`
|
||||||
|
|
||||||
|
Core responsibilities:
|
||||||
|
|
||||||
|
- `BuildSnapshot(...)`
|
||||||
|
- `GetLatestSnapshot()`
|
||||||
|
- `GetSnapshotVersion()`
|
||||||
|
- `PublishSnapshot(...)`
|
||||||
|
|
||||||
|
### `ControlServices`
|
||||||
|
|
||||||
|
Core responsibilities:
|
||||||
|
|
||||||
|
- `StartOscIngress(...)`
|
||||||
|
- `StartWebControlIngress(...)`
|
||||||
|
- `StartFileWatchIngress(...)`
|
||||||
|
- `EnqueueControlAction(...)`
|
||||||
|
- `DrainServiceEvents(...)`
|
||||||
|
|
||||||
|
### `RenderEngine`
|
||||||
|
|
||||||
|
Core responsibilities:
|
||||||
|
|
||||||
|
- `StartRenderLoop(...)`
|
||||||
|
- `ConsumeSnapshot(...)`
|
||||||
|
- `EnqueueInputFrame(...)`
|
||||||
|
- `ProduceOutputFrame(...)`
|
||||||
|
- `ResetRenderLocalState(...)`
|
||||||
|
- `HandleRebuildOutputs(...)`
|
||||||
|
|
||||||
|
### `VideoBackend`
|
||||||
|
|
||||||
|
Core responsibilities:
|
||||||
|
|
||||||
|
- `ConfigureInput(...)`
|
||||||
|
- `ConfigureOutput(...)`
|
||||||
|
- `StartPlayout(...)`
|
||||||
|
- `StopPlayout(...)`
|
||||||
|
- `ConsumeRenderedFrame(...)`
|
||||||
|
- `ReportBackendState(...)`
|
||||||
|
|
||||||
|
### `HealthTelemetry`
|
||||||
|
|
||||||
|
Core responsibilities:
|
||||||
|
|
||||||
|
- `RecordTimingSample(...)`
|
||||||
|
- `RecordCounterDelta(...)`
|
||||||
|
- `RaiseWarning(...)`
|
||||||
|
- `ClearWarning(...)`
|
||||||
|
- `AppendLogEntry(...)`
|
||||||
|
- `BuildHealthSnapshot()`
|
||||||
|
|
||||||
|
## Mapping From Current Code to Target Subsystems
|
||||||
|
|
||||||
|
This is not a one-to-one rename plan. It is a responsibility migration map.
|
||||||
|
|
||||||
|
### Current `RuntimeHost`
|
||||||
|
|
||||||
|
Should eventually split across:
|
||||||
|
|
||||||
|
- `RuntimeStore`
|
||||||
|
- `RuntimeCoordinator`
|
||||||
|
- `RuntimeSnapshotProvider`
|
||||||
|
- parts of `HealthTelemetry`
|
||||||
|
|
||||||
|
Likely examples:
|
||||||
|
|
||||||
|
- config loading/saving -> `RuntimeStore`
|
||||||
|
- layer stack mutation validation -> `RuntimeCoordinator`
|
||||||
|
- render state building/versioning -> `RuntimeSnapshotProvider`
|
||||||
|
- timing/status setters -> `HealthTelemetry`
|
||||||
|
|
||||||
|
### Current `RuntimeServices`
|
||||||
|
|
||||||
|
Should eventually become mostly:
|
||||||
|
|
||||||
|
- `ControlServices`
|
||||||
|
- a small service-hosting shell
|
||||||
|
|
||||||
|
Likely examples:
|
||||||
|
|
||||||
|
- OSC ingress/coalescing -> `ControlServices`
|
||||||
|
- file-watch ingress -> `ControlServices`
|
||||||
|
- deferred service coordination now done by polling -> split between `ControlServices` and event-driven coordinator calls
|
||||||
|
|
||||||
|
### Current `OpenGLComposite`
|
||||||
|
|
||||||
|
Should eventually split across:
|
||||||
|
|
||||||
|
- application bootstrap shell
|
||||||
|
- `RenderEngine`
|
||||||
|
- orchestration glue that wires subsystems together
|
||||||
|
|
||||||
|
Likely examples:
|
||||||
|
|
||||||
|
- render-pass facing code -> `RenderEngine`
|
||||||
|
- app/service/backend bootstrap -> composition root
|
||||||
|
- runtime mutation API surface -> coordinator-facing adapter, not render owner
|
||||||
|
|
||||||
|
### Current `OpenGLVideoIOBridge` and `DeckLinkSession`
|
||||||
|
|
||||||
|
Should eventually align more clearly under:
|
||||||
|
|
||||||
|
- `VideoBackend`
|
||||||
|
- `RenderEngine`
|
||||||
|
|
||||||
|
Likely examples:
|
||||||
|
|
||||||
|
- device callback and scheduling policy -> `VideoBackend`
|
||||||
|
- GL upload/readback/render work -> `RenderEngine`
|
||||||
|
|
||||||
|
## Architectural Guardrails
|
||||||
|
|
||||||
|
As later phases begin, these rules should be treated as guardrails.
|
||||||
|
|
||||||
|
### 1. No new cross-cutting state should be added to `RuntimeHost`
|
||||||
|
|
||||||
|
If a new feature needs durable state, place it conceptually under `RuntimeStore`.
|
||||||
|
If it needs render-local transient state, place it conceptually under `RenderEngine`.
|
||||||
|
If it needs timing/status counters, place it conceptually under `HealthTelemetry`.
|
||||||
|
|
||||||
|
### 2. Render-local state should stay render-local
|
||||||
|
|
||||||
|
Do not push shader feedback, temporal history, preview caches, or playout queues back into the store just to make them easy to reach from other systems.
|
||||||
|
|
||||||
|
### 3. Device callbacks should not become a dumping ground for app work
|
||||||
|
|
||||||
|
Callback threads should converge toward signaling and queue management, not core rendering, persistence, or control mutation.
|
||||||
|
|
||||||
|
### 4. Persistence should not be used as a control synchronization mechanism
|
||||||
|
|
||||||
|
Saving state is not how subsystems discover changes. Published snapshots and explicit events should handle that.
|
||||||
|
|
||||||
|
### 5. Health reporting should observe, not coordinate
|
||||||
|
|
||||||
|
Telemetry systems may record warnings and degraded states, but they should not become the hidden control plane for the app.
|
||||||
|
|
||||||
|
## Migration Strategy
|
||||||
|
|
||||||
|
Phase 1 is a design phase, but it should support incremental migration.
|
||||||
|
|
||||||
|
Recommended order after this document:
|
||||||
|
|
||||||
|
1. Introduce names and interfaces before moving logic.
|
||||||
|
2. Create compatibility adapters around `RuntimeHost` rather than forcing a flag day.
|
||||||
|
3. Move read-only render snapshot publication out before moving all mutation logic.
|
||||||
|
4. Move service ingress boundaries out before removing the old polling shell.
|
||||||
|
5. Isolate timing/health setters from the core store as early as practical.
|
||||||
|
|
||||||
|
This keeps progress measurable while reducing rewrite risk.
|
||||||
|
|
||||||
|
## Suggested Deliverables for Completing Phase 1
|
||||||
|
|
||||||
|
Phase 1 can reasonably be considered complete once the project has:
|
||||||
|
|
||||||
|
- this subsystem-boundary design document
|
||||||
|
- agreed subsystem names and responsibilities
|
||||||
|
- agreed allowed dependency directions
|
||||||
|
- explicit state categories: persisted, committed live, transient overlay, health/timing
|
||||||
|
- a current-to-target responsibility map for `RuntimeHost`, `RuntimeServices`, `OpenGLComposite`, and backend/render bridge code
|
||||||
|
- a decision that later phases will build against this target rather than inventing new boundaries ad hoc
|
||||||
|
|
||||||
|
## Open Questions For Later Phases
|
||||||
|
|
||||||
|
These do not block Phase 1, but they should remain visible.
|
||||||
|
|
||||||
|
- Should shader package registry ownership live entirely in `RuntimeStore`, or should compile-ready derived registry data move into the snapshot provider?
|
||||||
|
- Should committed live state be stored directly in `RuntimeStore`, or split into store plus live-session state owned by the coordinator?
|
||||||
|
- How much of shader build orchestration belongs to `RenderEngine` versus a separate build service?
|
||||||
|
- At what phase should preview become fully decoupled from playout cadence?
|
||||||
|
- Should persistence become its own `PersistenceWriter` subsystem in Phase 6, or remain an implementation detail under `RuntimeStore`?
|
||||||
|
|
||||||
|
## Short Version
|
||||||
|
|
||||||
|
Phase 1 should establish one simple rule for the rest of the refactor:
|
||||||
|
|
||||||
|
- durable state lives in the store
|
||||||
|
- mutation policy lives in the coordinator
|
||||||
|
- render-facing state is published as snapshots
|
||||||
|
- external control sources enter through services
|
||||||
|
- GL work belongs to render
|
||||||
|
- hardware pacing belongs to the backend
|
||||||
|
- health visibility belongs to telemetry
|
||||||
|
|
||||||
|
If later phases keep to that rule, the architecture will become materially more resilient without needing another round of foundational boundary changes.
|
||||||
Reference in New Issue
Block a user