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/Material/ShaderCollection.cpp

269 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 <AtomCore/std/containers/vector_set.h>
#include <Atom/RPI.Reflect/Material/ShaderCollection.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RHI/DrawListTagRegistry.h>
namespace AZ
{
namespace RPI
{
//! This allows ShaderCollection::Item to serialize only a ShaderVariantId rather than the ShaderOptionsGroup object,
//! but still provide the corresponding ShaderOptionsGroup for use at runtime.
//! RenderStates will be modified at runtime as well. It will be merged into the RenderStates stored in the corresponding ShaderVariant.
class ShaderVariantReferenceSerializationEvents
: public SerializeContext::IEventHandler
{
//! Called right before we start reading from the instance pointed by classPtr.
void OnReadBegin(void* classPtr) override
{
ShaderCollection::Item* shaderVariantReference = reinterpret_cast<ShaderCollection::Item*>(classPtr);
shaderVariantReference->m_shaderVariantId = shaderVariantReference->m_shaderOptionGroup.GetShaderVariantId();
}
//! Called right after we finish writing data to the instance pointed at by classPtr.
void OnWriteEnd(void* classPtr) override
{
ShaderCollection::Item* shaderVariantReference = reinterpret_cast<ShaderCollection::Item*>(classPtr);
// Dependent asset references aren't guaranteed to finish loading by the time this asset is serialized, only by
// the time this asset load is completed. But since the data is needed here, we will deliberately block until the
// shader asset has finished loading.
if (shaderVariantReference->m_shaderAsset.QueueLoad())
{
shaderVariantReference->m_shaderAsset.BlockUntilLoadComplete();
}
if (shaderVariantReference->m_shaderAsset.IsReady())
{
shaderVariantReference->m_shaderOptionGroup = ShaderOptionGroup{
shaderVariantReference->m_shaderAsset->GetShaderOptionGroupLayout(),
shaderVariantReference->m_shaderVariantId
};
}
else
{
shaderVariantReference->m_shaderOptionGroup = {};
}
}
};
void ShaderCollection::Reflect(AZ::ReflectContext* context)
{
ShaderCollection::Item::Reflect(context);
NameReflectionMapForIndex::Reflect(context);
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ShaderCollection>()
->Version(5)
->Field("ShaderItems", &ShaderCollection::m_shaderItems)
->Field("ShaderTagIndexMap", &ShaderCollection::m_shaderTagIndexMap)
;
}
}
void ShaderCollection::Item::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ShaderCollection::Item>()
->Version(6)
->EventHandler<ShaderVariantReferenceSerializationEvents>()
->Field("ShaderAsset", &ShaderCollection::Item::m_shaderAsset)
->Field("ShaderVariantId", &ShaderCollection::Item::m_shaderVariantId)
->Field("Enabled", &ShaderCollection::Item::m_enabled)
->Field("OwnedShaderOptionIndices", &ShaderCollection::Item::m_ownedShaderOptionIndices)
->Field("ShaderTag", &ShaderCollection::Item::m_shaderTag)
;
}
if (BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext->Class<Item>("ShaderCollectionItem")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
->Attribute(AZ::Script::Attributes::Category, "Shader")
->Attribute(AZ::Script::Attributes::Module, "shader")
->Method("GetShaderAsset", &Item::GetShaderAsset)
->Method("GetShaderAssetId", &Item::GetShaderAssetId)
->Method("GetShaderVariantId", &Item::GetShaderVariantId)
->Method("GetShaderOptionGroup", &Item::GetShaderOptionGroup)
;
}
}
size_t ShaderCollection::size() const
{
return m_shaderItems.size();
}
ShaderCollection::iterator ShaderCollection::begin()
{
return m_shaderItems.begin();
}
ShaderCollection::const_iterator ShaderCollection::begin() const
{
return m_shaderItems.begin();
}
ShaderCollection::iterator ShaderCollection::end()
{
return m_shaderItems.end();
}
ShaderCollection::const_iterator ShaderCollection::end() const
{
return m_shaderItems.end();
}
ShaderCollection::Item::Item()
{
m_renderStatesOverlay = RHI::GetInvalidRenderStates();
}
ShaderCollection::Item& ShaderCollection::operator[](size_t i)
{
return m_shaderItems[i];
}
const ShaderCollection::Item& ShaderCollection::operator[](size_t i) const
{
return m_shaderItems[i];
}
ShaderCollection::Item& ShaderCollection::operator[](const AZ::Name& shaderTag)
{
return m_shaderItems[m_shaderTagIndexMap.Find(shaderTag).GetIndex()];
}
const ShaderCollection::Item& ShaderCollection::operator[](const AZ::Name& shaderTag) const
{
return m_shaderItems[m_shaderTagIndexMap.Find(shaderTag).GetIndex()];
}
bool ShaderCollection::HasShaderTag(const AZ::Name& shaderTag) const
{
return (m_shaderTagIndexMap.Find(shaderTag).IsValid());
}
ShaderCollection::Item::Item(const Data::Asset<ShaderAsset>& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId)
: m_shaderAsset(shaderAsset)
, m_shaderVariantId(variantId)
, m_shaderTag(shaderTag)
, m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId)
{
}
ShaderCollection::Item::Item(Data::Asset<ShaderAsset>&& shaderAsset, const AZ::Name& shaderTag, ShaderVariantId variantId)
: m_shaderAsset(AZStd::move(shaderAsset))
, m_shaderVariantId(variantId)
, m_shaderTag(shaderTag)
, m_shaderOptionGroup(shaderAsset->GetShaderOptionGroupLayout(), variantId)
{
}
const Data::Asset<ShaderAsset>& ShaderCollection::Item::GetShaderAsset() const
{
return m_shaderAsset;
}
const ShaderVariantId& ShaderCollection::Item::GetShaderVariantId() const
{
return m_shaderOptionGroup.GetShaderVariantId();
}
const ShaderOptionGroup* ShaderCollection::Item::GetShaderOptions() const
{
return &m_shaderOptionGroup;
}
ShaderOptionGroup* ShaderCollection::Item::GetShaderOptions()
{
return &m_shaderOptionGroup;
}
bool ShaderCollection::Item::MaterialOwnsShaderOption(const AZ::Name& shaderOptionName) const
{
return m_ownedShaderOptionIndices.contains(m_shaderOptionGroup.FindShaderOptionIndex(shaderOptionName));
}
bool ShaderCollection::Item::MaterialOwnsShaderOption(ShaderOptionIndex shaderOptionIndex) const
{
return m_ownedShaderOptionIndices.contains(shaderOptionIndex);
}
const RHI::RenderStates* ShaderCollection::Item::GetRenderStatesOverlay() const
{
return &m_renderStatesOverlay;
}
RHI::RenderStates* ShaderCollection::Item::GetRenderStatesOverlay()
{
return &m_renderStatesOverlay;
}
RHI::DrawListTag ShaderCollection::Item::GetDrawListTagOverride() const
{
return m_drawListTagOverride;
}
void ShaderCollection::Item::SetDrawListTagOverride(RHI::DrawListTag drawList)
{
m_drawListTagOverride = drawList;
}
void ShaderCollection::Item::SetDrawListTagOverride(const AZ::Name& drawListName)
{
if (drawListName.IsEmpty())
{
m_drawListTagOverride.Reset();
return;
}
RHI::DrawListTagRegistry* drawListTagRegistry = RHI::RHISystemInterface::Get()->GetDrawListTagRegistry();
// Note: we should use FindTag instead of AcquireTag to avoid occupy DrawListTag entries.
RHI::DrawListTag newTag = drawListTagRegistry->FindTag(drawListName);
if (newTag.IsNull())
{
AZ_Error("ShaderCollection", false, "Failed to set draw list with name: %s.", drawListName.GetCStr());
return;
}
m_drawListTagOverride = newTag;
}
void ShaderCollection::Item::SetEnabled(bool enabled)
{
m_enabled = enabled;
}
bool ShaderCollection::Item::IsEnabled() const
{
return m_enabled;
}
const AZ::Name& ShaderCollection::Item::GetShaderTag() const
{
return m_shaderTag;
}
const Data::AssetId& ShaderCollection::Item::GetShaderAssetId() const
{
return m_shaderAsset->GetId();
}
const AZ::RPI::ShaderOptionGroup& ShaderCollection::Item::GetShaderOptionGroup() const
{
return m_shaderOptionGroup;
}
} // namespace RPI
} // namespace AZ