| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- /*
- * 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/RHI.Edit/ShaderPlatformInterface.h>
- #include <Atom/RPI.Reflect/Shader/ShaderAssetCreator.h>
- namespace AZ
- {
- namespace RPI
- {
- void ShaderAssetCreator::Begin(const Data::AssetId& assetId)
- {
- BeginCommon(assetId);
- }
- void ShaderAssetCreator::SetName(const Name& name)
- {
- if (ValidateIsReady())
- {
- m_asset->m_name = name;
- }
- }
-
- void ShaderAssetCreator::SetDrawListName(const Name& name)
- {
- if (ValidateIsReady())
- {
- m_asset->m_drawListName = name;
- }
- }
- void ShaderAssetCreator::SetShaderOptionGroupLayout(const Ptr<ShaderOptionGroupLayout>& shaderOptionGroupLayout)
- {
- if (ValidateIsReady())
- {
- m_asset->m_shaderOptionGroupLayout = shaderOptionGroupLayout;
- m_defaultShaderOptionGroup = ShaderOptionGroup{shaderOptionGroupLayout};
- }
- }
- void ShaderAssetCreator::SetShaderOptionDefaultValue(const Name& optionName, const Name& optionValue)
- {
- if (ValidateIsReady())
- {
- if (!m_defaultShaderOptionGroup.SetValue(optionName, optionValue))
- {
- ReportError("Could not set shader option '%s'.", optionName.GetCStr());
- }
- }
- }
- void ShaderAssetCreator::BeginAPI(RHI::APIType type)
- {
- if (ValidateIsReady())
- {
- ShaderAsset::ShaderApiDataContainer shaderData;
- shaderData.m_APIType = type;
- m_asset->m_currentAPITypeIndex = m_asset->m_perAPIShaderData.size();
- m_asset->m_perAPIShaderData.push_back(shaderData);
- }
- }
- void ShaderAssetCreator::BeginSupervariant(const Name& name)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (m_currentSupervariant)
- {
- ReportError("Call EndSupervariant() before calling BeginSupervariant again.");
- return;
- }
- if (m_asset->m_currentAPITypeIndex == ShaderAsset::InvalidAPITypeIndex)
- {
- ReportError("Can not begin supervariant with name [%s] because this function must be called between BeginAPI()/EndAPI()", name.GetCStr());
- return;
- }
- if (m_asset->m_perAPIShaderData.empty())
- {
- ReportError("Can not add supervariant with name [%s] because there's no per API shader data", name.GetCStr());
- return;
- }
- ShaderAsset::ShaderApiDataContainer& perAPIShaderData = m_asset->m_perAPIShaderData[m_asset->m_perAPIShaderData.size() - 1];
- if (perAPIShaderData.m_supervariants.empty())
- {
- if (!name.IsEmpty())
- {
- ReportError("The first supervariant must be nameless. Name [%s] is invalid", name.GetCStr());
- return;
- }
- }
- else
- {
- if (name.IsEmpty())
- {
- ReportError(
- "Only the first supervariant can be nameless. So far there are %zu supervariants",
- perAPIShaderData.m_supervariants.size());
- return;
- }
- }
- perAPIShaderData.m_supervariants.push_back({});
- m_currentSupervariant = &perAPIShaderData.m_supervariants[perAPIShaderData.m_supervariants.size() - 1];
- m_currentSupervariant->m_name = name;
- }
- void ShaderAssetCreator::SetSrgLayoutList(const ShaderResourceGroupLayoutList& srgLayoutList)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (!m_currentSupervariant)
- {
- ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
- return;
- }
- m_currentSupervariant->m_srgLayoutList = srgLayoutList;
- for (auto srgLayout : m_currentSupervariant->m_srgLayoutList)
- {
- if (!srgLayout->Finalize())
- {
- ReportError(
- "The current supervariant [%s], failed to finalize SRG Layout [%s]", m_currentSupervariant->m_name.GetCStr(),
- srgLayout->GetName().GetCStr());
- return;
- }
- }
- }
- //! [Required] Assigns the pipeline layout descriptor shared by all variants in the shader. Shader variants
- //! embedded in a single shader asset are required to use the same pipeline layout. It is not necessary to call
- //! Finalize() on the pipeline layout prior to assignment, but still permitted.
- void ShaderAssetCreator::SetPipelineLayout(RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (!m_currentSupervariant)
- {
- ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
- return;
- }
- m_currentSupervariant->m_pipelineLayoutDescriptor = pipelineLayoutDescriptor;
- }
- //! Assigns the contract for inputs required by the shader.
- void ShaderAssetCreator::SetInputContract(const ShaderInputContract& contract)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (!m_currentSupervariant)
- {
- ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
- return;
- }
- m_currentSupervariant->m_inputContract = contract;
- }
- //! Assigns the contract for outputs required by the shader.
- void ShaderAssetCreator::SetOutputContract(const ShaderOutputContract& contract)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (!m_currentSupervariant)
- {
- ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
- return;
- }
- m_currentSupervariant->m_outputContract = contract;
- }
- //! Assigns the render states for the draw pipeline. Ignored for non-draw pipelines.
- void ShaderAssetCreator::SetRenderStates(const RHI::RenderStates& renderStates)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (!m_currentSupervariant)
- {
- ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
- return;
- }
- m_currentSupervariant->m_renderStates = renderStates;
- }
- //! [Optional] Not all shaders have attributes before functions. Some attributes do not exist for all RHI::APIType either.
- void ShaderAssetCreator::SetShaderStageAttributeMapList(const RHI::ShaderStageAttributeMapList& shaderStageAttributeMapList)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (!m_currentSupervariant)
- {
- ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
- return;
- }
- m_currentSupervariant->m_attributeMaps = shaderStageAttributeMapList;
- }
- //! [Required] There's always a root variant for each supervariant.
- void ShaderAssetCreator::SetRootShaderVariantAsset(Data::Asset<ShaderVariantAsset> shaderVariantAsset)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (!m_currentSupervariant)
- {
- ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
- return;
- }
- if (!shaderVariantAsset)
- {
- ReportError("Invalid root variant");
- return;
- }
- m_currentSupervariant->m_rootShaderVariantAsset = shaderVariantAsset;
- }
- void ShaderAssetCreator::SetUseSpecializationConstants(bool value)
- {
- if (!ValidateIsReady())
- {
- return;
- }
- if (!m_currentSupervariant)
- {
- ReportError("BeginSupervariant() should be called first before calling %s", __FUNCTION__);
- return;
- }
- m_currentSupervariant->m_useSpecializationConstants = value;
- }
- static RHI::PipelineStateType GetPipelineStateType(const Data::Asset<ShaderVariantAsset>& shaderVariantAsset)
- {
- if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Vertex) ||
- shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Geometry) ||
- shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Fragment))
- {
- return RHI::PipelineStateType::Draw;
- }
- if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::Compute))
- {
- return RHI::PipelineStateType::Dispatch;
- }
- if (shaderVariantAsset->GetShaderStageFunction(RHI::ShaderStage::RayTracing))
- {
- return RHI::PipelineStateType::RayTracing;
- }
- return RHI::PipelineStateType::Count;
- }
- bool ShaderAssetCreator::EndSupervariant()
- {
- if (!ValidateIsReady())
- {
- return false;
- }
- if (!m_currentSupervariant)
- {
- ReportError("Can not end a supervariant that has not started");
- return false;
- }
- if (!m_currentSupervariant->m_rootShaderVariantAsset.IsReady())
- {
- ReportError(
- "The current supervariant [%s], is missing the root ShaderVariantAsset", m_currentSupervariant->m_name.GetCStr());
- return false;
- }
- // Supervariant specific resources
- if (m_currentSupervariant->m_pipelineLayoutDescriptor)
- {
- if (!m_currentSupervariant->m_pipelineLayoutDescriptor->IsFinalized())
- {
- if (m_currentSupervariant->m_pipelineLayoutDescriptor->Finalize() != RHI::ResultCode::Success)
- {
- ReportError("Failed to finalize pipeline layout descriptor.");
- return false;
- }
- }
- }
- else
- {
- ReportError("PipelineLayoutDescriptor not specified.");
- return false;
- }
- const ShaderInputContract& shaderInputContract = m_currentSupervariant->m_inputContract;
- // Validate that each stream ID appears only once.
- for (const auto& channel : shaderInputContract.m_streamChannels)
- {
- int count = 0;
- for (const auto& searchChannel : shaderInputContract.m_streamChannels)
- {
- if (channel.m_semantic == searchChannel.m_semantic)
- {
- ++count;
- }
- }
- if (count > 1)
- {
- ReportError(
- "Input stream channel [%s] appears multiple times. For supervariant with name [%s]",
- channel.m_semantic.ToString().c_str(), m_currentSupervariant->m_name.GetCStr());
- return false;
- }
- }
- auto pipelineStateType = GetPipelineStateType(m_currentSupervariant->m_rootShaderVariantAsset);
- if (pipelineStateType == RHI::PipelineStateType::Count)
- {
- ReportError("Invalid pipelineStateType for supervariant [%s]", m_currentSupervariant->m_name.GetCStr());
- return false;
- }
- if (m_currentSupervariant->m_name.IsEmpty())
- {
- m_asset->m_pipelineStateType = pipelineStateType;
- }
- else
- {
- if (m_asset->m_pipelineStateType != pipelineStateType)
- {
- ReportError("All supervariants must be of the same pipelineStateType. Current pipelineStateType is [%d], but for supervariant [%s] the pipelineStateType is [%d]",
- m_asset->m_pipelineStateType, m_currentSupervariant->m_name.GetCStr(), pipelineStateType);
- return false;
- }
- }
- m_currentSupervariant->m_useSpecializationConstants =
- m_currentSupervariant->m_useSpecializationConstants && m_asset->m_shaderOptionGroupLayout->UseSpecializationConstants();
- m_currentSupervariant = nullptr;
- return true;
- }
- bool ShaderAssetCreator::EndAPI()
- {
- if (!ValidateIsReady())
- {
- return false;
- }
- if (m_currentSupervariant)
- {
- ReportError("EndSupervariant() must be called before calling EndAPI()");
- return false;
- }
-
- m_asset->m_currentAPITypeIndex = ShaderAsset::InvalidAPITypeIndex;
- return true;
- }
- bool ShaderAssetCreator::End(Data::Asset<ShaderAsset>& shaderAsset)
- {
- if (!ValidateIsReady())
- {
- return false;
- }
- if (m_asset->m_perAPIShaderData.empty())
- {
- ReportError("Empty shader data. Check that a valid RHI is enabled for this platform.");
- return false;
- }
-
- if (!m_asset->SelectShaderApiData())
- {
- ReportError("Failed to finalize the ShaderAsset.");
- return false;
- }
- m_asset->m_defaultShaderOptionValueOverrides = m_defaultShaderOptionGroup.GetShaderVariantId();
- m_asset->SetReady();
- return EndCommon(shaderAsset);
- }
- void ShaderAssetCreator::Clone(
- const Data::AssetId& assetId,
- const ShaderAsset& sourceShaderAsset,
- [[maybe_unused]] const ShaderSupervariants& supervariants,
- const AZStd::vector<RHI::ShaderPlatformInterface*>& platformInterfaces)
- {
- BeginCommon(assetId);
- m_asset->m_name = sourceShaderAsset.m_name;
- m_asset->m_pipelineStateType = sourceShaderAsset.m_pipelineStateType;
- m_asset->m_drawListName = sourceShaderAsset.m_drawListName;
- m_asset->m_shaderOptionGroupLayout = sourceShaderAsset.m_shaderOptionGroupLayout;
- // copy the perAPIShaderData
- for (auto& perAPIShaderData : sourceShaderAsset.m_perAPIShaderData)
- {
- // find the API in the list of supported APIs on this platform
- AZStd::vector<RHI::ShaderPlatformInterface*>::const_iterator itFoundAPI = AZStd::find_if(
- platformInterfaces.begin(),
- platformInterfaces.end(),
- [&perAPIShaderData](const RHI::ShaderPlatformInterface* shaderPlatformInterface)
- {
- return perAPIShaderData.m_APIType == shaderPlatformInterface->GetAPIType();
- });
- if (itFoundAPI == platformInterfaces.end())
- {
- // the API is not supported on this platform, skip this entry
- continue;
- }
- if (perAPIShaderData.m_supervariants.empty())
- {
- ReportWarning("Attempting to clone a shader asset that has no supervariants for API [%d]", perAPIShaderData.m_APIType);
- continue;
- }
- if (perAPIShaderData.m_supervariants.size() != supervariants.size())
- {
- ReportError("Incorrect number of supervariants provided to ShaderAssetCreator::Clone");
- return;
- }
- m_asset->m_perAPIShaderData.push_back(perAPIShaderData);
- // set the supervariants for this API
- for (auto& supervariant : m_asset->m_perAPIShaderData.back().m_supervariants)
- {
- // find the matching Supervariant by name from the incoming list
- ShaderSupervariants::const_iterator itFoundSuperVariant = AZStd::find_if(
- supervariants.begin(),
- supervariants.end(),
- [&supervariant](const ShaderSupervariant& shaderSupervariant)
- {
- return supervariant.m_name == shaderSupervariant.m_name;
- });
- if (itFoundSuperVariant == supervariants.end())
- {
- ReportError("Failed to find supervariant [%s]", supervariant.m_name.GetCStr());
- return;
- }
- // find the matching ShaderVariantAsset for this API
- ShaderRootVariantAssets::const_iterator itFoundRootShaderVariantAsset = AZStd::find_if(
- itFoundSuperVariant->m_rootVariantAssets.begin(),
- itFoundSuperVariant->m_rootVariantAssets.end(),
- [&perAPIShaderData](const ShaderRootVariantAssetPair& rootShaderVariantAsset)
- {
- return perAPIShaderData.m_APIType == rootShaderVariantAsset.first;
- });
- if (itFoundRootShaderVariantAsset == itFoundSuperVariant->m_rootVariantAssets.end())
- {
- ReportWarning("Failed to find root shader variant asset for API [%d] Supervariant [%s]", perAPIShaderData.m_APIType, supervariant.m_name.GetCStr());
- }
- else
- {
- supervariant.m_rootShaderVariantAsset = itFoundRootShaderVariantAsset->second;
- }
- }
- }
- }
- } // namespace RPI
- } // namespace AZ
|