You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderOptionGroup.cpp

325 lines
10 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
namespace RPI
{
const char* ShaderOptionGroup::DebugCategory = "ShaderOption";
ShaderOptionGroup::ShaderOptionGroup(const ShaderOptionGroup& rhs)
: m_layout(rhs.m_layout)
, m_id{rhs.m_id}
{
}
ShaderOptionGroup::ShaderOptionGroup(const ConstPtr<ShaderOptionGroupLayout>& shaderOptionGroupLayout)
: m_layout{shaderOptionGroupLayout}
{
AZ_Assert(m_layout, "ShaderOptionGroup created with null layout!");
Clear();
}
ShaderOptionGroup::ShaderOptionGroup(const ConstPtr<ShaderOptionGroupLayout>& shaderOptionGroupLayout, const ShaderVariantId& id)
: m_layout{shaderOptionGroupLayout}
, m_id{id}
{
AZ_Assert(m_layout, "ShaderOptionGroup created with null layout!");
}
void ShaderOptionGroup::Reflect(AZ::ReflectContext* context)
{
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<ShaderOptionGroup>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
->Attribute(AZ::Script::Attributes::Category, "Shader")
->Attribute(AZ::Script::Attributes::Module, "shader")
->Method("GetValueByOptionName", static_cast<ShaderOptionValue (ShaderOptionGroup::*)(const Name&) const>(&ShaderOptionGroup::GetValue))
->Method("GetShaderOptionDescriptors", &ShaderOptionGroup::GetShaderOptionDescriptors)
->Method("GetShaderVariantId", &ShaderOptionGroup::GetShaderVariantId)
;
}
}
void ShaderOptionGroup::Clear()
{
m_id.Reset();
}
ShaderOptionIndex ShaderOptionGroup::FindShaderOptionIndex(const Name& optionName) const
{
return m_layout->FindShaderOptionIndex(optionName);
}
bool ShaderOptionGroup::GetShaderOptionIndex(const Name& optionName, ShaderOptionIndex& optionIndex) const
{
optionIndex = FindShaderOptionIndex(optionName);
if (!optionIndex.IsValid())
{
AZ_Error(DebugCategory, false, "Shader Option '%s' does not exist", optionName.GetCStr());
return false;
}
return true;
}
bool ShaderOptionGroup::ValidateIndex(const ShaderOptionIndex& optionIndex) const
{
if (!optionIndex.IsValid())
{
AZ_Error(DebugCategory, false, "Invalid ShaderOptionIndex");
return false;
}
return true;
}
bool ShaderOptionGroup::SetValue(const Name& optionName, const Name& valueName)
{
ShaderOptionIndex index;
if (GetShaderOptionIndex(optionName, index))
{
return SetValue(index, valueName);
}
else
{
return false;
}
}
bool ShaderOptionGroup::SetValue(const Name& optionName, ShaderOptionValue valueIndex)
{
ShaderOptionIndex index;
if (GetShaderOptionIndex(optionName, index))
{
return SetValue(index, valueIndex);
}
else
{
return false;
}
}
ShaderOptionValue ShaderOptionGroup::GetValue(const Name& optionName) const
{
ShaderOptionIndex index;
if (GetShaderOptionIndex(optionName, index))
{
return GetValue(index);
}
else
{
return ShaderOptionValue{};
}
}
bool ShaderOptionGroup::SetValue(ShaderOptionIndex optionIndex, const Name& valueName)
{
if (ValidateIndex(optionIndex))
{
const ShaderOptionDescriptor& option = m_layout->GetShaderOption(optionIndex);
if (!option.Set(*this, valueName))
{
return false;
}
return true;
}
else
{
return false;
}
}
bool ShaderOptionGroup::SetValue(ShaderOptionIndex optionIndex, ShaderOptionValue valueIndex)
{
if (ValidateIndex(optionIndex))
{
const ShaderOptionDescriptor& option = m_layout->GetShaderOption(optionIndex);
if (!option.Set(*this, valueIndex))
{
return false;
}
return true;
}
else
{
return false;
}
}
ShaderOptionValue ShaderOptionGroup::GetValue(ShaderOptionIndex optionIndex) const
{
if (ValidateIndex(optionIndex))
{
const ShaderOptionDescriptor& option = m_layout->GetShaderOption(optionIndex);
return option.Get(*this);
}
else
{
return ShaderOptionValue{};
}
}
bool ShaderOptionGroup::ClearValue(const Name& optionName)
{
ShaderOptionIndex index;
if (GetShaderOptionIndex(optionName, index))
{
return ClearValue(index);
}
else
{
return false;
}
}
bool ShaderOptionGroup::ClearValue(ShaderOptionIndex optionIndex)
{
if (ValidateIndex(optionIndex))
{
const ShaderOptionDescriptor& option = m_layout->GetShaderOption(optionIndex);
option.Clear(*this);
return true;
}
return false;
}
void ShaderOptionGroup::SetAllToDefaultValues()
{
for (auto& option : m_layout->GetShaderOptions())
{
option.Set(*this, option.GetDefaultValue());
}
}
void ShaderOptionGroup::SetUnspecifiedToDefaultValues()
{
for (auto& option : m_layout->GetShaderOptions())
{
if (!(m_id.m_mask & option.GetBitMask()).any())
{
option.Set(*this, option.GetDefaultValue());
}
}
}
bool ShaderOptionGroup::IsFullySpecified() const
{
for (auto& option : m_layout->GetShaderOptions())
{
if (!(m_id.m_mask & option.GetBitMask()).any())
{
return false;
}
}
return true;
}
ShaderVariantKey ShaderOptionGroup::GetShaderVariantKeyFallbackValue() const
{
// By default the fallback value is the search key
auto fallbackValueKey = m_id.m_key;
// However, we have to make sure that all options are set, opting for default values where missing
for (auto& option : m_layout->GetShaderOptions())
{
if (!(m_id.m_mask & option.GetBitMask()).any())
{
const auto value = option.FindValue(option.GetDefaultValue());
// This is an assert, not error, because the build system should have detected this situation earlier.
AZ_Assert(value.IsValid(), "Default value for shader option '%s' is invalid.", option.GetName().GetCStr());
option.Set(fallbackValueKey, value);
}
}
return fallbackValueKey;
}
const ShaderVariantKey& ShaderOptionGroup::GetShaderVariantKey() const
{
return m_id.m_key;
}
const ShaderVariantKey& ShaderOptionGroup::GetShaderVariantMask() const
{
return m_id.m_mask;
}
const ShaderVariantId& ShaderOptionGroup::GetShaderVariantId() const
{
return m_id;
}
ShaderVariantKey& ShaderOptionGroup::GetShaderVariantKey()
{
return m_id.m_key;
}
ShaderVariantKey& ShaderOptionGroup::GetShaderVariantMask()
{
return m_id.m_mask;
}
const ShaderOptionGroupLayout* ShaderOptionGroup::GetShaderOptionLayout() const
{
return m_layout.get();
}
AZStd::string ShaderOptionGroup::ToString() const
{
AZStd::string s;
for (int i = 0; i < GetShaderOptionLayout()->GetShaderOptionCount(); ++i)
{
ShaderOptionIndex index{i};
const ShaderOptionDescriptor& option = GetShaderOptionLayout()->GetShaderOption(index);
const ShaderOptionValue& value = GetValue(index);
if (value.IsNull())
{
s += AZStd::string::format("%s=?, ", option.GetName().GetCStr());
}
else
{
//[GFX TODO][ATOM-3481] Report the names of enum options instead of numeric values. This depends on storing Names in NameIdReflectionMap.
s += AZStd::string::format("%s=%d, ", option.GetName().GetCStr(), value.GetIndex());
}
}
// Remove the trailing ", " from the last shader option in the string
static const size_t separateLength = 2;
if (s.size() >= separateLength)
{
s.resize(s.size() - separateLength);
}
return s;
}
const AZStd::vector<AZ::RPI::ShaderOptionDescriptor>& ShaderOptionGroup::GetShaderOptionDescriptors() const
{
return m_layout->GetShaderOptions();
}
} // namespace RPI
} // namespace AZ