From f458eb013016ca312ec52f7a94a0007daeebd3c9 Mon Sep 17 00:00:00 2001 From: Aiden Date: Fri, 8 May 2026 17:04:28 +1000 Subject: [PATCH] Texture binding --- .../gl/pipeline/OpenGLRenderPass.cpp | 48 +------ .../gl/pipeline/OpenGLRenderPass.h | 4 +- .../gl/pipeline/TemporalHistoryBuffers.cpp | 23 ++++ .../gl/pipeline/TemporalHistoryBuffers.h | 2 + .../gl/shader/ShaderProgramCompiler.cpp | 41 ++---- .../gl/shader/ShaderTextureBindings.cpp | 119 ++++++++++++++++++ .../gl/shader/ShaderTextureBindings.h | 22 ++++ 7 files changed, 181 insertions(+), 78 deletions(-) diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.cpp index 510e662..4c40fec 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.cpp @@ -173,52 +173,16 @@ void OpenGLRenderPass::RenderShaderProgram( glBindFramebuffer(GL_FRAMEBUFFER, destinationFrameBuffer); glViewport(0, 0, inputFrameWidth, inputFrameHeight); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glActiveTexture(GL_TEXTURE0 + kDecodedVideoTextureUnit); - glBindTexture(GL_TEXTURE_2D, sourceTexture); - mRenderer.TemporalHistory().BindSamplers(state, sourceTexture, historyCap); - BindLayerTextureAssets(layerProgram); + const std::vector sourceHistoryTextures = mRenderer.TemporalHistory().ResolveSourceHistoryTextures(sourceTexture, state.isTemporal ? historyCap : 0); + const std::vector temporalHistoryTextures = mRenderer.TemporalHistory().ResolveTemporalHistoryTextures(state, sourceTexture, state.isTemporal ? historyCap : 0); + const ShaderTextureBindings::RuntimeTextureBindingPlan texturePlan = + mTextureBindings.BuildLayerRuntimeBindingPlan(layerProgram, sourceTexture, sourceHistoryTextures, temporalHistoryTextures); + mTextureBindings.BindRuntimeTexturePlan(texturePlan); glBindVertexArray(mRenderer.FullscreenVertexArray()); glUseProgram(layerProgram.program); updateGlobalParams(state, mRenderer.TemporalHistory().SourceAvailableCount(), mRenderer.TemporalHistory().AvailableCountForLayer(state.layerId)); glDrawArrays(GL_TRIANGLES, 0, 3); glUseProgram(0); glBindVertexArray(0); - UnbindLayerTextureAssets(layerProgram, historyCap); -} - -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(index)); - glBindTexture(GL_TEXTURE_2D, layerProgram.textureBindings[index].texture); - } - const GLuint textTextureBase = shaderTextureBase + static_cast(layerProgram.textureBindings.size()); - for (std::size_t index = 0; index < layerProgram.textBindings.size(); ++index) - { - glActiveTexture(GL_TEXTURE0 + textTextureBase + static_cast(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(index)); - glBindTexture(GL_TEXTURE_2D, 0); - } - glActiveTexture(GL_TEXTURE0 + kDecodedVideoTextureUnit); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); + mTextureBindings.UnbindRuntimeTexturePlan(texturePlan); } diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.h b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.h index 18e7739..7262acc 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.h +++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/OpenGLRenderPass.h @@ -2,6 +2,7 @@ #include "OpenGLRenderer.h" #include "RenderPassDescriptor.h" +#include "ShaderTextureBindings.h" #include "ShaderTypes.h" #include "VideoIOFormat.h" @@ -51,8 +52,7 @@ private: unsigned historyCap, const TextBindingUpdater& updateTextBinding, const GlobalParamsUpdater& updateGlobalParams); - void BindLayerTextureAssets(const LayerProgram& layerProgram); - void UnbindLayerTextureAssets(const LayerProgram& layerProgram, unsigned historyCap); OpenGLRenderer& mRenderer; + ShaderTextureBindings mTextureBindings; }; diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/TemporalHistoryBuffers.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/TemporalHistoryBuffers.cpp index c080630..89d9b10 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/TemporalHistoryBuffers.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/TemporalHistoryBuffers.cpp @@ -212,6 +212,29 @@ void TemporalHistoryBuffers::BindSamplers(const RuntimeRenderState& state, GLuin glActiveTexture(GL_TEXTURE0); } +std::vector TemporalHistoryBuffers::ResolveSourceHistoryTextures(GLuint fallbackTexture, unsigned historyCap) const +{ + std::vector textures; + textures.reserve(historyCap); + for (unsigned index = 0; index < historyCap; ++index) + textures.push_back(ResolveTexture(sourceHistoryRing, fallbackTexture, index)); + return textures; +} + +std::vector 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 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 { if (ring.filledCount == 0 || ring.slots.empty()) diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/TemporalHistoryBuffers.h b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/TemporalHistoryBuffers.h index b8b66fd..960953d 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/TemporalHistoryBuffers.h +++ b/apps/LoopThroughWithOpenGLCompositing/gl/pipeline/TemporalHistoryBuffers.h @@ -40,6 +40,8 @@ public: void PushSourceFramebuffer(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); + std::vector ResolveSourceHistoryTextures(GLuint fallbackTexture, unsigned historyCap) const; + std::vector ResolveTemporalHistoryTextures(const RuntimeRenderState& state, GLuint fallbackTexture, unsigned historyCap) const; GLuint ResolveTexture(const Ring& ring, GLuint fallbackTexture, std::size_t framesAgo) const; unsigned SourceAvailableCount() const; unsigned AvailableCountForLayer(const std::string& layerId) const; diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderProgramCompiler.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderProgramCompiler.cpp index 7b62f8d..21ef418 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderProgramCompiler.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderProgramCompiler.cpp @@ -101,51 +101,24 @@ bool ShaderProgramCompiler::CompilePreparedLayerProgram(const RuntimeRenderState std::vector 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"); if (globalParamsIndex != GL_INVALID_INDEX) glUniformBlockBinding(newProgram.get(), globalParamsIndex, kGlobalParamsBindingPoint); const unsigned historyCap = mRuntimeHost.GetMaxTemporalHistoryFrames(); - const GLuint shaderTextureBase = state.isTemporal ? kSourceHistoryTextureUnitBase + historyCap + historyCap : kSourceHistoryTextureUnitBase; glUseProgram(newProgram.get()); - const GLint videoInputLocation = glGetUniformLocation(newProgram.get(), "gVideoInput"); - if (videoInputLocation >= 0) - glUniform1i(videoInputLocation, static_cast(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(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(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(shaderTextureBase + static_cast(index))); - } - const GLuint textTextureBase = shaderTextureBase + static_cast(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(textTextureBase + static_cast(index))); - } + mTextureBindings.AssignLayerSamplerUniforms(newProgram.get(), state, layerProgram, historyCap); glUseProgram(0); - layerProgram.layerId = state.layerId; - layerProgram.shaderId = state.shaderId; - layerProgram.shaderTextureBase = shaderTextureBase; layerProgram.program = newProgram.release(); layerProgram.vertexShader = newVertexShader.release(); layerProgram.fragmentShader = newFragmentShader.release(); - layerProgram.textureBindings.swap(textureBindings); - layerProgram.textBindings.swap(textBindings); return true; } diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderTextureBindings.cpp b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderTextureBindings.cpp index a2e9e76..f326ed0 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderTextureBindings.cpp +++ b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderTextureBindings.cpp @@ -102,3 +102,122 @@ GLint ShaderTextureBindings::FindSamplerUniformLocation(GLuint program, const st return location; 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(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(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(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(shaderTextureBase + static_cast(index))); + } + + const GLuint textTextureBase = shaderTextureBase + static_cast(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(textTextureBase + static_cast(index))); + } +} + +ShaderTextureBindings::RuntimeTextureBindingPlan ShaderTextureBindings::BuildLayerRuntimeBindingPlan( + const LayerProgram& layerProgram, + GLuint layerInputTexture, + const std::vector& sourceHistoryTextures, + const std::vector& 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(index) + }); + } + + const GLuint temporalBase = kSourceHistoryTextureUnitBase + static_cast(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(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(index) + }); + } + + const GLuint textTextureBase = shaderTextureBase + static_cast(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(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); +} diff --git a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderTextureBindings.h b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderTextureBindings.h index 8f98ade..c6d14aa 100644 --- a/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderTextureBindings.h +++ b/apps/LoopThroughWithOpenGLCompositing/gl/shader/ShaderTextureBindings.h @@ -11,8 +11,30 @@ class ShaderTextureBindings public: using LayerProgram = OpenGLRenderer::LayerProgram; + struct RuntimeTextureBinding + { + std::string semanticName; + std::string samplerName; + GLuint texture = 0; + GLuint textureUnit = 0; + }; + + struct RuntimeTextureBindingPlan + { + std::vector bindings; + }; + bool LoadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error); void CreateTextBindings(const RuntimeRenderState& state, std::vector& textBindings); bool UpdateTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error); 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& sourceHistoryTextures, + const std::vector& temporalHistoryTextures) const; + void BindRuntimeTexturePlan(const RuntimeTextureBindingPlan& plan) const; + void UnbindRuntimeTexturePlan(const RuntimeTextureBindingPlan& plan) const; };