Texture binding

This commit is contained in:
2026-05-08 17:04:28 +10:00
parent 7d8f9a39d1
commit f458eb0130
7 changed files with 181 additions and 78 deletions

View File

@@ -173,52 +173,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(layerProgram, sourceTexture, sourceHistoryTextures, temporalHistoryTextures);
mTextureBindings.BindRuntimeTexturePlan(texturePlan);
glBindVertexArray(mRenderer.FullscreenVertexArray()); glBindVertexArray(mRenderer.FullscreenVertexArray());
glUseProgram(layerProgram.program); glUseProgram(layerProgram.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"
@@ -51,8 +52,7 @@ private:
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

@@ -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

@@ -101,51 +101,24 @@ 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;
layerProgram.shaderTextureBase = mTextureBindings.ResolveShaderTextureBase(state, mRuntimeHost.GetMaxTemporalHistoryFrames());
layerProgram.textureBindings.swap(textureBindings);
layerProgram.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, layerProgram, 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;
layerProgram.shaderId = state.shaderId;
layerProgram.shaderTextureBase = shaderTextureBase;
layerProgram.program = newProgram.release(); layerProgram.program = newProgram.release();
layerProgram.vertexShader = newVertexShader.release(); layerProgram.vertexShader = newVertexShader.release();
layerProgram.fragmentShader = newFragmentShader.release(); layerProgram.fragmentShader = newFragmentShader.release();
layerProgram.textureBindings.swap(textureBindings);
layerProgram.textBindings.swap(textBindings);
return true; return true;
} }

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 LayerProgram& layerProgram, 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 < layerProgram.textureBindings.size(); ++index)
{
const GLint textureSamplerLocation = FindSamplerUniformLocation(program, layerProgram.textureBindings[index].samplerName);
if (textureSamplerLocation >= 0)
glUniform1i(textureSamplerLocation, static_cast<GLint>(shaderTextureBase + static_cast<GLuint>(index)));
}
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(layerProgram.textureBindings.size());
for (std::size_t index = 0; index < layerProgram.textBindings.size(); ++index)
{
const GLint textSamplerLocation = FindSamplerUniformLocation(program, layerProgram.textBindings[index].samplerName);
if (textSamplerLocation >= 0)
glUniform1i(textSamplerLocation, static_cast<GLint>(textTextureBase + static_cast<GLuint>(index)));
}
}
ShaderTextureBindings::RuntimeTextureBindingPlan ShaderTextureBindings::BuildLayerRuntimeBindingPlan(
const LayerProgram& layerProgram,
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 = layerProgram.shaderTextureBase != 0 ? layerProgram.shaderTextureBase : kSourceHistoryTextureUnitBase;
for (std::size_t index = 0; index < layerProgram.textureBindings.size(); ++index)
{
const LayerProgram::TextureBinding& textureBinding = layerProgram.textureBindings[index];
plan.bindings.push_back({
"shaderTexture",
textureBinding.samplerName,
textureBinding.texture,
shaderTextureBase + static_cast<GLuint>(index)
});
}
const GLuint textTextureBase = shaderTextureBase + static_cast<GLuint>(layerProgram.textureBindings.size());
for (std::size_t index = 0; index < layerProgram.textBindings.size(); ++index)
{
const LayerProgram::TextBinding& textBinding = layerProgram.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

@@ -11,8 +11,30 @@ class ShaderTextureBindings
public: public:
using LayerProgram = OpenGLRenderer::LayerProgram; using LayerProgram = OpenGLRenderer::LayerProgram;
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 LayerProgram& layerProgram, unsigned historyCap) const;
RuntimeTextureBindingPlan BuildLayerRuntimeBindingPlan(
const LayerProgram& layerProgram,
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;
}; };