257 lines
9.9 KiB
C++
257 lines
9.9 KiB
C++
#include "ShaderTextureBindings.h"
|
|
|
|
#include "GlRenderConstants.h"
|
|
#include "TextRasterizer.h"
|
|
#include "TextureAssetLoader.h"
|
|
|
|
#include <algorithm>
|
|
#include <filesystem>
|
|
|
|
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<LayerProgram::TextBinding>& 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<unsigned char> empty(static_cast<std::size_t>(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<unsigned char> 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<GLuint>(previousUnpackBuffer));
|
|
glActiveTexture(static_cast<GLenum>(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::ResolveFeedbackTextureUnit(const RuntimeRenderState& state, unsigned historyCap) const
|
|
{
|
|
return state.isTemporal ? kSourceHistoryTextureUnitBase + historyCap + historyCap : kSourceHistoryTextureUnitBase;
|
|
}
|
|
|
|
GLuint ShaderTextureBindings::ResolveShaderTextureBase(const RuntimeRenderState& state, unsigned historyCap) const
|
|
{
|
|
return ResolveFeedbackTextureUnit(state, historyCap) + (state.feedback.enabled ? 1u : 0u);
|
|
}
|
|
|
|
void ShaderTextureBindings::AssignLayerSamplerUniforms(GLuint program, const RuntimeRenderState& state, const PassProgram& passProgram, unsigned historyCap) const
|
|
{
|
|
const GLuint shaderTextureBase = ResolveShaderTextureBase(state, historyCap);
|
|
|
|
const GLint layerInputLocation = FindSamplerUniformLocation(program, "gLayerInput");
|
|
if (layerInputLocation >= 0)
|
|
glUniform1i(layerInputLocation, static_cast<GLint>(kLayerInputTextureUnit));
|
|
|
|
const GLint videoInputLocation = FindSamplerUniformLocation(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));
|
|
}
|
|
|
|
if (state.feedback.enabled)
|
|
{
|
|
const GLint feedbackSamplerLocation = FindSamplerUniformLocation(program, "gFeedbackState");
|
|
if (feedbackSamplerLocation >= 0)
|
|
glUniform1i(feedbackSamplerLocation, static_cast<GLint>(ResolveFeedbackTextureUnit(state, historyCap)));
|
|
}
|
|
|
|
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,
|
|
GLuint originalLayerInputTexture,
|
|
const RuntimeRenderState& state,
|
|
GLuint feedbackTexture,
|
|
const std::vector<GLuint>& sourceHistoryTextures,
|
|
const std::vector<GLuint>& temporalHistoryTextures) const
|
|
{
|
|
RuntimeTextureBindingPlan plan;
|
|
plan.bindings.push_back({ "originalLayerInput", "gLayerInput", originalLayerInputTexture, kLayerInputTextureUnit });
|
|
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 feedbackTextureUnit = ResolveFeedbackTextureUnit(state, static_cast<unsigned>(sourceHistoryTextures.size()));
|
|
if (state.feedback.enabled)
|
|
{
|
|
plan.bindings.push_back({
|
|
"feedbackState",
|
|
"gFeedbackState",
|
|
feedbackTexture,
|
|
feedbackTextureUnit
|
|
});
|
|
}
|
|
|
|
const GLuint shaderTextureBase = passProgram.shaderTextureBase != 0
|
|
? passProgram.shaderTextureBase
|
|
: feedbackTextureUnit + (state.feedback.enabled ? 1u : 0u);
|
|
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);
|
|
}
|