#include "ShaderTextureBindings.h" #include "GlRenderConstants.h" #include "TextRasterizer.h" #include "TextureAssetLoader.h" #include #include namespace { std::string TextValueForBinding(const RuntimeRenderState& state, const std::string& parameterId) { auto valueIt = state.parameterValues.find(parameterId); return valueIt == state.parameterValues.end() ? std::string() : valueIt->second.textValue; } const ShaderFontAsset* FindFontAssetForParameter(const RuntimeRenderState& state, const ShaderParameterDefinition& definition) { if (!definition.fontId.empty()) { for (const ShaderFontAsset& fontAsset : state.fontAssets) { if (fontAsset.id == definition.fontId) return &fontAsset; } } return state.fontAssets.empty() ? nullptr : &state.fontAssets.front(); } } bool ShaderTextureBindings::LoadTextureAsset(const ShaderTextureAsset& textureAsset, GLuint& textureId, std::string& error) { return ::LoadTextureAsset(textureAsset, textureId, error); } void ShaderTextureBindings::CreateTextBindings(const RuntimeRenderState& state, std::vector& textBindings) { for (const ShaderParameterDefinition& definition : state.parameterDefinitions) { if (definition.type != ShaderParameterType::Text) continue; LayerProgram::TextBinding textBinding; textBinding.parameterId = definition.id; textBinding.samplerName = definition.id + "Texture"; textBinding.fontId = definition.fontId; glGenTextures(1, &textBinding.texture); glBindTexture(GL_TEXTURE_2D, textBinding.texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); std::vector empty(static_cast(kTextTextureWidth) * kTextTextureHeight * 4, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kTextTextureWidth, kTextTextureHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, empty.data()); glBindTexture(GL_TEXTURE_2D, 0); textBindings.push_back(textBinding); } } bool ShaderTextureBindings::UpdateTextBindingTexture(const RuntimeRenderState& state, LayerProgram::TextBinding& textBinding, std::string& error) { const std::string text = TextValueForBinding(state, textBinding.parameterId); if (text == textBinding.renderedText && textBinding.renderedWidth == kTextTextureWidth && textBinding.renderedHeight == kTextTextureHeight) return true; auto definitionIt = std::find_if(state.parameterDefinitions.begin(), state.parameterDefinitions.end(), [&textBinding](const ShaderParameterDefinition& definition) { return definition.id == textBinding.parameterId; }); if (definitionIt == state.parameterDefinitions.end()) return true; const ShaderFontAsset* fontAsset = FindFontAssetForParameter(state, *definitionIt); std::filesystem::path fontPath; if (fontAsset) fontPath = fontAsset->path; std::vector sdf; if (!RasterizeTextSdf(text, fontPath, sdf, error)) return false; GLint previousActiveTexture = 0; GLint previousUnpackBuffer = 0; glGetIntegerv(GL_ACTIVE_TEXTURE, &previousActiveTexture); glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &previousUnpackBuffer); glActiveTexture(GL_TEXTURE0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glBindTexture(GL_TEXTURE_2D, textBinding.texture); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextTextureWidth, kTextTextureHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, sdf.data()); glBindTexture(GL_TEXTURE_2D, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast(previousUnpackBuffer)); glActiveTexture(static_cast(previousActiveTexture)); textBinding.renderedText = text; textBinding.renderedWidth = kTextTextureWidth; textBinding.renderedHeight = kTextTextureHeight; return true; } GLint ShaderTextureBindings::FindSamplerUniformLocation(GLuint program, const std::string& samplerName) const { GLint location = glGetUniformLocation(program, samplerName.c_str()); if (location >= 0) 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 PassProgram& passProgram, 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 < passProgram.textureBindings.size(); ++index) { const GLint textureSamplerLocation = FindSamplerUniformLocation(program, passProgram.textureBindings[index].samplerName); if (textureSamplerLocation >= 0) glUniform1i(textureSamplerLocation, static_cast(shaderTextureBase + static_cast(index))); } const GLuint textTextureBase = shaderTextureBase + static_cast(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(textTextureBase + static_cast(index))); } } ShaderTextureBindings::RuntimeTextureBindingPlan ShaderTextureBindings::BuildLayerRuntimeBindingPlan( const PassProgram& passProgram, 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 = 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(index) }); } const GLuint textTextureBase = shaderTextureBase + static_cast(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(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); }