Graphics/UberShader: Add config callback
This commit is contained in:
parent
b6c3988bbe
commit
732bb89a86
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue