2 Commits

Author SHA1 Message Date
87cb55b80b Layer program split
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m14s
CI / Windows Release Package (push) Successful in 2m26s
2026-05-08 17:10:29 +10:00
f458eb0130 Texture binding 2026-05-08 17:04:28 +10:00
11 changed files with 252 additions and 126 deletions

View File

@@ -101,6 +101,8 @@ std::vector<RenderPassDescriptor> OpenGLRenderPass::BuildLayerPassDescriptors(
{ {
const RuntimeRenderState& state = layerStates[index]; const RuntimeRenderState& state = layerStates[index];
LayerProgram& layerProgram = layerPrograms[index]; LayerProgram& layerProgram = layerPrograms[index];
if (layerProgram.passes.empty())
continue;
const std::size_t remaining = layerStates.size() - index; const std::size_t remaining = layerStates.size() - index;
const bool writeToMain = (remaining % 2) == 1; const bool writeToMain = (remaining % 2) == 1;
@@ -115,6 +117,7 @@ std::vector<RenderPassDescriptor> OpenGLRenderPass::BuildLayerPassDescriptors(
pass.sourceFramebuffer = sourceFramebuffer; pass.sourceFramebuffer = sourceFramebuffer;
pass.destinationFramebuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer(); pass.destinationFramebuffer = writeToMain ? mRenderer.CompositeFramebuffer() : mRenderer.LayerTempFramebuffer();
pass.layerProgram = &layerProgram; pass.layerProgram = &layerProgram;
pass.passProgram = &layerProgram.passes.front();
pass.layerState = &state; pass.layerState = &state;
pass.capturePreLayerHistory = state.temporalHistorySource == TemporalHistorySource::PreLayerInput; pass.capturePreLayerHistory = state.temporalHistorySource == TemporalHistorySource::PreLayerInput;
passes.push_back(pass); passes.push_back(pass);
@@ -134,13 +137,13 @@ void OpenGLRenderPass::RenderLayerPass(
const TextBindingUpdater& updateTextBinding, const TextBindingUpdater& updateTextBinding,
const GlobalParamsUpdater& updateGlobalParams) const GlobalParamsUpdater& updateGlobalParams)
{ {
if (pass.layerProgram == nullptr || pass.layerState == nullptr) if (pass.passProgram == nullptr || pass.layerState == nullptr)
return; return;
RenderShaderProgram( RenderShaderProgram(
pass.sourceTexture, pass.sourceTexture,
pass.destinationFramebuffer, pass.destinationFramebuffer,
*pass.layerProgram, *pass.passProgram,
*pass.layerState, *pass.layerState,
inputFrameWidth, inputFrameWidth,
inputFrameHeight, inputFrameHeight,
@@ -155,7 +158,7 @@ void OpenGLRenderPass::RenderLayerPass(
void OpenGLRenderPass::RenderShaderProgram( void OpenGLRenderPass::RenderShaderProgram(
GLuint sourceTexture, GLuint sourceTexture,
GLuint destinationFrameBuffer, GLuint destinationFrameBuffer,
LayerProgram& layerProgram, PassProgram& passProgram,
const RuntimeRenderState& state, const RuntimeRenderState& state,
unsigned inputFrameWidth, unsigned inputFrameWidth,
unsigned inputFrameHeight, unsigned inputFrameHeight,
@@ -163,7 +166,7 @@ void OpenGLRenderPass::RenderShaderProgram(
const TextBindingUpdater& updateTextBinding, const TextBindingUpdater& updateTextBinding,
const GlobalParamsUpdater& updateGlobalParams) const GlobalParamsUpdater& updateGlobalParams)
{ {
for (LayerProgram::TextBinding& textBinding : layerProgram.textBindings) for (LayerProgram::TextBinding& textBinding : passProgram.textBindings)
{ {
std::string textError; std::string textError;
if (!updateTextBinding(state, textBinding, textError)) if (!updateTextBinding(state, textBinding, textError))
@@ -173,52 +176,16 @@ void OpenGLRenderPass::RenderShaderProgram(
glBindFramebuffer(GL_FRAMEBUFFER, destinationFrameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, destinationFrameBuffer);
glViewport(0, 0, inputFrameWidth, inputFrameHeight); glViewport(0, 0, inputFrameWidth, inputFrameHeight);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0 + kDecodedVideoTextureUnit); const std::vector<GLuint> sourceHistoryTextures = mRenderer.TemporalHistory().ResolveSourceHistoryTextures(sourceTexture, state.isTemporal ? historyCap : 0);
glBindTexture(GL_TEXTURE_2D, sourceTexture); const std::vector<GLuint> temporalHistoryTextures = mRenderer.TemporalHistory().ResolveTemporalHistoryTextures(state, sourceTexture, state.isTemporal ? historyCap : 0);
mRenderer.TemporalHistory().BindSamplers(state, sourceTexture, historyCap); const ShaderTextureBindings::RuntimeTextureBindingPlan texturePlan =
BindLayerTextureAssets(layerProgram); mTextureBindings.BuildLayerRuntimeBindingPlan(passProgram, sourceTexture, sourceHistoryTextures, temporalHistoryTextures);
mTextureBindings.BindRuntimeTexturePlan(texturePlan);
glBindVertexArray(mRenderer.FullscreenVertexArray()); glBindVertexArray(mRenderer.FullscreenVertexArray());
glUseProgram(layerProgram.program); glUseProgram(passProgram.program);
updateGlobalParams(state, mRenderer.TemporalHistory().SourceAvailableCount(), mRenderer.TemporalHistory().AvailableCountForLayer(state.layerId)); updateGlobalParams(state, mRenderer.TemporalHistory().SourceAvailableCount(), mRenderer.TemporalHistory().AvailableCountForLayer(state.layerId));
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
glUseProgram(0); glUseProgram(0);
glBindVertexArray(0); glBindVertexArray(0);
UnbindLayerTextureAssets(layerProgram, historyCap); mTextureBindings.UnbindRuntimeTexturePlan(texturePlan);
}
void OpenGLRenderPass::BindLayerTextureAssets(const LayerProgram& layerProgram)
{
const GLuint shaderTextureBase = layerProgram.shaderTextureBase != 0 ? layerProgram.shaderTextureBase : kSourceHistoryTextureUnitBase;
for (std::size_t index = 0; index < layerProgram.textureBindings.size(); ++index)
{
glActiveTexture(GL_TEXTURE0 + shaderTextureBase + static_cast<GLuint>(index));
glBindTexture(GL_TEXTURE_2D, layerProgram.textureBindings[index].texture);
}
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(layerProgram.textureBindings.size());
for (std::size_t index = 0; index < layerProgram.textBindings.size(); ++index)
{
glActiveTexture(GL_TEXTURE0 + textTextureBase + static_cast<GLuint>(index));
glBindTexture(GL_TEXTURE_2D, layerProgram.textBindings[index].texture);
}
glActiveTexture(GL_TEXTURE0);
}
void OpenGLRenderPass::UnbindLayerTextureAssets(const LayerProgram& layerProgram, unsigned historyCap)
{
for (unsigned index = 0; index < historyCap; ++index)
{
glActiveTexture(GL_TEXTURE0 + kSourceHistoryTextureUnitBase + index);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0 + kSourceHistoryTextureUnitBase + historyCap + index);
glBindTexture(GL_TEXTURE_2D, 0);
}
const GLuint shaderTextureBase = layerProgram.shaderTextureBase != 0 ? layerProgram.shaderTextureBase : kSourceHistoryTextureUnitBase;
for (std::size_t index = 0; index < layerProgram.textureBindings.size() + layerProgram.textBindings.size(); ++index)
{
glActiveTexture(GL_TEXTURE0 + shaderTextureBase + static_cast<GLuint>(index));
glBindTexture(GL_TEXTURE_2D, 0);
}
glActiveTexture(GL_TEXTURE0 + kDecodedVideoTextureUnit);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
} }

View File

@@ -2,6 +2,7 @@
#include "OpenGLRenderer.h" #include "OpenGLRenderer.h"
#include "RenderPassDescriptor.h" #include "RenderPassDescriptor.h"
#include "ShaderTextureBindings.h"
#include "ShaderTypes.h" #include "ShaderTypes.h"
#include "VideoIOFormat.h" #include "VideoIOFormat.h"
@@ -13,6 +14,7 @@ class OpenGLRenderPass
{ {
public: public:
using LayerProgram = OpenGLRenderer::LayerProgram; using LayerProgram = OpenGLRenderer::LayerProgram;
using PassProgram = OpenGLRenderer::LayerProgram::PassProgram;
using TextBindingUpdater = std::function<bool(const RuntimeRenderState&, LayerProgram::TextBinding&, std::string&)>; using TextBindingUpdater = std::function<bool(const RuntimeRenderState&, LayerProgram::TextBinding&, std::string&)>;
using GlobalParamsUpdater = std::function<bool(const RuntimeRenderState&, unsigned, unsigned)>; using GlobalParamsUpdater = std::function<bool(const RuntimeRenderState&, unsigned, unsigned)>;
@@ -44,15 +46,14 @@ private:
void RenderShaderProgram( void RenderShaderProgram(
GLuint sourceTexture, GLuint sourceTexture,
GLuint destinationFrameBuffer, GLuint destinationFrameBuffer,
LayerProgram& layerProgram, PassProgram& passProgram,
const RuntimeRenderState& state, const RuntimeRenderState& state,
unsigned inputFrameWidth, unsigned inputFrameWidth,
unsigned inputFrameHeight, unsigned inputFrameHeight,
unsigned historyCap, unsigned historyCap,
const TextBindingUpdater& updateTextBinding, const TextBindingUpdater& updateTextBinding,
const GlobalParamsUpdater& updateGlobalParams); const GlobalParamsUpdater& updateGlobalParams);
void BindLayerTextureAssets(const LayerProgram& layerProgram);
void UnbindLayerTextureAssets(const LayerProgram& layerProgram, unsigned historyCap);
OpenGLRenderer& mRenderer; OpenGLRenderer& mRenderer;
ShaderTextureBindings mTextureBindings;
}; };

View File

@@ -31,6 +31,7 @@ struct RenderPassDescriptor
GLuint sourceFramebuffer = 0; GLuint sourceFramebuffer = 0;
GLuint destinationFramebuffer = 0; GLuint destinationFramebuffer = 0;
OpenGLRenderer::LayerProgram* layerProgram = nullptr; OpenGLRenderer::LayerProgram* layerProgram = nullptr;
OpenGLRenderer::LayerProgram::PassProgram* passProgram = nullptr;
const RuntimeRenderState* layerState = nullptr; const RuntimeRenderState* layerState = nullptr;
bool capturePreLayerHistory = false; bool capturePreLayerHistory = false;
}; };

View File

@@ -212,6 +212,29 @@ void TemporalHistoryBuffers::BindSamplers(const RuntimeRenderState& state, GLuin
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} }
std::vector<GLuint> TemporalHistoryBuffers::ResolveSourceHistoryTextures(GLuint fallbackTexture, unsigned historyCap) const
{
std::vector<GLuint> textures;
textures.reserve(historyCap);
for (unsigned index = 0; index < historyCap; ++index)
textures.push_back(ResolveTexture(sourceHistoryRing, fallbackTexture, index));
return textures;
}
std::vector<GLuint> TemporalHistoryBuffers::ResolveTemporalHistoryTextures(const RuntimeRenderState& state, GLuint fallbackTexture, unsigned historyCap) const
{
const Ring* temporalRing = nullptr;
auto it = preLayerHistoryByLayerId.find(state.layerId);
if (it != preLayerHistoryByLayerId.end())
temporalRing = &it->second;
std::vector<GLuint> textures;
textures.reserve(historyCap);
for (unsigned index = 0; index < historyCap; ++index)
textures.push_back(temporalRing ? ResolveTexture(*temporalRing, fallbackTexture, index) : fallbackTexture);
return textures;
}
GLuint TemporalHistoryBuffers::ResolveTexture(const Ring& ring, GLuint fallbackTexture, std::size_t framesAgo) const GLuint TemporalHistoryBuffers::ResolveTexture(const Ring& ring, GLuint fallbackTexture, std::size_t framesAgo) const
{ {
if (ring.filledCount == 0 || ring.slots.empty()) if (ring.filledCount == 0 || ring.slots.empty())

View File

@@ -40,6 +40,8 @@ public:
void PushSourceFramebuffer(GLuint sourceFramebuffer, unsigned frameWidth, unsigned frameHeight); void PushSourceFramebuffer(GLuint sourceFramebuffer, unsigned frameWidth, unsigned frameHeight);
void PushPreLayerFramebuffer(const std::string& layerId, GLuint sourceFramebuffer, unsigned frameWidth, unsigned frameHeight); void PushPreLayerFramebuffer(const std::string& layerId, GLuint sourceFramebuffer, unsigned frameWidth, unsigned frameHeight);
void BindSamplers(const RuntimeRenderState& state, GLuint currentSourceTexture, unsigned historyCap); void BindSamplers(const RuntimeRenderState& state, GLuint currentSourceTexture, unsigned historyCap);
std::vector<GLuint> ResolveSourceHistoryTextures(GLuint fallbackTexture, unsigned historyCap) const;
std::vector<GLuint> ResolveTemporalHistoryTextures(const RuntimeRenderState& state, GLuint fallbackTexture, unsigned historyCap) const;
GLuint ResolveTexture(const Ring& ring, GLuint fallbackTexture, std::size_t framesAgo) const; GLuint ResolveTexture(const Ring& ring, GLuint fallbackTexture, std::size_t framesAgo) const;
unsigned SourceAvailableCount() const; unsigned SourceAvailableCount() const;
unsigned AvailableCountForLayer(const std::string& layerId) const; unsigned AvailableCountForLayer(const std::string& layerId) const;

View File

@@ -155,43 +155,47 @@ void OpenGLRenderer::DestroyResources()
void OpenGLRenderer::DestroySingleLayerProgram(LayerProgram& layerProgram) void OpenGLRenderer::DestroySingleLayerProgram(LayerProgram& layerProgram)
{ {
for (LayerProgram::TextureBinding& binding : layerProgram.textureBindings) for (LayerProgram::PassProgram& passProgram : layerProgram.passes)
{ {
if (binding.texture != 0) for (LayerProgram::TextureBinding& binding : passProgram.textureBindings)
{ {
glDeleteTextures(1, &binding.texture); if (binding.texture != 0)
binding.texture = 0; {
glDeleteTextures(1, &binding.texture);
binding.texture = 0;
}
}
passProgram.textureBindings.clear();
for (LayerProgram::TextBinding& binding : passProgram.textBindings)
{
if (binding.texture != 0)
{
glDeleteTextures(1, &binding.texture);
binding.texture = 0;
}
}
passProgram.textBindings.clear();
if (passProgram.program != 0)
{
glDeleteProgram(passProgram.program);
passProgram.program = 0;
}
if (passProgram.fragmentShader != 0)
{
glDeleteShader(passProgram.fragmentShader);
passProgram.fragmentShader = 0;
}
if (passProgram.vertexShader != 0)
{
glDeleteShader(passProgram.vertexShader);
passProgram.vertexShader = 0;
} }
} }
layerProgram.textureBindings.clear(); layerProgram.passes.clear();
for (LayerProgram::TextBinding& binding : layerProgram.textBindings)
{
if (binding.texture != 0)
{
glDeleteTextures(1, &binding.texture);
binding.texture = 0;
}
}
layerProgram.textBindings.clear();
if (layerProgram.program != 0)
{
glDeleteProgram(layerProgram.program);
layerProgram.program = 0;
}
if (layerProgram.fragmentShader != 0)
{
glDeleteShader(layerProgram.fragmentShader);
layerProgram.fragmentShader = 0;
}
if (layerProgram.vertexShader != 0)
{
glDeleteShader(layerProgram.vertexShader);
layerProgram.vertexShader = 0;
}
} }
void OpenGLRenderer::DestroyLayerPrograms() void OpenGLRenderer::DestroyLayerPrograms()

View File

@@ -37,12 +37,19 @@ public:
std::string layerId; std::string layerId;
std::string shaderId; std::string shaderId;
GLuint shaderTextureBase = 0;
GLuint program = 0; struct PassProgram
GLuint vertexShader = 0; {
GLuint fragmentShader = 0; std::string passId;
std::vector<TextureBinding> textureBindings; GLuint shaderTextureBase = 0;
std::vector<TextBinding> textBindings; GLuint program = 0;
GLuint vertexShader = 0;
GLuint fragmentShader = 0;
std::vector<TextureBinding> textureBindings;
std::vector<TextBinding> textBindings;
};
std::vector<PassProgram> passes;
}; };
GLuint CaptureTexture() const { return mCaptureTexture; } GLuint CaptureTexture() const { return mCaptureTexture; }

View File

@@ -5,6 +5,7 @@
#include "GlShaderSources.h" #include "GlShaderSources.h"
#include <cstring> #include <cstring>
#include <utility>
#include <vector> #include <vector>
namespace namespace
@@ -101,51 +102,28 @@ bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState
std::vector<LayerProgram::TextBinding> textBindings; std::vector<LayerProgram::TextBinding> textBindings;
mTextureBindings.CreateTextBindings(state, textBindings); mTextureBindings.CreateTextBindings(state, textBindings);
layerProgram.layerId = state.layerId;
layerProgram.shaderId = state.shaderId;
PassProgram passProgram;
passProgram.passId = "main";
passProgram.shaderTextureBase = mTextureBindings.ResolveShaderTextureBase(state, mRuntimeHost.GetMaxTemporalHistoryFrames());
passProgram.textureBindings.swap(textureBindings);
passProgram.textBindings.swap(textBindings);
const GLuint globalParamsIndex = glGetUniformBlockIndex(newProgram.get(), "GlobalParams"); const GLuint globalParamsIndex = glGetUniformBlockIndex(newProgram.get(), "GlobalParams");
if (globalParamsIndex != GL_INVALID_INDEX) if (globalParamsIndex != GL_INVALID_INDEX)
glUniformBlockBinding(newProgram.get(), globalParamsIndex, kGlobalParamsBindingPoint); glUniformBlockBinding(newProgram.get(), globalParamsIndex, kGlobalParamsBindingPoint);
const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames(); const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames();
const GLuint shaderTextureBase = state.isTemporal ? kSourceHistoryTextureUnitBase + historyCap + historyCap : kSourceHistoryTextureUnitBase;
glUseProgram(newProgram.get()); glUseProgram(newProgram.get());
const GLint videoInputLocation = glGetUniformLocation(newProgram.get(), "gVideoInput"); mTextureBindings.AssignLayerSamplerUniforms(newProgram.get(), state, passProgram, historyCap);
if (videoInputLocation >= 0)
glUniform1i(videoInputLocation, static_cast<GLint>(kDecodedVideoTextureUnit));
for (unsigned index = 0; index < historyCap; ++index)
{
const std::string sourceSamplerName = "gSourceHistory" + std::to_string(index);
const GLint sourceSamplerLocation = glGetUniformLocation(newProgram.get(), sourceSamplerName.c_str());
if (sourceSamplerLocation >= 0)
glUniform1i(sourceSamplerLocation, static_cast<GLint>(kSourceHistoryTextureUnitBase + index));
const std::string temporalSamplerName = "gTemporalHistory" + std::to_string(index);
const GLint temporalSamplerLocation = glGetUniformLocation(newProgram.get(), temporalSamplerName.c_str());
if (temporalSamplerLocation >= 0)
glUniform1i(temporalSamplerLocation, static_cast<GLint>(kSourceHistoryTextureUnitBase + historyCap + index));
}
for (std::size_t index = 0; index < textureBindings.size(); ++index)
{
const GLint textureSamplerLocation = mTextureBindings.FindSamplerUniformLocation(newProgram.get(), textureBindings[index].samplerName);
if (textureSamplerLocation >= 0)
glUniform1i(textureSamplerLocation, static_cast<GLint>(shaderTextureBase + static_cast<GLuint>(index)));
}
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(textureBindings.size());
for (std::size_t index = 0; index < textBindings.size(); ++index)
{
const GLint textSamplerLocation = mTextureBindings.FindSamplerUniformLocation(newProgram.get(), textBindings[index].samplerName);
if (textSamplerLocation >= 0)
glUniform1i(textSamplerLocation, static_cast<GLint>(textTextureBase + static_cast<GLuint>(index)));
}
glUseProgram(0); glUseProgram(0);
layerProgram.layerId = state.layerId; passProgram.program = newProgram.release();
layerProgram.shaderId = state.shaderId; passProgram.vertexShader = newVertexShader.release();
layerProgram.shaderTextureBase = shaderTextureBase; passProgram.fragmentShader = newFragmentShader.release();
layerProgram.program = newProgram.release(); layerProgram.passes.push_back(std::move(passProgram));
layerProgram.vertexShader = newVertexShader.release();
layerProgram.fragmentShader = newFragmentShader.release();
layerProgram.textureBindings.swap(textureBindings);
layerProgram.textBindings.swap(textBindings);
return true; return true;
} }

View File

@@ -10,6 +10,7 @@ class ShaderProgramCompiler
{ {
public: public:
using LayerProgram = OpenGLRenderer::LayerProgram; using LayerProgram = OpenGLRenderer::LayerProgram;
using PassProgram = OpenGLRenderer::LayerProgram::PassProgram;
ShaderProgramCompiler(OpenGLRenderer& renderer, RuntimeHost& runtimeHost, ShaderTextureBindings& textureBindings); ShaderProgramCompiler(OpenGLRenderer& renderer, RuntimeHost& runtimeHost, ShaderTextureBindings& textureBindings);

View File

@@ -102,3 +102,122 @@ GLint ShaderTextureBindings::FindSamplerUniformLocation(GLuint program, const st
return location; return location;
return glGetUniformLocation(program, (samplerName + "_0").c_str()); return glGetUniformLocation(program, (samplerName + "_0").c_str());
} }
GLuint ShaderTextureBindings::ResolveShaderTextureBase(const RuntimeRenderState& state, unsigned historyCap) const
{
return state.isTemporal ? kSourceHistoryTextureUnitBase + historyCap + historyCap : kSourceHistoryTextureUnitBase;
}
void ShaderTextureBindings::AssignLayerSamplerUniforms(GLuint program, const RuntimeRenderState& state, const PassProgram& passProgram, unsigned historyCap) const
{
const GLuint shaderTextureBase = ResolveShaderTextureBase(state, historyCap);
const GLint videoInputLocation = glGetUniformLocation(program, "gVideoInput");
if (videoInputLocation >= 0)
glUniform1i(videoInputLocation, static_cast<GLint>(kDecodedVideoTextureUnit));
for (unsigned index = 0; index < historyCap; ++index)
{
const std::string sourceSamplerName = "gSourceHistory" + std::to_string(index);
const GLint sourceSamplerLocation = glGetUniformLocation(program, sourceSamplerName.c_str());
if (sourceSamplerLocation >= 0)
glUniform1i(sourceSamplerLocation, static_cast<GLint>(kSourceHistoryTextureUnitBase + index));
const std::string temporalSamplerName = "gTemporalHistory" + std::to_string(index);
const GLint temporalSamplerLocation = glGetUniformLocation(program, temporalSamplerName.c_str());
if (temporalSamplerLocation >= 0)
glUniform1i(temporalSamplerLocation, static_cast<GLint>(kSourceHistoryTextureUnitBase + historyCap + index));
}
for (std::size_t index = 0; index < passProgram.textureBindings.size(); ++index)
{
const GLint textureSamplerLocation = FindSamplerUniformLocation(program, passProgram.textureBindings[index].samplerName);
if (textureSamplerLocation >= 0)
glUniform1i(textureSamplerLocation, static_cast<GLint>(shaderTextureBase + static_cast<GLuint>(index)));
}
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(passProgram.textureBindings.size());
for (std::size_t index = 0; index < passProgram.textBindings.size(); ++index)
{
const GLint textSamplerLocation = FindSamplerUniformLocation(program, passProgram.textBindings[index].samplerName);
if (textSamplerLocation >= 0)
glUniform1i(textSamplerLocation, static_cast<GLint>(textTextureBase + static_cast<GLuint>(index)));
}
}
ShaderTextureBindings::RuntimeTextureBindingPlan ShaderTextureBindings::BuildLayerRuntimeBindingPlan(
const PassProgram& passProgram,
GLuint layerInputTexture,
const std::vector<GLuint>& sourceHistoryTextures,
const std::vector<GLuint>& temporalHistoryTextures) const
{
RuntimeTextureBindingPlan plan;
plan.bindings.push_back({ "layerInput", "gVideoInput", layerInputTexture, kDecodedVideoTextureUnit });
for (std::size_t index = 0; index < sourceHistoryTextures.size(); ++index)
{
plan.bindings.push_back({
"sourceHistory",
"gSourceHistory" + std::to_string(index),
sourceHistoryTextures[index],
kSourceHistoryTextureUnitBase + static_cast<GLuint>(index)
});
}
const GLuint temporalBase = kSourceHistoryTextureUnitBase + static_cast<GLuint>(sourceHistoryTextures.size());
for (std::size_t index = 0; index < temporalHistoryTextures.size(); ++index)
{
plan.bindings.push_back({
"temporalHistory",
"gTemporalHistory" + std::to_string(index),
temporalHistoryTextures[index],
temporalBase + static_cast<GLuint>(index)
});
}
const GLuint shaderTextureBase = passProgram.shaderTextureBase != 0 ? passProgram.shaderTextureBase : kSourceHistoryTextureUnitBase;
for (std::size_t index = 0; index < passProgram.textureBindings.size(); ++index)
{
const LayerProgram::TextureBinding& textureBinding = passProgram.textureBindings[index];
plan.bindings.push_back({
"shaderTexture",
textureBinding.samplerName,
textureBinding.texture,
shaderTextureBase + static_cast<GLuint>(index)
});
}
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(passProgram.textureBindings.size());
for (std::size_t index = 0; index < passProgram.textBindings.size(); ++index)
{
const LayerProgram::TextBinding& textBinding = passProgram.textBindings[index];
plan.bindings.push_back({
"textTexture",
textBinding.samplerName,
textBinding.texture,
textTextureBase + static_cast<GLuint>(index)
});
}
return plan;
}
void ShaderTextureBindings::BindRuntimeTexturePlan(const RuntimeTextureBindingPlan& plan) const
{
for (const RuntimeTextureBinding& binding : plan.bindings)
{
glActiveTexture(GL_TEXTURE0 + binding.textureUnit);
glBindTexture(GL_TEXTURE_2D, binding.texture);
}
glActiveTexture(GL_TEXTURE0);
}
void ShaderTextureBindings::UnbindRuntimeTexturePlan(const RuntimeTextureBindingPlan& plan) const
{
for (const RuntimeTextureBinding& binding : plan.bindings)
{
glActiveTexture(GL_TEXTURE0 + binding.textureUnit);
glBindTexture(GL_TEXTURE_2D, 0);
}
glActiveTexture(GL_TEXTURE0);
}

View File

@@ -10,9 +10,32 @@ class ShaderTextureBindings
{ {
public: public:
using LayerProgram = OpenGLRenderer::LayerProgram; using LayerProgram = OpenGLRenderer::LayerProgram;
using PassProgram = OpenGLRenderer::LayerProgram::PassProgram;
struct RuntimeTextureBinding
{
std::string semanticName;
std::string samplerName;
GLuint texture = 0;
GLuint textureUnit = 0;
};
struct RuntimeTextureBindingPlan
{
std::vector<RuntimeTextureBinding> bindings;
};
bool LoadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error); bool LoadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error);
void CreateTextBindings(const RuntimeRenderState& state, std::vector<LayerProgram::TextBinding>& textBindings); void CreateTextBindings(const RuntimeRenderState& state, std::vector<LayerProgram::TextBinding>& textBindings);
bool UpdateTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error); bool UpdateTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error);
GLint FindSamplerUniformLocation(GLuint program, const std::string& samplerName) const; GLint FindSamplerUniformLocation(GLuint program, const std::string& samplerName) const;
GLuint ResolveShaderTextureBase(const RuntimeRenderState& state, unsigned historyCap) const;
void AssignLayerSamplerUniforms(GLuint program, const RuntimeRenderState& state, const PassProgram& passProgram, unsigned historyCap) const;
RuntimeTextureBindingPlan BuildLayerRuntimeBindingPlan(
const PassProgram& passProgram,
GLuint layerInputTexture,
const std::vector<GLuint>& sourceHistoryTextures,
const std::vector<GLuint>& temporalHistoryTextures) const;
void BindRuntimeTexturePlan(const RuntimeTextureBindingPlan& plan) const;
void UnbindRuntimeTexturePlan(const RuntimeTextureBindingPlan& plan) const;
}; };