/* * 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 #include #include #include 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(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(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(context)) { serializeContext->Class() ->Version(5) ->Field("ShaderItems", &ShaderCollection::m_shaderItems) ->Field("ShaderTagIndexMap", &ShaderCollection::m_shaderTagIndexMap) ; } } void ShaderCollection::Item::Reflect(AZ::ReflectContext* context) { if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() ->Version(6) ->EventHandler() ->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(context)) { behaviorContext->Class("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, 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, 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& 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