diff --git a/CMakeLists.txt b/CMakeLists.txt
index a58323c..1f70d9c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,6 +64,7 @@ set(APP_SOURCES
"${APP_DIR}/gl/pipeline/OpenGLRenderPass.h"
"${APP_DIR}/gl/pipeline/OpenGLRenderPipeline.cpp"
"${APP_DIR}/gl/pipeline/OpenGLRenderPipeline.h"
+ "${APP_DIR}/gl/pipeline/RenderPassDescriptor.h"
"${APP_DIR}/gl/renderer/OpenGLRenderer.cpp"
"${APP_DIR}/gl/renderer/OpenGLRenderer.h"
"${APP_DIR}/gl/pipeline/OpenGLVideoIOBridge.cpp"
diff --git a/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj b/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj
index 65a2b9c..6f8b9ec 100644
--- a/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj
+++ b/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj
@@ -206,6 +206,7 @@
+
diff --git a/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj.filters b/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj.filters
index 151acb1..cae0ed3 100644
--- a/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj.filters
+++ b/apps/LoopThroughWithOpenGLCompositing/LoopThroughWithOpenGLCompositing.vcxproj.filters
@@ -92,6 +92,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.cpp
index 8c86fb9..510e662 100644
--- a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.cpp
+++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.cpp
@@ -43,26 +43,16 @@ void OpenGLRenderPass::Render(
}
else
{
- GLuint sourceTexture = mRenderer.DecodedTexture();
- GLuint sourceFrameBuffer = mRenderer.DecodeFramebuffer();
- for (std::size_t index = 0; index < layerStates.size() && index < layerPrograms.size(); ++index)
+ const std::vector passes = BuildLayerPassDescriptors(layerStates, layerPrograms);
+ for (const RenderPassDescriptor& pass : passes)
{
- const std::size_t remaining = layerStates.size() - index;
- const bool writeToMain = (remaining % 2) == 1;
- RenderShaderProgram(
- sourceTexture,
- writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer(),
- layerPrograms[index],
- layerStates[index],
+ RenderLayerPass(
+ pass,
inputFrameWidth,
inputFrameHeight,
historyCap,
updateTextBinding,
updateGlobalParams);
- if (layerStates[index].temporalHistorySource == TemporalHistorySource::PreLayerInput)
- mRenderer.TemporalHistory().PushPreLayerFramebuffer(layerStates[index].layerId, sourceFrameBuffer, inputFrameWidth, inputFrameHeight);
- sourceTexture = writeToMain ? mRenderer.CompositeTexture() : mRenderer.LayerTempTexture();
- sourceFrameBuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer();
}
}
@@ -97,6 +87,71 @@ void OpenGLRenderPass::RenderDecodePass(unsigned inputFrameWidth, unsigned input
glActiveTexture(GL_TEXTURE0);
}
+std::vector OpenGLRenderPass::BuildLayerPassDescriptors(
+ const std::vector& layerStates,
+ std::vector& layerPrograms) const
+{
+ std::vector passes;
+ const std::size_t passCount = layerStates.size() < layerPrograms.size() ? layerStates.size() : layerPrograms.size();
+ passes.reserve(passCount);
+
+ GLuint sourceTexture = mRenderer.DecodedTexture();
+ GLuint sourceFramebuffer = mRenderer.DecodeFramebuffer();
+ for (std::size_t index = 0; index < passCount; ++index)
+ {
+ const RuntimeRenderState& state = layerStates[index];
+ LayerProgram& layerProgram = layerPrograms[index];
+ const std::size_t remaining = layerStates.size() - index;
+ const bool writeToMain = (remaining % 2) == 1;
+
+ RenderPassDescriptor pass;
+ pass.kind = RenderPassKind::LayerEffect;
+ pass.outputTarget = writeToMain ? RenderPassOutputTarget::Composite : RenderPassOutputTarget::LayerTemp;
+ pass.passIndex = index;
+ pass.passId = state.layerId;
+ pass.layerId = state.layerId;
+ pass.shaderId = state.shaderId;
+ pass.sourceTexture = sourceTexture;
+ pass.sourceFramebuffer = sourceFramebuffer;
+ pass.destinationFramebuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer();
+ pass.layerProgram = &layerProgram;
+ pass.layerState = &state;
+ pass.capturePreLayerHistory = state.temporalHistorySource == TemporalHistorySource::PreLayerInput;
+ passes.push_back(pass);
+
+ sourceTexture = writeToMain ? mRenderer.CompositeTexture() : mRenderer.LayerTempTexture();
+ sourceFramebuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer();
+ }
+
+ return passes;
+}
+
+void OpenGLRenderPass::RenderLayerPass(
+ const RenderPassDescriptor& pass,
+ unsigned inputFrameWidth,
+ unsigned inputFrameHeight,
+ unsigned historyCap,
+ const TextBindingUpdater& updateTextBinding,
+ const GlobalParamsUpdater& updateGlobalParams)
+{
+ if (pass.layerProgram == nullptr || pass.layerState == nullptr)
+ return;
+
+ RenderShaderProgram(
+ pass.sourceTexture,
+ pass.destinationFramebuffer,
+ *pass.layerProgram,
+ *pass.layerState,
+ inputFrameWidth,
+ inputFrameHeight,
+ historyCap,
+ updateTextBinding,
+ updateGlobalParams);
+
+ if (pass.capturePreLayerHistory)
+ mRenderer.TemporalHistory().PushPreLayerFramebuffer(pass.layerId, pass.sourceFramebuffer, inputFrameWidth, inputFrameHeight);
+}
+
void OpenGLRenderPass::RenderShaderProgram(
GLuint sourceTexture,
GLuint destinationFrameBuffer,
diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.h b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.h
index 43beb39..18e7739 100644
--- a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.h
+++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.h
@@ -1,6 +1,7 @@
#pragma once
#include "OpenGLRenderer.h"
+#include "RenderPassDescriptor.h"
#include "ShaderTypes.h"
#include "VideoIOFormat.h"
@@ -30,6 +31,16 @@ public:
private:
void RenderDecodePass(unsigned inputFrameWidth, unsigned inputFrameHeight, unsigned captureTextureWidth, VideoIOPixelFormat inputPixelFormat);
+ std::vector BuildLayerPassDescriptors(
+ const std::vector& layerStates,
+ std::vector& layerPrograms) const;
+ void RenderLayerPass(
+ const RenderPassDescriptor& pass,
+ unsigned inputFrameWidth,
+ unsigned inputFrameHeight,
+ unsigned historyCap,
+ const TextBindingUpdater& updateTextBinding,
+ const GlobalParamsUpdater& updateGlobalParams);
void RenderShaderProgram(
GLuint sourceTexture,
GLuint destinationFrameBuffer,
diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/RenderPassDescriptor.h b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/RenderPassDescriptor.h
new file mode 100644
index 0000000..3e108bf
--- /dev/null
+++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/RenderPassDescriptor.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "OpenGLRenderer.h"
+#include "ShaderTypes.h"
+
+#include
+
+#include
+#include
+
+enum class RenderPassKind
+{
+ LayerEffect
+};
+
+enum class RenderPassOutputTarget
+{
+ LayerTemp,
+ Composite
+};
+
+struct RenderPassDescriptor
+{
+ RenderPassKind kind = RenderPassKind::LayerEffect;
+ RenderPassOutputTarget outputTarget = RenderPassOutputTarget::Composite;
+ std::size_t passIndex = 0;
+ std::string passId;
+ std::string layerId;
+ std::string shaderId;
+ GLuint sourceTexture = 0;
+ GLuint sourceFramebuffer = 0;
+ GLuint destinationFramebuffer = 0;
+ OpenGLRenderer::LayerProgram* layerProgram = nullptr;
+ const RuntimeRenderState* layerState = nullptr;
+ bool capturePreLayerHistory = false;
+};
diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/renderer/RenderTargetPool.h b/apps/LoopThroughWithOpenGLCompositing/gl/renderer/RenderTargetPool.h
new file mode 100644
index 0000000..1c0f1c1
--- /dev/null
+++ b/apps/LoopThroughWithOpenGLCompositing/gl/renderer/RenderTargetPool.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include
+
+#include
+#include
+
+enum class RenderTargetId
+{
+ Decoded,
+ LayerTemp,
+ Composite,
+ Output,
+ OutputPack,
+ Count
+};
+
+struct RenderTarget
+{
+ GLuint texture = 0;
+ GLuint framebuffer = 0;
+ unsigned width = 0;
+ unsigned height = 0;
+ GLenum internalFormat = GL_RGBA8;
+ GLenum pixelFormat = GL_RGBA;
+ GLenum pixelType = GL_UNSIGNED_BYTE;
+};
+
+class RenderTargetPool
+{
+public:
+ bool Create(
+ RenderTargetId id,
+ unsigned width,
+ unsigned height,
+ GLenum internalFormat,
+ GLenum pixelFormat,
+ GLenum pixelType,
+ const char* errorPrefix,
+ std::string& error);
+ void Destroy();
+
+ GLuint Texture(RenderTargetId id) const { return Target(id).texture; }
+ GLuint Framebuffer(RenderTargetId id) const { return Target(id).framebuffer; }
+ const RenderTarget& Target(RenderTargetId id) const;
+
+private:
+ static std::size_t TargetIndex(RenderTargetId id) { return static_cast(id); }
+
+ std::array(RenderTargetId::Count)> mTargets;
+};