Handle shader options of any type

This commit is contained in:
Jérôme Leclercq
2021-09-03 19:33:41 +02:00
parent 2f9e495739
commit 02a12d9328
38 changed files with 236 additions and 1118 deletions

View File

@@ -160,19 +160,19 @@ namespace Nz
if (optionIndexes)
optionIndexes->hasDiffuseMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasDiffuseMap", "HAS_DIFFUSE_TEXTURE");
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasDiffuseMap", "HasDiffuseTexture");
// HasAlphaMap
if (optionIndexes)
optionIndexes->hasAlphaMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasAlphaMap", "HAS_ALPHA_TEXTURE");
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasAlphaMap", "HasAlphaTexture");
// AlphaTest
if (optionIndexes)
optionIndexes->alphaTest = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "AlphaTest", "ALPHA_TEST");
MaterialSettings::BuildOption(settings.options, settings.shaders, "AlphaTest", "AlphaTest");
return settings;
}

View File

@@ -28,7 +28,6 @@ namespace Nz
*/
MaterialPass::MaterialPass(std::shared_ptr<const MaterialSettings> settings) :
m_settings(std::move(settings)),
m_enabledOptions(0),
m_forceCommandBufferRegeneration(false),
m_pipelineUpdated(false),
m_shaderBindingUpdated(false)
@@ -99,23 +98,20 @@ namespace Nz
void MaterialPass::UpdatePipeline() const
{
for (auto& shader : m_pipelineInfo.shaders)
shader.enabledOptions = 0;
shader.optionValues.fill(ShaderAst::NoValue{});
const auto& options = m_settings->GetOptions();
for (std::size_t optionIndex = 0; optionIndex < options.size(); ++optionIndex)
{
if (TestBit<UInt64>(m_enabledOptions, optionIndex))
const auto& option = options[optionIndex];
assert(option.optionIndexByShader.size() <= m_pipelineInfo.shaders.size());
for (std::size_t shaderIndex = 0; shaderIndex < option.optionIndexByShader.size(); ++shaderIndex)
{
for (auto& shader : m_pipelineInfo.shaders)
{
ShaderStageTypeFlags supportedStages = shader.uberShader->GetSupportedStages();
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
{
ShaderStageType shaderStage = static_cast<ShaderStageType>(i);
if (supportedStages & shaderStage)
shader.enabledOptions |= options[optionIndex].enabledOptions[i];
}
}
if (!option.optionIndexByShader[shaderIndex].has_value())
continue;
m_pipelineInfo.shaders[shaderIndex].optionValues[optionIndex] = m_optionValues[optionIndex];
}
}

View File

@@ -45,14 +45,18 @@ namespace Nz
}
RenderPipelineInfo renderPipelineInfo;
static_cast<RenderStates&>(renderPipelineInfo).operator=(m_pipelineInfo); // Not the line I4m the most proud of
static_cast<RenderStates&>(renderPipelineInfo).operator=(m_pipelineInfo); // Not the line I'm the most proud of
renderPipelineInfo.pipelineLayout = m_pipelineInfo.settings->GetRenderPipelineLayout();
for (const auto& shader : m_pipelineInfo.shaders)
{
if (shader.uberShader)
renderPipelineInfo.shaderModules.push_back(shader.uberShader->Get(shader.enabledOptions));
{
UberShader::Config config{ shader.optionValues };
renderPipelineInfo.shaderModules.push_back(shader.uberShader->Get(config));
}
}
renderPipelineInfo.vertexBuffers = vertexBuffers;

View File

@@ -1,8 +1,8 @@
option HAS_DIFFUSE_TEXTURE: bool;
option HAS_ALPHA_TEXTURE: bool;
option ALPHA_TEST: bool;
option HasDiffuseTexture: bool = false;
option HasAlphaTexture: bool = false;
option AlphaTest: bool = false;
const HasUV = HAS_DIFFUSE_TEXTURE || HAS_ALPHA_TEXTURE;
const HasUV = HasDiffuseTexture || HasAlphaTexture;
[layout(std140)]
struct BasicSettings
@@ -56,15 +56,15 @@ struct FragOut
fn main(input: FragIn) -> FragOut
{
let diffuseColor = settings.DiffuseColor;
const if (HAS_DIFFUSE_TEXTURE)
const if (HasDiffuseTexture)
// TODO: diffuseColor *= MaterialDiffuseMap.Sample(input.uv)
diffuseColor = diffuseColor * MaterialDiffuseMap.Sample(input.uv);
const if (HAS_ALPHA_TEXTURE)
const if (HasAlphaTexture)
// TODO: diffuseColor.w *= MaterialAlphaMap.Sample(input.uv)).x
diffuseColor = vec4<f32>(diffuseColor.x, diffuseColor.y, diffuseColor.z, MaterialAlphaMap.Sample(input.uv).x * diffuseColor.w);
const if (ALPHA_TEST)
const if (AlphaTest)
{
if (diffuseColor.w < settings.AlphaThreshold)
discard;

View File

@@ -1,8 +1,8 @@
option HAS_DIFFUSE_TEXTURE: bool;
option HAS_ALPHA_TEXTURE: bool;
option ALPHA_TEST: bool;
option HasDiffuseTexture: bool = false;
option HasAlphaTexture: bool = false;
option AlphaTest: bool = false;
const HasUV = ALPHA_TEST && (HAS_DIFFUSE_TEXTURE || HAS_ALPHA_TEXTURE);
const HasUV = AlphaTest && (HasDiffuseTexture || HasAlphaTexture);
[layout(std140)]
struct BasicSettings
@@ -47,15 +47,15 @@ struct FragIn
[location(0), cond(HasUV)] uv: vec2<f32>
}
[entry(frag), cond(ALPHA_TEST)]
[entry(frag), cond(AlphaTest)]
fn main(input: FragIn)
{
let alpha = settings.DiffuseColor.a;
const if (HAS_DIFFUSE_TEXTURE)
const if (HasDiffuseTexture)
// TODO: alpha *= MaterialDiffuseMap.Sample(input.uv).a;
alpha = alpha * MaterialDiffuseMap.Sample(input.uv).a;
const if (HAS_ALPHA_TEXTURE)
const if (HasAlphaTexture)
// TODO: alpha *= MaterialAlphaMap.Sample(input.uv).x
alpha = alpha * MaterialAlphaMap.Sample(input.uv).x;
@@ -64,7 +64,7 @@ fn main(input: FragIn)
}
// Dummy fragment shader (TODO: Add a way to delete stage?)
[entry(frag), cond(!ALPHA_TEST)]
[entry(frag), cond(!AlphaTest)]
fn main() {}
// Vertex stage

View File

@@ -33,7 +33,11 @@ namespace Nz
callbacks.onOptionDeclaration = [&](const std::string& optionName, const ShaderAst::ExpressionType& optionType)
{
m_optionIndexByName[optionName] = optionCount;
m_optionIndexByName[optionName] = Option{
optionCount,
optionType
};
optionCount++;
};
@@ -43,36 +47,26 @@ namespace Nz
if (m_shaderStages & supportedStageType != m_shaderStages)
throw std::runtime_error("shader doesn't support all required shader stages");
if (optionCount >= 64)
throw std::runtime_error("Too many conditions");
m_combinationMask = std::numeric_limits<UInt64>::max();
m_combinationMask <<= optionCount;
m_combinationMask = ~m_combinationMask;
if (optionCount >= MaximumOptionValue)
throw std::runtime_error("Too many shader options (at most " + std::to_string(MaximumOptionValue) + " are supported)");
}
UInt64 UberShader::GetOptionFlagByName(const std::string& optionName) const
const std::shared_ptr<ShaderModule>& UberShader::Get(const Config& config)
{
auto it = m_optionIndexByName.find(optionName);
if (it == m_optionIndexByName.end())
return 0;
return SetBit<UInt64>(0, it->second);
}
const std::shared_ptr<ShaderModule>& UberShader::Get(UInt64 combination)
{
combination &= m_combinationMask;
auto it = m_combinations.find(combination);
auto it = m_combinations.find(config);
if (it == m_combinations.end())
{
ShaderWriter::States states;
states.enabledOptions = combination;
for (std::size_t i = 0; i < MaximumOptionValue; ++i)
{
if (!std::holds_alternative<ShaderAst::NoValue>(config.optionValues[i]))
states.optionValues[i] = config.optionValues[i];
}
std::shared_ptr<ShaderModule> stage = Graphics::Instance()->GetRenderDevice()->InstantiateShaderModule(m_shaderStages, *m_shaderAst, std::move(states));
it = m_combinations.emplace(combination, std::move(stage)).first;
it = m_combinations.emplace(config, std::move(stage)).first;
}
return it->second;