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

@ -1,6 +1,6 @@
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;
[layout(std140)]
struct BasicSettings
@ -57,15 +57,15 @@ struct OutputData
fn main(input: InputData) -> OutputData
{
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

@ -12,7 +12,7 @@ NAZARA_REQUEST_DEDICATED_GPU()
const char shaderSource[] = R"(
option red: bool;
option red: bool = false;
[layout(std140)]
struct Data
@ -109,7 +109,6 @@ int main()
}
Nz::ShaderWriter::States states;
states.enabledOptions = 0;
states.optimize = true;
auto fragVertShader = device->InstantiateShaderModule(Nz::ShaderStageType::Fragment | Nz::ShaderStageType::Vertex, Nz::ShaderLanguage::NazaraShader, shaderSource, sizeof(shaderSource), states);

View File

@ -26,7 +26,7 @@ namespace Nz
inline void BasicMaterial::EnableAlphaTest(bool alphaTest)
{
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
m_material.EnableOption(m_optionIndexes.alphaTest, alphaTest);
m_material.SetOptionValue(m_optionIndexes.alphaTest, alphaTest);
}
inline const std::shared_ptr<Texture>& BasicMaterial::GetAlphaMap() const
@ -56,7 +56,11 @@ namespace Nz
inline bool BasicMaterial::IsAlphaTestEnabled() const
{
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
return m_material.IsOptionEnabled(m_optionIndexes.alphaTest);
const auto& optionOpt = m_material.GetOptionValue(m_optionIndexes.alphaTest);
if (std::holds_alternative<ShaderAst::NoValue>(optionOpt))
return false;
return std::get<bool>(optionOpt);
}
inline bool BasicMaterial::HasAlphaMap() const
@ -91,7 +95,7 @@ namespace Nz
m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap));
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.EnableOption(m_optionIndexes.hasAlphaMap, hasAlphaMap);
m_material.SetOptionValue(m_optionIndexes.hasAlphaMap, hasAlphaMap);
}
inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler)
@ -107,7 +111,7 @@ namespace Nz
m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap));
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.EnableOption(m_optionIndexes.hasDiffuseMap, hasDiffuseMap);
m_material.SetOptionValue(m_optionIndexes.hasDiffuseMap, hasDiffuseMap);
}
inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler)

View File

@ -20,6 +20,7 @@
#include <Nazara/Graphics/MaterialPipeline.hpp>
#include <Nazara/Renderer/Texture.hpp>
#include <Nazara/Renderer/TextureSampler.hpp>
#include <Nazara/Shader/Ast/ConstantValue.hpp>
#include <Nazara/Utility/UniformBuffer.hpp>
#include <array>
#include <string>
@ -45,7 +46,6 @@ namespace Nz
inline void EnableDepthClamp(bool depthClamp);
inline void EnableDepthWrite(bool depthWrite);
inline void EnableFaceCulling(bool faceCulling);
inline void EnableOption(std::size_t optionIndex, bool enable);
inline void EnableScissorTest(bool scissorTest);
inline void EnableStencilTest(bool stencilTest);
@ -61,6 +61,7 @@ namespace Nz
inline FaceSide GetFaceCulling() const;
inline FaceFilling GetFaceFilling() const;
inline float GetLineWidth() const;
inline const ShaderAst::ConstantValue& GetOptionValue(std::size_t optionIndex) const;
inline const std::shared_ptr<MaterialPipeline>& GetPipeline() const;
inline const MaterialPipelineInfo& GetPipelineInfo() const;
inline float GetPointSize() const;
@ -82,7 +83,6 @@ namespace Nz
inline bool IsDepthClampEnabled() const;
inline bool IsDepthWriteEnabled() const;
inline bool IsFaceCullingEnabled() const;
inline bool IsOptionEnabled(std::size_t optionIndex) const;
inline bool IsScissorTestEnabled() const;
inline bool IsStencilTestEnabled() const;
@ -92,6 +92,7 @@ namespace Nz
inline void SetFaceCulling(FaceSide faceSide);
inline void SetFaceFilling(FaceFilling filling);
inline void SetLineWidth(float lineWidth);
inline void SetOptionValue(std::size_t optionIndex, ShaderAst::ConstantValue value);
inline void SetPointSize(float pointSize);
inline void SetPrimitiveMode(PrimitiveMode mode);
inline void SetTexture(std::size_t textureIndex, std::shared_ptr<Texture> texture);
@ -126,11 +127,11 @@ namespace Nz
bool dataInvalidated = true;
};
std::array<ShaderAst::ConstantValue, 64> m_optionValues;
std::shared_ptr<const MaterialSettings> m_settings;
std::vector<MaterialTexture> m_textures;
std::vector<UniformBuffer> m_uniformBuffers;
mutable std::shared_ptr<MaterialPipeline> m_pipeline;
UInt64 m_enabledOptions;
mutable MaterialPipelineInfo m_pipelineInfo;
ShaderBindingPtr m_shaderBinding;
bool m_forceCommandBufferRegeneration;

View File

@ -182,15 +182,6 @@ namespace Nz
InvalidatePipeline();
}
inline void MaterialPass::EnableOption(std::size_t optionIndex, bool enable)
{
if (TestBit<UInt64>(m_enabledOptions, optionIndex) != enable)
{
m_enabledOptions = ToggleBit<UInt64>(m_enabledOptions, optionIndex);
InvalidatePipeline();
}
}
/*!
* \brief Enable/Disable scissor test for this material
*
@ -315,6 +306,12 @@ namespace Nz
return m_pipelineInfo.lineWidth;
}
inline const ShaderAst::ConstantValue& MaterialPass::GetOptionValue(std::size_t optionIndex) const
{
assert(optionIndex < m_optionValues.size());
return m_optionValues[optionIndex];
}
/*!
* \brief Gets the render states
* \return Constant reference to the render states
@ -461,11 +458,6 @@ namespace Nz
return m_pipelineInfo.faceCulling;
}
inline bool MaterialPass::IsOptionEnabled(std::size_t optionIndex) const
{
return TestBit<UInt64>(m_enabledOptions, optionIndex);
}
/*!
* \brief Checks whether this material has scissor test enabled
* \return true If it is the case
@ -562,6 +554,16 @@ namespace Nz
InvalidatePipeline();
}
inline void MaterialPass::SetOptionValue(std::size_t optionIndex, ShaderAst::ConstantValue value)
{
assert(optionIndex < m_optionValues.size());
if (m_optionValues[optionIndex] != value)
{
m_optionValues[optionIndex] = std::move(value);
InvalidatePipeline();
}
}
/*!
* \brief Sets the point size for this material
*
@ -654,3 +656,4 @@ namespace Nz
}
#include <Nazara/Graphics/DebugOff.hpp>
#include "MaterialPass.hpp"

View File

@ -12,6 +12,7 @@
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/MaterialSettings.hpp>
#include <Nazara/Renderer/RenderPipeline.hpp>
#include <Nazara/Shader/Ast/ConstantValue.hpp>
#include <array>
#include <memory>
@ -23,8 +24,8 @@ namespace Nz
{
struct Shader
{
std::array<ShaderAst::ConstantValue, 32> optionValues;
std::shared_ptr<UberShader> uberShader;
Nz::UInt64 enabledOptions = 0;
};
std::vector<Shader> shaders;

View File

@ -34,7 +34,7 @@ namespace Nz
for (std::size_t i = 0; i < lhs.shaders.size(); ++i)
{
if (lhs.shaders[i].enabledOptions != rhs.shaders[i].enabledOptions)
if (lhs.shaders[i].optionValues != rhs.shaders[i].optionValues)
return false;
if (lhs.shaders[i].uberShader != rhs.shaders[i].uberShader)
@ -73,7 +73,9 @@ namespace std
for (const auto& shader : pipelineInfo.shaders)
{
Nz::HashCombine(seed, shader.enabledOptions);
for (const auto& value : shader.optionValues)
Nz::HashCombine(seed, value);
Nz::HashCombine(seed, shader.uberShader.get());
}

View File

@ -55,7 +55,7 @@ namespace Nz
static constexpr std::size_t InvalidIndex = std::numeric_limits<std::size_t>::max();
static void BuildOption(std::vector<Option>& options, const std::vector<std::shared_ptr<UberShader>>& uberShaders, std::string optionName, const std::string& shaderOptionName);
static inline void BuildOption(std::vector<Option>& options, const std::vector<std::shared_ptr<UberShader>>& uberShaders, std::string optionName, const std::string& shaderOptionName);
struct Builder
{
@ -69,7 +69,7 @@ namespace Nz
struct Option
{
std::string name;
std::array<UInt64, ShaderStageTypeCount> enabledOptions;
std::vector<std::optional<std::size_t>> optionIndexByShader;
};
struct UniformVariable

View File

@ -168,22 +168,23 @@ namespace Nz
inline void MaterialSettings::BuildOption(std::vector<Option>& options, const std::vector<std::shared_ptr<UberShader>>& uberShaders, std::string optionName, const std::string& shaderOptionName)
{
std::array<UInt64, ShaderStageTypeCount> shaderOptions;
shaderOptions.fill(0);
std::vector<std::optional<std::size_t>> shaderOptions;
for (std::size_t i = 0; i < ShaderStageTypeCount; ++i)
for (std::size_t shaderIndex = 0; shaderIndex < uberShaders.size(); ++shaderIndex)
{
for (const auto& uberShader : uberShaders)
const auto& uberShader = uberShaders[shaderIndex];
const UberShader::Option* optionData;
if (uberShader->HasOption(shaderOptionName, &optionData))
{
if (uberShader->GetSupportedStages() & static_cast<ShaderStageType>(i))
{
assert(shaderOptions[i] == 0);
shaderOptions[i] |= uberShader->GetOptionFlagByName(shaderOptionName);
}
if (shaderIndex >= shaderOptions.size())
shaderOptions.resize(shaderIndex + 1);
shaderOptions[shaderIndex] = optionData->index;
}
}
if (std::any_of(shaderOptions.begin(), shaderOptions.end(), [&](UInt64 flags) { return flags != 0; }))
if (std::any_of(shaderOptions.begin(), shaderOptions.end(), [&](std::optional<std::size_t> optionIndex) { return optionIndex.has_value(); }))
{
options.push_back({
std::move(optionName),

View File

@ -8,8 +8,10 @@
#define NAZARA_UBER_SHADER_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/Bitset.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Renderer/RenderPipeline.hpp>
#include <Nazara/Shader/Ast/Nodes.hpp>
#include <unordered_map>
@ -20,21 +22,45 @@ namespace Nz
class NAZARA_GRAPHICS_API UberShader
{
public:
struct Config;
struct Option;
UberShader(ShaderStageTypeFlags shaderStages, const ShaderAst::StatementPtr& shaderAst);
~UberShader() = default;
UInt64 GetOptionFlagByName(const std::string& optionName) const;
inline ShaderStageTypeFlags GetSupportedStages() const;
const std::shared_ptr<ShaderModule>& Get(UInt64 combination);
const std::shared_ptr<ShaderModule>& Get(const Config& config);
inline bool HasOption(const std::string& optionName, Pointer<const Option>* option = nullptr) const;
static constexpr std::size_t MaximumOptionValue = 32;
struct Config
{
std::array<ShaderAst::ConstantValue, MaximumOptionValue> optionValues;
};
struct ConfigEqual
{
inline bool operator()(const Config& lhs, const Config& rhs) const;
};
struct ConfigHasher
{
inline std::size_t operator()(const Config& config) const;
};
struct Option
{
std::size_t index;
ShaderAst::ExpressionType type;
};
private:
std::unordered_map<UInt64 /*combination*/, std::shared_ptr<ShaderModule>> m_combinations;
std::unordered_map<std::string, std::size_t> m_optionIndexByName;
std::unordered_map<Config, std::shared_ptr<ShaderModule>, ConfigHasher, ConfigEqual> m_combinations;
std::unordered_map<std::string, Option> m_optionIndexByName;
ShaderAst::StatementPtr m_shaderAst;
ShaderStageTypeFlags m_shaderStages;
UInt64 m_combinationMask;
};
}

View File

@ -11,6 +11,38 @@ namespace Nz
{
return m_shaderStages;
}
inline bool UberShader::HasOption(const std::string& optionName, Pointer<const Option>* option) const
{
auto it = m_optionIndexByName.find(optionName);
if (it == m_optionIndexByName.end())
return false;
if (option)
*option = &it->second;
return true;
}
inline bool UberShader::ConfigEqual::operator()(const Config& lhs, const Config& rhs) const
{
for (std::size_t i = 0; i < lhs.optionValues.size(); ++i)
{
if (lhs.optionValues[i] != rhs.optionValues[i])
return false;
}
return true;
}
inline std::size_t UberShader::ConfigHasher::operator()(const Config& config) const
{
std::size_t hash = 0;
for (std::size_t i = 0; i < config.optionValues.size(); ++i)
HashCombine(hash, config.optionValues[i]);
return hash;
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -11,6 +11,7 @@
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/Ast/AstCloner.hpp>
#include <optional>
#include <unordered_map>
#include <vector>
namespace Nz::ShaderAst
@ -36,7 +37,6 @@ namespace Nz::ShaderAst
struct Options
{
std::function<const ConstantValue&(std::size_t constantId)> constantQueryCallback;
std::optional<UInt64> enabledOptions = 0;
};
protected:

View File

@ -18,7 +18,10 @@
namespace Nz::ShaderAst
{
using NoValue = std::monostate;
using ConstantTypes = TypeList<
NoValue,
bool,
float,
Int32,

View File

@ -302,7 +302,7 @@ namespace Nz::ShaderAst
std::optional<std::size_t> optIndex;
std::string optName;
ExpressionPtr initialValue;
ExpressionPtr defaultValue;
ExpressionType optType;
};

View File

@ -36,7 +36,7 @@ namespace Nz::ShaderAst
struct Options
{
std::unordered_set<std::string> reservedIdentifiers;
UInt64 enabledOptions = 0;
std::unordered_map<std::size_t, ConstantValue> optionValues;
bool makeVariableNameUnique = false;
bool removeOptionDeclaration = true;
};

View File

@ -46,7 +46,7 @@ namespace Nz
};
static const char* GetFlipYUniformName();
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, UInt64 enabledOptions, std::string* error = nullptr);
static ShaderAst::StatementPtr Sanitize(ShaderAst::Statement& ast, std::unordered_map<std::size_t, ShaderAst::ConstantValue> optionValues, std::string* error = nullptr);
private:
void Append(const ShaderAst::ExpressionType& type);

View File

@ -198,7 +198,7 @@ namespace Nz::ShaderBuilder
auto declareOptionNode = std::make_unique<ShaderAst::DeclareOptionStatement>();
declareOptionNode->optName = std::move(name);
declareOptionNode->optType = std::move(type);
declareOptionNode->initialValue = std::move(initialValue);
declareOptionNode->defaultValue = std::move(initialValue);
return declareOptionNode;
}

View File

@ -9,8 +9,9 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Shader/Config.hpp>
#include <Nazara/Shader/Ast/ConstantValue.hpp>
#include <string>
#include <unordered_set>
#include <unordered_map>
namespace Nz
{
@ -26,7 +27,7 @@ namespace Nz
struct States
{
Nz::UInt64 enabledOptions = 0;
std::unordered_map<std::size_t, ShaderAst::ConstantValue> optionValues;
bool optimize = false;
bool sanitized = false;
};

View File

@ -63,8 +63,6 @@ namespace Nz
UInt32 GetPointerTypeId(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const;
UInt32 GetTypeId(const ShaderAst::ExpressionType& type) const;
bool IsOptionEnabled(std::size_t optionIndex) const;
UInt32 RegisterConstant(const ShaderAst::ConstantValue& value);
UInt32 RegisterFunctionType(const ShaderAst::DeclareFunctionStatement& functionNode);
UInt32 RegisterPointerType(ShaderAst::ExpressionType type, SpirvStorageClass storageClass);

View File

@ -1,597 +0,0 @@
{
"buffers": [
{
"bindingIndex": 0,
"name": "viewerData",
"setIndex": 0,
"structIndex": 2,
"type": "UniformBufferObject"
},
{
"bindingIndex": 0,
"name": "instanceData",
"setIndex": 1,
"structIndex": 1,
"type": "UniformBufferObject"
},
{
"bindingIndex": 0,
"name": "settings",
"setIndex": 2,
"structIndex": 0,
"type": "UniformBufferObject"
}
],
"conditions": [
{
"name": "HAS_DIFFUSE_TEXTURE"
},
{
"name": "HAS_ALPHA_TEXTURE"
},
{
"name": "ALPHA_TEST"
}
],
"connections": [
{
"in_id": "{fc7542b2-5752-4891-98c1-35b498da257b}",
"in_index": 1,
"out_id": "{743930bd-1d81-4d4c-b7ec-175a34838d69}",
"out_index": 0
},
{
"in_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}",
"in_index": 0,
"out_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}",
"out_index": 0
},
{
"in_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}",
"in_index": 3,
"out_id": "{93fdbb4c-bc81-4100-89a9-b465793099b9}",
"out_index": 0
},
{
"in_id": "{7750a050-b116-4e1b-bd89-b194c366d256}",
"in_index": 1,
"out_id": "{ca2c2ac5-39e0-4814-9432-fbf3e20d3cad}",
"out_index": 0
},
{
"in_id": "{bed466d8-5ed0-4e8a-bba7-1c809cb4c3f7}",
"in_index": 1,
"out_id": "{07a43c79-67e2-46b1-87d4-e00d2da22820}",
"out_index": 0
},
{
"in_id": "{6fcfbcd0-c2df-41dd-bb50-74b455b9021f}",
"in_index": 0,
"out_id": "{7750a050-b116-4e1b-bd89-b194c366d256}",
"out_index": 0
},
{
"in_id": "{d7acd173-9188-43b5-bfa1-31f17dff44ad}",
"in_index": 1,
"out_id": "{1f9d52d7-4f44-4d96-8edb-fbc1239a93bb}",
"out_index": 0
},
{
"in_id": "{be3547ff-0bf3-4701-9c27-c21e9d1322c3}",
"in_index": 0,
"out_id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}",
"out_index": 0
},
{
"in_id": "{fc7542b2-5752-4891-98c1-35b498da257b}",
"in_index": 0,
"out_id": "{bb071807-e65e-4c31-acf0-d296efa665fa}",
"out_index": 3
},
{
"in_id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}",
"in_index": 0,
"out_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}",
"out_index": 0
},
{
"in_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}",
"in_index": 2,
"out_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}",
"out_index": 2
},
{
"in_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}",
"in_index": 0,
"out_id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}",
"out_index": 0
},
{
"in_id": "{7750a050-b116-4e1b-bd89-b194c366d256}",
"in_index": 0,
"out_id": "{f9ba0cce-3b85-4f95-a79e-a2f64d955d89}",
"out_index": 0
},
{
"in_id": "{93fdbb4c-bc81-4100-89a9-b465793099b9}",
"in_index": 0,
"out_id": "{6fcfbcd0-c2df-41dd-bb50-74b455b9021f}",
"out_index": 0
},
{
"in_id": "{359a78e1-df0d-467f-907e-7bff04a55db5}",
"in_index": 1,
"out_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}",
"out_index": 1
},
{
"in_id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}",
"in_index": 1,
"out_id": "{07a43c79-67e2-46b1-87d4-e00d2da22820}",
"out_index": 0
},
{
"in_id": "{3cdb5bb1-f572-4055-a1af-460b152b0c13}",
"in_index": 0,
"out_id": "{d7acd173-9188-43b5-bfa1-31f17dff44ad}",
"out_index": 0
},
{
"in_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}",
"in_index": 0,
"out_id": "{ac98a68f-0160-4189-af31-b8278e7c119c}",
"out_index": 0
},
{
"in_id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}",
"in_index": 0,
"out_id": "{bed466d8-5ed0-4e8a-bba7-1c809cb4c3f7}",
"out_index": 0
},
{
"in_id": "{93fdbb4c-bc81-4100-89a9-b465793099b9}",
"in_index": 1,
"out_id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}",
"out_index": 3
},
{
"in_id": "{d7acd173-9188-43b5-bfa1-31f17dff44ad}",
"in_index": 0,
"out_id": "{fc7542b2-5752-4891-98c1-35b498da257b}",
"out_index": 0
},
{
"in_id": "{bed466d8-5ed0-4e8a-bba7-1c809cb4c3f7}",
"in_index": 0,
"out_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}",
"out_index": 0
},
{
"in_id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}",
"in_index": 1,
"out_id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}",
"out_index": 0
},
{
"in_id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}",
"in_index": 1,
"out_id": "{5e4c18b3-9a7f-4c0e-abe4-778be151ad06}",
"out_index": 0
},
{
"in_id": "{bb071807-e65e-4c31-acf0-d296efa665fa}",
"in_index": 0,
"out_id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}",
"out_index": 0
}
],
"inputs": [
{
"locationIndex": 0,
"name": "vertUV",
"role": "TexCoord",
"roleIndex": 0,
"type": "Float2"
}
],
"nodes": [
{
"id": "{becdd0d4-2b28-44f5-86c2-2ed6b846326c}",
"model": {
"name": "vec_decompose",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 1005.0000000000002,
"y": 201.76
}
},
{
"id": "{fbaddbbe-f9cd-4e8d-b7a8-40c10c96f580}",
"model": {
"name": "SampleTexture",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 167.75,
"y": 473.97222222222194
}
},
{
"id": "{ac98a68f-0160-4189-af31-b8278e7c119c}",
"model": {
"name": "Texture",
"preview_enabled": true,
"preview_height": 64,
"preview_width": 64,
"texture": "MaterialDiffuseMap",
"variable_name": ""
},
"position": {
"x": -10.194444444444457,
"y": 445
}
},
{
"id": "{be3547ff-0bf3-4701-9c27-c21e9d1322c3}",
"model": {
"name": "Output",
"output": "RenderTarget0",
"preview_enabled": true,
"preview_height": 128,
"preview_width": 128,
"variable_name": ""
},
"position": {
"x": 2598.5,
"y": 293.33333333333326
}
},
{
"id": "{93fdbb4c-bc81-4100-89a9-b465793099b9}",
"model": {
"name": "float_mul",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 1209.686666666667,
"y": 316.4066666666666
}
},
{
"id": "{bed466d8-5ed0-4e8a-bba7-1c809cb4c3f7}",
"model": {
"name": "vec_mul",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 377.1388888888888,
"y": 507.83333333333337
}
},
{
"id": "{07a43c79-67e2-46b1-87d4-e00d2da22820}",
"model": {
"buffer": "settings",
"field": "DiffuseColor",
"name": "BufferField",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 135.11111111111126,
"y": 643.5277777777775
}
},
{
"id": "{e1f86d56-eb21-4267-9075-e6b0cc875a6d}",
"model": {
"condition_name": "HAS_DIFFUSE_TEXTURE",
"name": "ConditionalExpression",
"preview_enabled": true,
"preview_height": 128,
"preview_width": 128,
"variable_name": ""
},
"position": {
"x": 602.5,
"y": 566.5
}
},
{
"id": "{ca2c2ac5-39e0-4814-9432-fbf3e20d3cad}",
"model": {
"input": "vertUV",
"name": "Input",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 646.0466666666667,
"y": 47.54000000000002
}
},
{
"id": "{f9ba0cce-3b85-4f95-a79e-a2f64d955d89}",
"model": {
"name": "Texture",
"preview_enabled": true,
"preview_height": 64,
"preview_width": 64,
"texture": "MaterialAlphaMap",
"variable_name": ""
},
"position": {
"x": 592.2799999999996,
"y": -30.780000000000058
}
},
{
"id": "{7750a050-b116-4e1b-bd89-b194c366d256}",
"model": {
"name": "SampleTexture",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 819.5933333333332,
"y": 6.606666666666669
}
},
{
"id": "{6fcfbcd0-c2df-41dd-bb50-74b455b9021f}",
"model": {
"name": "vec_decompose",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 1011.3799999999998,
"y": 21.560000000000016
}
},
{
"id": "{359a78e1-df0d-467f-907e-7bff04a55db5}",
"model": {
"name": "vec_compose4",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 1373.82,
"y": 198.09999999999997
}
},
{
"id": "{92d95fe0-84f6-4d27-91ea-992d5f73c04e}",
"model": {
"condition_name": "HAS_ALPHA_TEXTURE",
"name": "ConditionalExpression",
"preview_enabled": true,
"preview_height": 128,
"preview_width": 128,
"variable_name": ""
},
"position": {
"x": 1619.8933333333334,
"y": 447.44000000000005
}
},
{
"id": "{bb071807-e65e-4c31-acf0-d296efa665fa}",
"model": {
"name": "vec_decompose",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 2270,
"y": 67
}
},
{
"id": "{3cdb5bb1-f572-4055-a1af-460b152b0c13}",
"model": {
"name": "Discard",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 2694,
"y": 4
}
},
{
"id": "{d7acd173-9188-43b5-bfa1-31f17dff44ad}",
"model": {
"condition_name": "ALPHA_TEST",
"name": "ConditionalExpression",
"preview_enabled": true,
"preview_height": 128,
"preview_width": 128,
"variable_name": ""
},
"position": {
"x": 2240,
"y": -174
}
},
{
"id": "{1f9d52d7-4f44-4d96-8edb-fbc1239a93bb}",
"model": {
"name": "bool_constant",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"value": false,
"variable_name": ""
},
"position": {
"x": 2005,
"y": -99
}
},
{
"id": "{fc7542b2-5752-4891-98c1-35b498da257b}",
"model": {
"name": "float_lt",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 2000,
"y": -241
}
},
{
"id": "{743930bd-1d81-4d4c-b7ec-175a34838d69}",
"model": {
"buffer": "settings",
"field": "AlphaThreshold",
"name": "BufferField",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 1675,
"y": -254
}
},
{
"id": "{5e4c18b3-9a7f-4c0e-abe4-778be151ad06}",
"model": {
"input": "vertUV",
"name": "Input",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": -5,
"y": 542
}
}
],
"outputs": [
{
"locationIndex": 0,
"name": "RenderTarget0",
"type": "Float4"
}
],
"structs": [
{
"members": [
{
"name": "AlphaThreshold",
"type": "Float"
},
{
"name": "DiffuseColor",
"type": "Float4"
}
],
"name": "BasicSettings"
},
{
"members": [
{
"name": "worldMatrix",
"type": "Mat4x4"
},
{
"name": "invWorldMatrix",
"type": "Mat4x4"
}
],
"name": "InstanceData"
},
{
"members": [
{
"name": "projectionMatrix",
"type": "Mat4x4"
},
{
"name": "invProjectionMatrix",
"type": "Mat4x4"
},
{
"name": "viewMatrix",
"type": "Mat4x4"
},
{
"name": "invViewMatrix",
"type": "Mat4x4"
},
{
"name": "viewProjMatrix",
"type": "Mat4x4"
},
{
"name": "invViewProjMatrix",
"type": "Mat4x4"
},
{
"name": "renderTargetSize",
"type": "Float2"
},
{
"name": "invRenderTargetSize",
"type": "Float2"
},
{
"name": "eyePosition",
"type": "Float3"
}
],
"name": "ViewerData"
}
],
"textures": [
{
"bindingIndex": 2,
"name": "MaterialAlphaMap",
"setIndex": 2,
"type": "Sampler2D"
},
{
"bindingIndex": 1,
"name": "MaterialDiffuseMap",
"setIndex": 2,
"type": "Sampler2D"
}
],
"type": "Fragment"
}

View File

@ -1,349 +0,0 @@
{
"buffers": [
{
"bindingIndex": 0,
"name": "viewerData",
"setIndex": 0,
"structIndex": 2,
"type": "UniformBufferObject"
},
{
"bindingIndex": 0,
"name": "instanceData",
"setIndex": 1,
"structIndex": 1,
"type": "UniformBufferObject"
},
{
"bindingIndex": 0,
"name": "settings",
"setIndex": 2,
"structIndex": 0,
"type": "UniformBufferObject"
}
],
"conditions": [
],
"connections": [
{
"in_id": "{1bb9712b-8bff-4398-9e4e-fba79a04df0e}",
"in_index": 1,
"out_id": "{a2fff9e2-af6e-4c7f-80ee-ca3492f3c5ab}",
"out_index": 0
},
{
"in_id": "{62731a4b-f054-4f78-82da-08d2584e51ab}",
"in_index": 1,
"out_id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}",
"out_index": 0
},
{
"in_id": "{62731a4b-f054-4f78-82da-08d2584e51ab}",
"in_index": 0,
"out_id": "{1bb9712b-8bff-4398-9e4e-fba79a04df0e}",
"out_index": 0
},
{
"in_id": "{43ce1867-629f-442b-a672-540fa67f1446}",
"in_index": 0,
"out_id": "{33840c70-4e37-4127-bab0-23c4a4cb6d7f}",
"out_index": 0
},
{
"in_id": "{1bb9712b-8bff-4398-9e4e-fba79a04df0e}",
"in_index": 0,
"out_id": "{d8f4d14a-c67a-470f-87bf-8f60d9513c3b}",
"out_index": 0
},
{
"in_id": "{63bb13f0-55e3-451b-860e-568b65e09b04}",
"in_index": 0,
"out_id": "{62731a4b-f054-4f78-82da-08d2584e51ab}",
"out_index": 0
},
{
"in_id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}",
"in_index": 0,
"out_id": "{c3b906bc-d230-4026-a32e-34c00eaf4481}",
"out_index": 0
},
{
"in_id": "{d8f4d14a-c67a-470f-87bf-8f60d9513c3b}",
"in_index": 0,
"out_id": "{d32dfb1d-c8a4-4315-a710-90d2a51f68e8}",
"out_index": 0
},
{
"in_id": "{d8f4d14a-c67a-470f-87bf-8f60d9513c3b}",
"in_index": 1,
"out_id": "{c6058af1-6913-4218-a9b9-11adb5cdffa0}",
"out_index": 0
}
],
"inputs": [
{
"locationIndex": 0,
"name": "inPos",
"role": "Position",
"roleIndex": 0,
"type": "Float3"
},
{
"locationIndex": 1,
"name": "inTexCoord",
"role": "TexCoord",
"roleIndex": 0,
"type": "Float2"
}
],
"nodes": [
{
"id": "{43ce1867-629f-442b-a672-540fa67f1446}",
"model": {
"name": "Output",
"output": "vertUV",
"preview_enabled": false,
"preview_height": 128,
"preview_width": 128,
"variable_name": ""
},
"position": {
"x": 243,
"y": 292
}
},
{
"id": "{33840c70-4e37-4127-bab0-23c4a4cb6d7f}",
"model": {
"input": "inTexCoord",
"name": "Input",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 82,
"y": 287
}
},
{
"id": "{d8f4d14a-c67a-470f-87bf-8f60d9513c3b}",
"model": {
"name": "mat4_mul",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 248,
"y": 424
}
},
{
"id": "{1bb9712b-8bff-4398-9e4e-fba79a04df0e}",
"model": {
"name": "mat4_mul",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 463,
"y": 496
}
},
{
"id": "{c3b906bc-d230-4026-a32e-34c00eaf4481}",
"model": {
"input": "inPos",
"name": "Input",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 54,
"y": 675
}
},
{
"id": "{62731a4b-f054-4f78-82da-08d2584e51ab}",
"model": {
"name": "mat4vec_mul",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 699,
"y": 512
}
},
{
"id": "{7ac65f09-7f55-4a6e-9380-1bee5213f079}",
"model": {
"name": "cast_vec4",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"value": [
1,
0,
0,
0
],
"variable_name": ""
},
"position": {
"x": 345,
"y": 668
}
},
{
"id": "{63bb13f0-55e3-451b-860e-568b65e09b04}",
"model": {
"name": "PositionOutputValue",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 930,
"y": 524
}
},
{
"id": "{d32dfb1d-c8a4-4315-a710-90d2a51f68e8}",
"model": {
"buffer": "viewerData",
"field": "projectionMatrix",
"name": "BufferField",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 21,
"y": 374
}
},
{
"id": "{c6058af1-6913-4218-a9b9-11adb5cdffa0}",
"model": {
"buffer": "viewerData",
"field": "viewMatrix",
"name": "BufferField",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 25,
"y": 456
}
},
{
"id": "{a2fff9e2-af6e-4c7f-80ee-ca3492f3c5ab}",
"model": {
"buffer": "instanceData",
"field": "worldMatrix",
"name": "BufferField",
"preview_enabled": false,
"preview_height": 64,
"preview_width": 64,
"variable_name": ""
},
"position": {
"x": 27,
"y": 538
}
}
],
"outputs": [
{
"locationIndex": 0,
"name": "vertUV",
"type": "Float2"
}
],
"structs": [
{
"members": [
{
"name": "AlphaThreshold",
"type": "Float"
},
{
"name": "DiffuseColor",
"type": "Float4"
}
],
"name": "BasicSettings"
},
{
"members": [
{
"name": "worldMatrix",
"type": "Mat4x4"
},
{
"name": "invWorldMatrix",
"type": "Mat4x4"
}
],
"name": "InstanceData"
},
{
"members": [
{
"name": "projectionMatrix",
"type": "Mat4x4"
},
{
"name": "invProjectionMatrix",
"type": "Mat4x4"
},
{
"name": "viewMatrix",
"type": "Mat4x4"
},
{
"name": "invViewMatrix",
"type": "Mat4x4"
},
{
"name": "viewProjMatrix",
"type": "Mat4x4"
},
{
"name": "invViewProjMatrix",
"type": "Mat4x4"
},
{
"name": "renderTargetSize",
"type": "Float2"
},
{
"name": "invRenderTargetSize",
"type": "Float2"
},
{
"name": "eyePosition",
"type": "Float3"
}
],
"name": "ViewerData"
}
],
"textures": [
],
"type": "Vertex"
}

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;

View File

@ -116,7 +116,7 @@ namespace Nz::ShaderAst
StatementPtr AstCloner::Clone(DeclareOptionStatement& node)
{
auto clone = std::make_unique<DeclareOptionStatement>();
clone->initialValue = CloneExpression(node.initialValue);
clone->defaultValue = CloneExpression(node.defaultValue);
clone->optIndex = node.optIndex;
clone->optName = node.optName;
clone->optType = node.optType;

View File

@ -697,7 +697,9 @@ namespace Nz::ShaderAst
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, float> || std::is_same_v<T, Int32> || std::is_same_v<T, UInt32>)
if constexpr (std::is_same_v<T, NoValue>)
throw std::runtime_error("invalid type (value expected)");
else if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, float> || std::is_same_v<T, Int32> || std::is_same_v<T, UInt32>)
constantValues.push_back(arg);
else if constexpr (std::is_same_v<T, Vector2f> || std::is_same_v<T, Vector2i32>)
{
@ -815,9 +817,6 @@ namespace Nz::ShaderAst
ExpressionPtr AstOptimizer::Clone(ConditionalExpression& node)
{
if (!m_options.enabledOptions)
return AstCloner::Clone(node);
auto cond = CloneExpression(node.condition);
if (cond->GetType() != NodeType::ConstantValueExpression)
throw std::runtime_error("conditional expression condition must be a constant expression");
@ -884,9 +883,6 @@ namespace Nz::ShaderAst
StatementPtr AstOptimizer::Clone(ConditionalStatement& node)
{
if (!m_options.enabledOptions)
return AstCloner::Clone(node);
auto cond = CloneExpression(node.condition);
if (cond->GetType() != NodeType::ConstantValueExpression)
throw std::runtime_error("conditional expression condition must be a constant expression");

View File

@ -134,8 +134,8 @@ namespace Nz::ShaderAst
void AstRecursiveVisitor::Visit(DeclareOptionStatement& node)
{
if (node.initialValue)
node.initialValue->Visit(*this);
if (node.defaultValue)
node.defaultValue->Visit(*this);
}
void AstRecursiveVisitor::Visit(DeclareStructStatement& /*node*/)

View File

@ -140,19 +140,20 @@ namespace Nz::ShaderAst
Value(value);
};
static_assert(std::variant_size_v<decltype(node.value)> == 10);
static_assert(std::variant_size_v<decltype(node.value)> == 11);
switch (typeIndex)
{
case 0: SerializeValue(bool()); break;
case 1: SerializeValue(float()); break;
case 2: SerializeValue(Int32()); break;
case 3: SerializeValue(UInt32()); break;
case 4: SerializeValue(Vector2f()); break;
case 5: SerializeValue(Vector3f()); break;
case 6: SerializeValue(Vector4f()); break;
case 7: SerializeValue(Vector2i32()); break;
case 8: SerializeValue(Vector3i32()); break;
case 9: SerializeValue(Vector4i32()); break;
case 0: break;
case 1: SerializeValue(bool()); break;
case 2: SerializeValue(float()); break;
case 3: SerializeValue(Int32()); break;
case 4: SerializeValue(UInt32()); break;
case 5: SerializeValue(Vector2f()); break;
case 6: SerializeValue(Vector3f()); break;
case 7: SerializeValue(Vector4f()); break;
case 8: SerializeValue(Vector2i32()); break;
case 9: SerializeValue(Vector3i32()); break;
case 10: SerializeValue(Vector4i32()); break;
default: throw std::runtime_error("unexpected data type");
}
}
@ -261,7 +262,7 @@ namespace Nz::ShaderAst
OptVal(node.optIndex);
Value(node.optName);
Type(node.optType);
Node(node.initialValue);
Node(node.defaultValue);
}
void AstSerializerBase::Serialize(DeclareStructStatement& node)

View File

@ -13,7 +13,9 @@ namespace Nz::ShaderAst
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, bool>)
if constexpr (std::is_same_v<T, NoValue>)
return NoType{};
else if constexpr (std::is_same_v<T, bool>)
return PrimitiveType::Boolean;
else if constexpr (std::is_same_v<T, float>)
return PrimitiveType::Float32;

View File

@ -583,6 +583,9 @@ namespace Nz::ShaderAst
ExpressionPtr SanitizeVisitor::Clone(ConstantValueExpression& node)
{
if (std::holds_alternative<NoValue>(node.value))
throw std::runtime_error("expected a value");
auto clone = static_unique_pointer_cast<ConstantValueExpression>(AstCloner::Clone(node));
clone->cachedExpressionType = GetExpressionType(clone->value);
@ -980,12 +983,17 @@ namespace Nz::ShaderAst
auto clone = static_unique_pointer_cast<DeclareOptionStatement>(AstCloner::Clone(node));
clone->optType = ResolveType(clone->optType);
if (clone->initialValue && clone->optType != GetExpressionType(*clone->initialValue))
throw AstError{ "option " + clone->optName + " initial expression must be of the same type than the option" };
if (clone->defaultValue && clone->optType != GetExpressionType(*clone->defaultValue))
throw AstError{ "option " + clone->optName + " default expression must be of the same type than the option" };
std::size_t optionIndex = m_context->nextOptionIndex++;
clone->optIndex = RegisterConstant(clone->optName, TestBit(m_context->options.enabledOptions, optionIndex));
if (auto optionValueIt = m_context->options.optionValues.find(optionIndex); optionValueIt != m_context->options.optionValues.end())
clone->optIndex = RegisterConstant(clone->optName, optionValueIt->second);
else if (clone->defaultValue)
clone->optIndex = RegisterConstant(clone->optName, ComputeConstantValue(*clone->defaultValue));
else
throw AstError{ "missing option " + clone->optName + " value (has no default value)" };
if (m_context->options.removeOptionDeclaration)
return ShaderBuilder::NoOp();
@ -1186,8 +1194,6 @@ namespace Nz::ShaderAst
return m_context->constantValues[constantId];
};
optimizerOptions.enabledOptions = m_context->options.enabledOptions;
// Run optimizer on constant value to hopefully retrieve a single constant value
return static_unique_pointer_cast<T>(ShaderAst::Optimize(node, optimizerOptions));
}

View File

@ -107,7 +107,6 @@ namespace Nz
std::optional<ShaderStageType> selectedStage;
std::unordered_map<std::size_t, FunctionData> functions;
ShaderAst::DeclareFunctionStatement* entryPoint = nullptr;
UInt64 enabledOptions = 0;
};
struct Builtin
@ -139,6 +138,7 @@ namespace Nz
std::optional<ShaderStageType> stage;
std::stringstream stream;
std::unordered_map<std::size_t, ShaderAst::ConstantValue> optionValues;
std::unordered_map<std::size_t, ShaderAst::StructDescription*> structs;
std::unordered_map<std::size_t, std::string> variableNames;
std::vector<InOutField> inputFields;
@ -147,7 +147,6 @@ namespace Nz
const GlslWriter::BindingMapping& bindingMapping;
PreVisitor previsitor;
const States* states = nullptr;
UInt64 enabledOptions = 0;
bool isInEntryPoint = false;
unsigned int indentLevel = 0;
};
@ -155,7 +154,7 @@ namespace Nz
std::string GlslWriter::Generate(std::optional<ShaderStageType> shaderStage, ShaderAst::Statement& shader, const BindingMapping& bindingMapping, const States& states)
{
State state(bindingMapping);
state.enabledOptions = states.enabledOptions;
state.optionValues = states.optionValues;
state.stage = shaderStage;
m_currentState = &state;
@ -168,7 +167,7 @@ namespace Nz
ShaderAst::Statement* targetAst;
if (!states.sanitized)
{
sanitizedAst = Sanitize(shader, states.enabledOptions);
sanitizedAst = Sanitize(shader, states.optionValues);
targetAst = sanitizedAst.get();
}
else
@ -182,7 +181,6 @@ namespace Nz
targetAst = optimizedAst.get();
}
state.previsitor.enabledOptions = states.enabledOptions;
state.previsitor.selectedStage = shaderStage;
targetAst->Visit(state.previsitor);
@ -203,11 +201,11 @@ namespace Nz
return s_flipYUniformName;
}
ShaderAst::StatementPtr GlslWriter::Sanitize(ShaderAst::Statement& ast, UInt64 enabledOptions, std::string* error)
ShaderAst::StatementPtr GlslWriter::Sanitize(ShaderAst::Statement& ast, std::unordered_map<std::size_t, ShaderAst::ConstantValue> optionValues, std::string* error)
{
// Always sanitize for reserved identifiers
ShaderAst::SanitizeVisitor::Options options;
options.enabledOptions = enabledOptions;
options.optionValues = std::move(optionValues);
options.makeVariableNameUnique = true;
options.reservedIdentifiers = {
// All reserved GLSL keywords as of GLSL ES 3.2
@ -837,7 +835,9 @@ namespace Nz
if constexpr (std::is_same_v<T, Vector2i32> || std::is_same_v<T, Vector3i32> || std::is_same_v<T, Vector4i32>)
Append("i"); //< for ivec
if constexpr (std::is_same_v<T, bool>)
if constexpr (std::is_same_v<T, ShaderAst::NoValue>)
throw std::runtime_error("invalid type (value expected)");
else if constexpr (std::is_same_v<T, bool>)
Append((arg) ? "true" : "false");
else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, Int32> || std::is_same_v<T, UInt32>)
Append(std::to_string(arg));

View File

@ -643,7 +643,9 @@ namespace Nz
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, bool>)
if constexpr (std::is_same_v<T, ShaderAst::NoValue>)
throw std::runtime_error("invalid type (value expected)");
else if constexpr (std::is_same_v<T, bool>)
Append((arg) ? "true" : "false");
else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, Int32> || std::is_same_v<T, UInt32>)
Append(std::to_string(arg));
@ -733,10 +735,10 @@ namespace Nz
RegisterConstant(*node.optIndex, node.optName);
Append("option ", node.optName, ": ", node.optType);
if (node.initialValue)
if (node.defaultValue)
{
Append(" = ");
node.initialValue->Visit(*this);
node.defaultValue->Visit(*this);
}
Append(";");

View File

@ -418,7 +418,9 @@ namespace Nz
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, bool>)
if constexpr (std::is_same_v<T, ShaderAst::NoValue>)
throw std::runtime_error("invalid type (value expected)");
else if constexpr (std::is_same_v<T, bool>)
return ConstantBool{ arg };
else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, Int32> || std::is_same_v<T, UInt32>)
return ConstantScalar{ arg };

View File

@ -463,7 +463,7 @@ namespace Nz
if (!states.sanitized)
{
ShaderAst::SanitizeVisitor::Options options;
options.enabledOptions = states.enabledOptions;
options.optionValues = states.optionValues;
sanitizedAst = ShaderAst::Sanitize(shader, options);
targetAst = sanitizedAst.get();
@ -653,11 +653,6 @@ namespace Nz
return m_currentState->constantTypeCache.GetId(*m_currentState->constantTypeCache.BuildType(type));
}
bool SpirvWriter::IsOptionEnabled(std::size_t optionIndex) const
{
return TestBit<Nz::UInt64>(m_context.states->enabledOptions, optionIndex);
}
UInt32 SpirvWriter::RegisterConstant(const ShaderAst::ConstantValue& value)
{
return m_currentState->constantTypeCache.Register(*m_currentState->constantTypeCache.BuildConstant(value));

View File

@ -55,29 +55,24 @@ void CodeOutputWidget::Refresh()
{
try
{
Nz::UInt64 enabledOptions = 0;
Nz::ShaderWriter::States states;
for (std::size_t i = 0; i < m_shaderGraph.GetOptionCount(); ++i)
{
if (m_shaderGraph.IsOptionEnabled(i))
enabledOptions = Nz::SetBit<Nz::UInt64>(enabledOptions, i);
}
states.optionValues[i] = m_shaderGraph.IsOptionEnabled(i);
Nz::ShaderAst::StatementPtr shaderAst = m_shaderGraph.ToAst();
if (m_optimisationCheckbox->isChecked())
{
shaderAst = Nz::ShaderAst::Sanitize(*shaderAst);
Nz::ShaderAst::SanitizeVisitor::Options sanitizeOptions;
sanitizeOptions.optionValues = states.optionValues;
Nz::ShaderAst::AstOptimizer::Options optimOptions;
optimOptions.enabledOptions = enabledOptions;
shaderAst = Nz::ShaderAst::Sanitize(*shaderAst, sanitizeOptions);
Nz::ShaderAst::AstOptimizer optimiser;
shaderAst = optimiser.Optimise(*shaderAst, optimOptions);
shaderAst = optimiser.Optimise(*shaderAst);
}
Nz::ShaderWriter::States states;
states.enabledOptions = enabledOptions;
std::string output;
OutputLanguage outputLang = static_cast<OutputLanguage>(m_outputLang->currentIndex());
switch (outputLang)