Shader: First working version on both Vulkan & OpenGL (ES)

This commit is contained in:
Jérôme Leclercq
2021-04-12 15:38:20 +02:00
parent f93a5bbdc1
commit ea99c6a19e
42 changed files with 1803 additions and 1053 deletions

View File

@@ -50,11 +50,6 @@ namespace Nz
return Compare(lhs.parameters, rhs.parameters) && Compare(lhs.returnType, rhs.returnType);
}
bool Compare(const Identifier& lhs, const Identifier& rhs) const
{
return lhs.name == rhs.name;
}
bool Compare(const Image& lhs, const Image& rhs) const
{
return lhs.arrayed == rhs.arrayed
@@ -114,6 +109,9 @@ namespace Nz
if (lhs.debugName != rhs.debugName)
return false;
if (lhs.funcId != rhs.funcId)
return false;
if (!Compare(lhs.initializer, rhs.initializer))
return false;
@@ -231,11 +229,6 @@ namespace Nz
void Register(const Integer&) {}
void Register(const Void&) {}
void Register(const Identifier& identifier)
{
Register(identifier);
}
void Register(const Image& image)
{
Register(image.sampledType);
@@ -406,6 +399,7 @@ namespace Nz
tsl::ordered_map<std::variant<AnyConstant, AnyType>, UInt32 /*id*/, AnyHasher, Eq> ids;
tsl::ordered_map<Variable, UInt32 /*id*/, AnyHasher, Eq> variableIds;
tsl::ordered_map<Structure, FieldOffsets /*fieldOffsets*/, AnyHasher, Eq> structureSizes;
StructCallback structCallback;
UInt32& nextResultId;
};
@@ -417,132 +411,8 @@ namespace Nz
SpirvConstantCache::SpirvConstantCache(SpirvConstantCache&& cache) noexcept = default;
SpirvConstantCache::~SpirvConstantCache() = default;
UInt32 SpirvConstantCache::GetId(const Constant& c)
{
auto it = m_internal->ids.find(c.constant);
if (it == m_internal->ids.end())
throw std::runtime_error("constant is not registered");
return it->second;
}
UInt32 SpirvConstantCache::GetId(const Type& t)
{
auto it = m_internal->ids.find(t.type);
if (it == m_internal->ids.end())
throw std::runtime_error("constant is not registered");
return it->second;
}
UInt32 SpirvConstantCache::GetId(const Variable& v)
{
auto it = m_internal->variableIds.find(v);
if (it == m_internal->variableIds.end())
throw std::runtime_error("variable is not registered");
return it->second;
}
UInt32 SpirvConstantCache::Register(Constant c)
{
AnyConstant& constant = c.constant;
DepRegisterer registerer(*this);
registerer.Register(constant);
std::size_t h = m_internal->ids.hash_function()(constant);
auto it = m_internal->ids.find(constant, h);
if (it == m_internal->ids.end())
{
UInt32 resultId = m_internal->nextResultId++;
it = m_internal->ids.emplace(std::move(constant), resultId).first;
}
return it.value();
}
UInt32 SpirvConstantCache::Register(Type t)
{
AnyType& type = t.type;
if (std::holds_alternative<Identifier>(type))
{
assert(m_identifierCallback);
return Register(*m_identifierCallback(std::get<Identifier>(type).name));
}
DepRegisterer registerer(*this);
registerer.Register(type);
std::size_t h = m_internal->ids.hash_function()(type);
auto it = m_internal->ids.find(type, h);
if (it == m_internal->ids.end())
{
UInt32 resultId = m_internal->nextResultId++;
it = m_internal->ids.emplace(std::move(type), resultId).first;
}
return it.value();
}
UInt32 SpirvConstantCache::Register(Variable v)
{
DepRegisterer registerer(*this);
registerer.Register(v);
std::size_t h = m_internal->variableIds.hash_function()(v);
auto it = m_internal->variableIds.find(v, h);
if (it == m_internal->variableIds.end())
{
UInt32 resultId = m_internal->nextResultId++;
it = m_internal->variableIds.emplace(std::move(v), resultId).first;
}
return it.value();
}
void SpirvConstantCache::SetIdentifierCallback(IdentifierCallback callback)
{
m_identifierCallback = std::move(callback);
}
void SpirvConstantCache::Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos)
{
for (auto&& [object, id] : m_internal->ids)
{
UInt32 resultId = id;
std::visit(overloaded
{
[&](const AnyConstant& constant) { Write(constant, resultId, constants); },
[&](const AnyType& type) { Write(type, resultId, annotations, constants, debugInfos); },
}, object);
}
for (auto&& [variable, id] : m_internal->variableIds)
{
const auto& var = variable;
UInt32 resultId = id;
if (!variable.debugName.empty())
debugInfos.Append(SpirvOp::OpName, resultId, variable.debugName);
constants.AppendVariadic(SpirvOp::OpVariable, [&](const auto& appender)
{
appender(GetId(*var.type));
appender(resultId);
appender(var.storageClass);
if (var.initializer)
appender(GetId((*var.initializer)->constant));
});
}
}
SpirvConstantCache& SpirvConstantCache::operator=(SpirvConstantCache&& cache) noexcept = default;
auto SpirvConstantCache::BuildConstant(const ShaderConstantValue& value) -> ConstantPtr
auto SpirvConstantCache::BuildConstant(const ShaderAst::ConstantValue& value) const -> ConstantPtr
{
return std::make_shared<Constant>(std::visit([&](auto&& arg) -> SpirvConstantCache::AnyConstant
{
@@ -590,7 +460,7 @@ namespace Nz
}, value));
}
auto SpirvConstantCache::BuildFunctionType(const ShaderAst::ExpressionType& retType, const std::vector<ShaderAst::ExpressionType>& parameters) -> TypePtr
auto SpirvConstantCache::BuildFunctionType(const ShaderAst::ExpressionType& retType, const std::vector<ShaderAst::ExpressionType>& parameters) const -> TypePtr
{
std::vector<SpirvConstantCache::TypePtr> parameterTypes;
parameterTypes.reserve(parameters.size());
@@ -604,7 +474,7 @@ namespace Nz
});
}
auto SpirvConstantCache::BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) -> TypePtr
auto SpirvConstantCache::BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const -> TypePtr
{
return std::make_shared<Type>(Pointer{
BuildType(type),
@@ -612,7 +482,7 @@ namespace Nz
});
}
auto SpirvConstantCache::BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) -> TypePtr
auto SpirvConstantCache::BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const -> TypePtr
{
return std::make_shared<Type>(Pointer{
BuildType(type),
@@ -620,7 +490,7 @@ namespace Nz
});
}
auto SpirvConstantCache::BuildType(const ShaderAst::ExpressionType& type) -> TypePtr
auto SpirvConstantCache::BuildType(const ShaderAst::ExpressionType& type) const -> TypePtr
{
return std::visit([&](auto&& arg) -> TypePtr
{
@@ -628,16 +498,13 @@ namespace Nz
}, type);
}
auto SpirvConstantCache::BuildType(const ShaderAst::IdentifierType& type) -> TypePtr
auto SpirvConstantCache::BuildType(const ShaderAst::IdentifierType& type) const -> TypePtr
{
return std::make_shared<Type>(
Identifier{
type.name
}
);
// No IdentifierType is expected (as they should have been resolved by now)
throw std::runtime_error("unexpected identifier");
}
auto SpirvConstantCache::BuildType(const ShaderAst::PrimitiveType& type) -> TypePtr
auto SpirvConstantCache::BuildType(const ShaderAst::PrimitiveType& type) const -> TypePtr
{
return std::make_shared<Type>([&]() -> AnyType
{
@@ -657,7 +524,7 @@ namespace Nz
}());
}
auto SpirvConstantCache::BuildType(const ShaderAst::MatrixType& type) -> TypePtr
auto SpirvConstantCache::BuildType(const ShaderAst::MatrixType& type) const -> TypePtr
{
return std::make_shared<Type>(
Matrix{
@@ -668,12 +535,12 @@ namespace Nz
});
}
auto SpirvConstantCache::BuildType(const ShaderAst::NoType& type) -> TypePtr
auto SpirvConstantCache::BuildType(const ShaderAst::NoType& type) const -> TypePtr
{
return std::make_shared<Type>(Void{});
}
auto SpirvConstantCache::BuildType(const ShaderAst::SamplerType& type) -> TypePtr
auto SpirvConstantCache::BuildType(const ShaderAst::SamplerType& type) const -> TypePtr
{
//TODO
auto imageType = Image{
@@ -690,7 +557,13 @@ namespace Nz
return std::make_shared<Type>(SampledImage{ std::make_shared<Type>(imageType) });
}
auto SpirvConstantCache::BuildType(const ShaderAst::StructDescription& structDesc) -> TypePtr
auto SpirvConstantCache::BuildType(const ShaderAst::StructType& type) const -> TypePtr
{
assert(m_internal->structCallback);
return BuildType(m_internal->structCallback(type.structIndex));
}
auto SpirvConstantCache::BuildType(const ShaderAst::StructDescription& structDesc) const -> TypePtr
{
Structure sType;
sType.name = structDesc.name;
@@ -705,11 +578,136 @@ namespace Nz
return std::make_shared<Type>(std::move(sType));
}
auto SpirvConstantCache::BuildType(const ShaderAst::VectorType& type) -> TypePtr
auto SpirvConstantCache::BuildType(const ShaderAst::VectorType& type) const -> TypePtr
{
return std::make_shared<Type>(Vector{ BuildType(type.type), UInt32(type.componentCount) });
}
auto SpirvConstantCache::BuildType(const ShaderAst::UniformType& type) const -> TypePtr
{
assert(std::holds_alternative<ShaderAst::StructType>(type.containedType));
return BuildType(std::get<ShaderAst::StructType>(type.containedType));
}
UInt32 SpirvConstantCache::GetId(const Constant& c)
{
auto it = m_internal->ids.find(c.constant);
if (it == m_internal->ids.end())
throw std::runtime_error("constant is not registered");
return it->second;
}
UInt32 SpirvConstantCache::GetId(const Type& t)
{
auto it = m_internal->ids.find(t.type);
if (it == m_internal->ids.end())
throw std::runtime_error("type is not registered");
return it->second;
}
UInt32 SpirvConstantCache::GetId(const Variable& v)
{
auto it = m_internal->variableIds.find(v);
if (it == m_internal->variableIds.end())
throw std::runtime_error("variable is not registered");
return it->second;
}
UInt32 SpirvConstantCache::Register(Constant c)
{
AnyConstant& constant = c.constant;
DepRegisterer registerer(*this);
registerer.Register(constant);
std::size_t h = m_internal->ids.hash_function()(constant);
auto it = m_internal->ids.find(constant, h);
if (it == m_internal->ids.end())
{
UInt32 resultId = m_internal->nextResultId++;
it = m_internal->ids.emplace(std::move(constant), resultId).first;
}
return it.value();
}
UInt32 SpirvConstantCache::Register(Type t)
{
AnyType& type = t.type;
DepRegisterer registerer(*this);
registerer.Register(type);
std::size_t h = m_internal->ids.hash_function()(type);
auto it = m_internal->ids.find(type, h);
if (it == m_internal->ids.end())
{
UInt32 resultId = m_internal->nextResultId++;
it = m_internal->ids.emplace(std::move(type), resultId).first;
}
return it.value();
}
UInt32 SpirvConstantCache::Register(Variable v)
{
DepRegisterer registerer(*this);
registerer.Register(v);
std::size_t h = m_internal->variableIds.hash_function()(v);
auto it = m_internal->variableIds.find(v, h);
if (it == m_internal->variableIds.end())
{
UInt32 resultId = m_internal->nextResultId++;
it = m_internal->variableIds.emplace(std::move(v), resultId).first;
}
return it.value();
}
void SpirvConstantCache::SetStructCallback(StructCallback callback)
{
m_internal->structCallback = std::move(callback);
}
void SpirvConstantCache::Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos)
{
for (auto&& [object, id] : m_internal->ids)
{
UInt32 resultId = id;
std::visit(overloaded
{
[&](const AnyConstant& constant) { Write(constant, resultId, constants); },
[&](const AnyType& type) { Write(type, resultId, annotations, constants, debugInfos); },
}, object);
}
for (auto&& [variable, id] : m_internal->variableIds)
{
const auto& var = variable;
UInt32 resultId = id;
if (!variable.debugName.empty())
debugInfos.Append(SpirvOp::OpName, resultId, variable.debugName);
constants.AppendVariadic(SpirvOp::OpVariable, [&](const auto& appender)
{
appender(GetId(*var.type));
appender(resultId);
appender(var.storageClass);
if (var.initializer)
appender(GetId((*var.initializer)->constant));
});
}
}
SpirvConstantCache& SpirvConstantCache::operator=(SpirvConstantCache&& cache) noexcept = default;
void SpirvConstantCache::Write(const AnyConstant& constant, UInt32 resultId, SpirvSection& constants)
{
std::visit([&](auto&& arg)