rendering: formalize shader keyword metadata contract
This commit is contained in:
@@ -95,6 +95,21 @@ bool IsTextureMaterialPropertyType(MaterialPropertyType type) {
|
||||
return type == MaterialPropertyType::Texture || type == MaterialPropertyType::Cubemap;
|
||||
}
|
||||
|
||||
Containers::String NormalizeShaderKeyword(const Containers::String& keyword) {
|
||||
const Containers::String normalized = keyword.Trim();
|
||||
if (normalized.Empty() ||
|
||||
normalized == Containers::String("_") ||
|
||||
normalized == Containers::String("__")) {
|
||||
return Containers::String();
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
bool CompareShaderKeywords(const Containers::String& left, const Containers::String& right) {
|
||||
return std::strcmp(left.CStr(), right.CStr()) < 0;
|
||||
}
|
||||
|
||||
MaterialPropertyType GetMaterialPropertyTypeForShaderProperty(ShaderPropertyType type) {
|
||||
switch (type) {
|
||||
case ShaderPropertyType::Float:
|
||||
@@ -312,6 +327,7 @@ Material::~Material() {
|
||||
// resetting them here avoids teardown-order issues during destruction.
|
||||
m_shader.Reset();
|
||||
m_tags = Containers::Array<MaterialTagEntry>();
|
||||
m_keywordSet = ShaderKeywordSet();
|
||||
m_properties = Containers::HashMap<Containers::String, MaterialProperty>();
|
||||
m_constantLayout = Containers::Array<MaterialConstantFieldDesc>();
|
||||
m_constantBufferData = Containers::Array<Core::uint8>();
|
||||
@@ -324,6 +340,7 @@ void Material::Release() {
|
||||
m_renderState = MaterialRenderState();
|
||||
m_shaderPass.Clear();
|
||||
m_tags.Clear();
|
||||
m_keywordSet.enabledKeywords.Clear();
|
||||
m_properties.Clear();
|
||||
m_constantLayout.Clear();
|
||||
m_textureBindings.Clear();
|
||||
@@ -336,6 +353,7 @@ void Material::Release() {
|
||||
void Material::SetShader(const ResourceHandle<Shader>& shader) {
|
||||
m_shader = shader;
|
||||
SyncShaderSchemaProperties(true);
|
||||
SyncShaderSchemaKeywords(true);
|
||||
MarkChanged(true);
|
||||
}
|
||||
|
||||
@@ -420,6 +438,90 @@ Containers::String Material::GetTagValue(Core::uint32 index) const {
|
||||
return index < m_tags.Size() ? m_tags[index].value : Containers::String();
|
||||
}
|
||||
|
||||
void Material::EnableKeyword(const Containers::String& keyword) {
|
||||
const Containers::String normalizedKeyword = NormalizeShaderKeyword(keyword);
|
||||
if (normalizedKeyword.Empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_shader.Get() != nullptr && !m_shader->DeclaresKeyword(normalizedKeyword)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const Containers::String& existingKeyword : m_keywordSet.enabledKeywords) {
|
||||
if (existingKeyword == normalizedKeyword) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_keywordSet.enabledKeywords.PushBack(normalizedKeyword);
|
||||
std::sort(
|
||||
m_keywordSet.enabledKeywords.begin(),
|
||||
m_keywordSet.enabledKeywords.end(),
|
||||
CompareShaderKeywords);
|
||||
MarkChanged(false);
|
||||
}
|
||||
|
||||
void Material::DisableKeyword(const Containers::String& keyword) {
|
||||
const Containers::String normalizedKeyword = NormalizeShaderKeyword(keyword);
|
||||
if (normalizedKeyword.Empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t keywordIndex = 0; keywordIndex < m_keywordSet.enabledKeywords.Size(); ++keywordIndex) {
|
||||
if (m_keywordSet.enabledKeywords[keywordIndex] == normalizedKeyword) {
|
||||
if (keywordIndex != m_keywordSet.enabledKeywords.Size() - 1) {
|
||||
m_keywordSet.enabledKeywords[keywordIndex] = std::move(m_keywordSet.enabledKeywords.Back());
|
||||
}
|
||||
m_keywordSet.enabledKeywords.PopBack();
|
||||
std::sort(
|
||||
m_keywordSet.enabledKeywords.begin(),
|
||||
m_keywordSet.enabledKeywords.end(),
|
||||
CompareShaderKeywords);
|
||||
MarkChanged(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Material::SetKeywordEnabled(const Containers::String& keyword, bool enabled) {
|
||||
if (enabled) {
|
||||
EnableKeyword(keyword);
|
||||
} else {
|
||||
DisableKeyword(keyword);
|
||||
}
|
||||
}
|
||||
|
||||
bool Material::IsKeywordEnabled(const Containers::String& keyword) const {
|
||||
const Containers::String normalizedKeyword = NormalizeShaderKeyword(keyword);
|
||||
if (normalizedKeyword.Empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const Containers::String& existingKeyword : m_keywordSet.enabledKeywords) {
|
||||
if (existingKeyword == normalizedKeyword) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Material::ClearKeywords() {
|
||||
if (m_keywordSet.enabledKeywords.Empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_keywordSet.enabledKeywords.Clear();
|
||||
MarkChanged(false);
|
||||
}
|
||||
|
||||
Containers::String Material::GetKeyword(Core::uint32 index) const {
|
||||
return index < m_keywordSet.enabledKeywords.Size()
|
||||
? m_keywordSet.enabledKeywords[index]
|
||||
: Containers::String();
|
||||
}
|
||||
|
||||
void Material::SetFloat(const Containers::String& name, float value) {
|
||||
if (!CanAssignPropertyType(name, MaterialPropertyType::Float)) {
|
||||
return;
|
||||
@@ -976,6 +1078,29 @@ void Material::SyncShaderSchemaProperties(bool removeUnknownProperties) {
|
||||
}
|
||||
}
|
||||
|
||||
void Material::SyncShaderSchemaKeywords(bool removeUnknownKeywords) {
|
||||
if (m_shader.Get() == nullptr || !removeUnknownKeywords) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t keywordIndex = 0; keywordIndex < m_keywordSet.enabledKeywords.Size();) {
|
||||
if (m_shader->DeclaresKeyword(m_keywordSet.enabledKeywords[keywordIndex])) {
|
||||
++keywordIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keywordIndex != m_keywordSet.enabledKeywords.Size() - 1) {
|
||||
m_keywordSet.enabledKeywords[keywordIndex] = std::move(m_keywordSet.enabledKeywords.Back());
|
||||
}
|
||||
m_keywordSet.enabledKeywords.PopBack();
|
||||
}
|
||||
|
||||
std::sort(
|
||||
m_keywordSet.enabledKeywords.begin(),
|
||||
m_keywordSet.enabledKeywords.end(),
|
||||
CompareShaderKeywords);
|
||||
}
|
||||
|
||||
void Material::MarkChanged(bool updateConstantBuffer) {
|
||||
if (updateConstantBuffer) {
|
||||
UpdateConstantBuffer();
|
||||
@@ -992,6 +1117,7 @@ void Material::UpdateMemorySize() {
|
||||
sizeof(MaterialRenderState) +
|
||||
m_shaderPass.Length() +
|
||||
m_tags.Size() * sizeof(MaterialTagEntry) +
|
||||
m_keywordSet.enabledKeywords.Size() * sizeof(Containers::String) +
|
||||
m_textureBindings.Size() * sizeof(MaterialTextureBinding) +
|
||||
m_properties.Size() * sizeof(MaterialProperty) +
|
||||
m_name.Length() +
|
||||
@@ -1002,6 +1128,10 @@ void Material::UpdateMemorySize() {
|
||||
m_memorySize += tag.value.Length();
|
||||
}
|
||||
|
||||
for (const Containers::String& keyword : m_keywordSet.enabledKeywords) {
|
||||
m_memorySize += keyword.Length();
|
||||
}
|
||||
|
||||
for (const MaterialConstantFieldDesc& field : m_constantLayout) {
|
||||
m_memorySize += field.name.Length();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user