Graphics/UberShader: Add config callback

This commit is contained in:
Jérôme Leclercq 2021-09-05 15:46:59 +02:00
parent b6c3988bbe
commit 732bb89a86
6 changed files with 100 additions and 5 deletions

View File

@ -24,6 +24,8 @@ namespace Nz
public: public:
struct Config; struct Config;
struct Option; struct Option;
using ConfigCallback = std::function<void(Config& config, const std::vector<RenderPipelineInfo::VertexBufferData>& vertexBuffers)>;
UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst); UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst);
~UberShader() = default; ~UberShader() = default;
@ -33,6 +35,9 @@ namespace Nz
inline bool HasOption(const std::string& optionName, Pointer<const Option>* option = nullptr) const; inline bool HasOption(const std::string& optionName, Pointer<const Option>* option = nullptr) const;
inline void UpdateConfig(Config& config, const std::vector<RenderPipelineInfo::VertexBufferData>& vertexBuffers);
inline void UpdateConfigCallback(ConfigCallback callback);
static constexpr std::size_t MaximumOptionValue = 32; static constexpr std::size_t MaximumOptionValue = 32;
struct Config struct Config
@ -60,6 +65,7 @@ namespace Nz
std::unordered_map<Config, std::shared_ptr<ShaderModule>, ConfigHasher, ConfigEqual> m_combinations; std::unordered_map<Config, std::shared_ptr<ShaderModule>, ConfigHasher, ConfigEqual> m_combinations;
std::unordered_map<std::string, Option> m_optionIndexByName; std::unordered_map<std::string, Option> m_optionIndexByName;
ShaderAst::StatementPtr m_shaderAst; ShaderAst::StatementPtr m_shaderAst;
ConfigCallback m_configCallback;
ShaderStageTypeFlags m_shaderStages; ShaderStageTypeFlags m_shaderStages;
}; };
} }

View File

@ -24,6 +24,17 @@ namespace Nz
return true; return true;
} }
inline void UberShader::UpdateConfig(Config& config, const std::vector<RenderPipelineInfo::VertexBufferData>& vertexBuffers)
{
if (m_configCallback)
m_configCallback(config, vertexBuffers);
}
inline void UberShader::UpdateConfigCallback(ConfigCallback callback)
{
m_configCallback = std::move(callback);
}
inline bool UberShader::ConfigEqual::operator()(const Config& lhs, const Config& rhs) const inline bool UberShader::ConfigEqual::operator()(const Config& lhs, const Config& rhs) const
{ {
for (std::size_t i = 0; i < lhs.optionValues.size(); ++i) for (std::size_t i = 0; i < lhs.optionValues.size(); ++i)

View File

@ -154,6 +154,66 @@ namespace Nz
settings.shaders = std::move(uberShaders); settings.shaders = std::move(uberShaders);
for (std::shared_ptr<UberShader> uberShader : settings.shaders)
{
constexpr std::size_t InvalidOption = std::numeric_limits<std::size_t>::max();
auto FetchLocationOption = [&](const std::string& optionName)
{
const UberShader::Option* optionPtr;
if (!uberShader->HasOption(optionName, &optionPtr))
return InvalidOption;
if (optionPtr->type != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::Int32 })
throw std::runtime_error("Location options must be of type i32");
return optionPtr->index;
};
std::size_t positionLocationIndex = FetchLocationOption("PosLocation");
std::size_t colorLocationIndex = FetchLocationOption("ColorLocation");
std::size_t uvLocationIndex = FetchLocationOption("UvLocation");
uberShader->UpdateConfigCallback([=](UberShader::Config& config, const std::vector<RenderPipelineInfo::VertexBufferData>& vertexBuffers)
{
if (vertexBuffers.empty())
return;
const VertexDeclaration& vertexDeclaration = *vertexBuffers.front().declaration;
const auto& components = vertexDeclaration.GetComponents();
std::size_t locationIndex = 0;
for (const auto& component : components)
{
switch (component.component)
{
case VertexComponent::Unused:
continue;
case VertexComponent::Position:
if (positionLocationIndex != InvalidOption)
config.optionValues[positionLocationIndex] = static_cast<Int32>(locationIndex);
break;
case VertexComponent::Color:
if (colorLocationIndex != InvalidOption)
config.optionValues[colorLocationIndex] = static_cast<Int32>(locationIndex);
break;
case VertexComponent::TexCoord:
if (uvLocationIndex != InvalidOption)
config.optionValues[uvLocationIndex] = static_cast<Int32>(locationIndex);
break;
}
++locationIndex;
}
});
}
// Options // Options
// HasDiffuseMap // HasDiffuseMap

View File

@ -54,6 +54,7 @@ namespace Nz
if (shader.uberShader) if (shader.uberShader)
{ {
UberShader::Config config{ shader.optionValues }; UberShader::Config config{ shader.optionValues };
shader.uberShader->UpdateConfig(config, vertexBuffers);
renderPipelineInfo.shaderModules.push_back(shader.uberShader->Get(config)); renderPipelineInfo.shaderModules.push_back(shader.uberShader->Get(config));
} }

View File

@ -2,7 +2,13 @@ option HasDiffuseTexture: bool = false;
option HasAlphaTexture: bool = false; option HasAlphaTexture: bool = false;
option AlphaTest: bool = false; option AlphaTest: bool = false;
const HasUV = HasDiffuseTexture || HasAlphaTexture; // Vertex declaration related options
option PosLocation: i32 = -1;
option ColorLocation: i32 = -1;
option UvLocation: i32 = -1;
const HasVertexColor = (ColorLocation >= 0);
const HasUV = (UvLocation >= 0) && (HasDiffuseTexture || HasAlphaTexture);
[layout(std140)] [layout(std140)]
struct BasicSettings struct BasicSettings
@ -44,7 +50,8 @@ external
// Fragment stage // Fragment stage
struct FragIn struct FragIn
{ {
[location(0), cond(HasUV)] uv: vec2<f32> [location(0), cond(HasUV)] uv: vec2<f32>,
[location(1), cond(HasVertexColor)] color: vec4<f32>
} }
struct FragOut struct FragOut
@ -56,6 +63,11 @@ struct FragOut
fn main(input: FragIn) -> FragOut fn main(input: FragIn) -> FragOut
{ {
let diffuseColor = settings.DiffuseColor; let diffuseColor = settings.DiffuseColor;
const if (HasVertexColor)
//TODO: diffuseColor *= input.color;
diffuseColor = diffuseColor * input.color;
const if (HasDiffuseTexture) const if (HasDiffuseTexture)
// TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv) // TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv)
diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv); diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv);
@ -78,13 +90,15 @@ fn main(input: FragIn) -> FragOut
// Vertex stage // Vertex stage
struct VertIn struct VertIn
{ {
[location(0)] pos: vec3<f32>, [location(PosLocation)] pos: vec3<f32>,
[location(1), cond(HasUV)] uv: vec2<f32> [location(ColorLocation), cond(HasVertexColor)] color: vec4<f32>,
[location(UvLocation), cond(HasUV)] uv: vec2<f32>
} }
struct VertOut struct VertOut
{ {
[location(0), cond(HasUV)] uv: vec2<f32>, [location(0), cond(HasUV)] uv: vec2<f32>,
[location(1), cond(HasVertexColor)] color: vec4<f32>,
[builtin(position)] position: vec4<f32> [builtin(position)] position: vec4<f32>
} }
@ -94,6 +108,9 @@ fn main(input: VertIn) -> VertOut
let output: VertOut; let output: VertOut;
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4<f32>(input.pos, 1.0); output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4<f32>(input.pos, 1.0);
const if (HasVertexColor)
output.color = input.color;
const if (HasUV) const if (HasUV)
output.uv = input.uv; output.uv = input.uv;

View File

@ -140,7 +140,7 @@ namespace Nz
{ {
m_states = states; m_states = states;
m_states.sanitized = true; //< Shader is always sanitized (because of keywords) m_states.sanitized = true; //< Shader is always sanitized (because of keywords)
std::shared_ptr<ShaderAst::Statement> sanitized = GlslWriter::Sanitize(shaderAst, states.enabledOptions); std::shared_ptr<ShaderAst::Statement> sanitized = GlslWriter::Sanitize(shaderAst, states.optionValues);
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i) for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
{ {