[ATOM-15472] Shader Build Pipeline: Remove Deprecated Files And Funct… (#1079)

* [ATOM-15472] Shader Build Pipeline: Remove Deprecated Files And Functions That
Predate The Shader Supervariants

These are the essential impactful changes as a result of deprecating the
ShaderResourceGroupAsset.

* Addressed feedback by @moudgils. Better comments in header files.

* More updates related with deprecation of ShaderResourceGroupAsset

* Deleted the temporary version 2 classes.

* Updated version of the shader asset builders.

* Updated version of all the shader related classes impacted
by the Supervariant concept and deprecation of ShaderResourceGroupAsset

* Changes to *.pass and DGI, Reflections and RayTracing.

* changes to material related assets

* changes to core lights

* Changes to auxgeom/dynamic draw.

* changes to decals, lyshine, imguipass

* changes to RPI Pass classes

* Shader for SceneSrg, ViewSrg and ForwardPass Srgs.

* changes to mesh, skinned mesh, Morphtarget.

* Fixes to RayTracingPass.cpp & now allow empty srg in shaders.

* Updated Atom_RPI.Tests

* Simplified InstanceDatabase by removing AddHandler

------------------------------------------------------------------------------------
* Updated DiffuseGI precompiled shaders.
Added RayTracingSceneSrg and RayTracingMaterialSrg shader asset.
Updated ShaderAssetCreator::Clone to handle the supervariant when processing root variants.
Co-authored-by: Doug McDiarmid <dmcdiar@amazon.com>
------------------------------------------------------------------------------------

* Changed semantics for some PassSrg to SRG_PerPass_WithFallback.

AuxGeom/FixedShapeProcessor.cpp requires SRG_PerDraw on ObjectSrg.

Removed names of SceneSrg and ViewSrg from RPISystemDescriptor.cpp

* Moved ShaderLib/Atom/Features/DummyEntryFunctions.azsli
To  Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/DummyEntryFunctions.azsli

Removed redundant checking for finalization in
ShaderResourceGroupLayout.cpp

* Fixed race condition bug for Shader::FindOrCreate.
InstanceDatabase<>::CreateInstance() needs to be atomic
for instance creation and initialization.

Added optional InstanceHandler::CreateFunctionWithParams to accomodate
to the needs of Instances that need more than an asset reference
to be able to be created an initialzed.

Removed ShaderResourceGroup::FindOrCreate() only ::Create is available
now.

* Renamed scene_and_view_srgs.* as SceneAndViewSrgs.*

Changed GetAzslFileOfOrigin for GetUniqueId

* Fixed unit tests.

* Reverted the serialization name of m_uniqueId back to
"m_azslFileOfOrigin" so precompiled shaders don't fail
in layout comparison.

* Fixed AtomCore.Tests
Removed non-applicable test. InstanceDatabase.AddHandler() is not
available anymore.

* The Null rhi is re-enabled for shader compilation.

Signed-off-by: garrieta <garrieta@amazon.com>
This commit is contained in:
galibzon
2021-06-11 07:48:23 -05:00
committed by GitHub
parent 1435982330
commit cc615a8f32
253 changed files with 3389 additions and 65834 deletions
@@ -29,8 +29,7 @@
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h> // DEPRECATED - [ATOM-15472]
#include <Atom/RPI.Reflect/Shader/ShaderAsset2.h>
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
#include <Atom/RHI.Edit/Utils.h>
@@ -87,68 +86,6 @@ namespace AZ
AzFramework::StringFunc::Path::ReplaceExtension(absoluteAzslPath, "azsl");
}
static bool LoadShaderResourceGroupAssets(
[[maybe_unused]] const char* builderName,
const SrgDataContainer& resourceGroups,
ShaderResourceGroupAssets& srgAssets)
{
bool readSRGsSuccessfuly = true;
// Load all SRGs included in source file
for (const SrgData& srgData : resourceGroups)
{
Data::AssetId assetId = {};
AZStd::string srgFilePath = "";
srgFilePath = srgData.m_containingFileName;
AzFramework::StringFunc::Path::Normalize(srgFilePath);
bool assetFound = false;
Data::AssetInfo sourceInfo;
AZStd::string watchFolder;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(assetFound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, srgFilePath.c_str(), sourceInfo, watchFolder);
if (!assetFound)
{
AZ_Error(builderName, false, "Could not find asset identified by path '%s'", srgFilePath.c_str());
readSRGsSuccessfuly = false;
continue;
}
assetId.m_guid = sourceInfo.m_assetId.m_guid;
assetId.m_subId = static_cast<uint32_t>(AZStd::hash<AZStd::string>()(srgData.m_name) & 0xFFFFFFFF);
Data::Asset<RPI::ShaderResourceGroupAsset> asset = Data::AssetManager::Instance().GetAsset<RPI::ShaderResourceGroupAsset>(
assetId, AZ::Data::AssetLoadBehavior::PreLoad);
asset.BlockUntilLoadComplete();
if (!asset.IsReady())
{
using Status = Data::AssetData::AssetStatus;
AZStd::string statusString = asset.GetStatus() == Status::Loading ? "loading"
: asset.GetStatus() == Status::ReadyPreNotify ? "ready-pre-notify"
: asset.GetStatus() == Status::Error ? "error" : "not-loaded/ready/unknown";
AZ_Error(builderName, false, "Searching SRG [%s]: Could not load SRG asset. (asset status [%s]) AssetId='%s' Path='%s'",
srgData.m_name.c_str(),
statusString.c_str(),
assetId.ToString<AZStd::string>().c_str(), srgFilePath.c_str());
readSRGsSuccessfuly = false;
continue;
}
else if (!asset->IsValid())
{
AZ_Error(builderName, false, "SRG asset has no layout information. AssetId='%s' Path='%s'",
assetId.ToString<AZStd::string>().c_str(), srgFilePath.c_str());
readSRGsSuccessfuly = false;
continue;
}
srgAssets.push_back(asset);
}
return readSRGsSuccessfuly;
}
AZStd::shared_ptr<ShaderFiles> PrepareSourceInput(
[[maybe_unused]] const char* builderName,
const AZStd::string& shaderAssetSourcePath,
@@ -171,87 +108,6 @@ namespace AZ
return files;
}
//! [GFX TODO] [ATOM-15472] Deprecated, remove when this ticket is addressed.
AssetBuilderSDK::ProcessJobResultCode PopulateAzslDataFromJsonFiles(
const char* builderName,
const AzslSubProducts::Paths& pathOfJsonFiles,
AzslData& azslData,
ShaderResourceGroupAssets& srgAssets,
RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionGroupLayout,
BindingDependencies& bindingDependencies,
RootConstantData& rootConstantData)
{
AzslCompiler azslc(azslData.m_preprocessedFullPath); // set the input file for eventual error messages, but the compiler won't be called on it.
bool allReadSuccess = true;
// read: input assembly reflection
// shader resource group reflection
// options reflection
// binding dependencies reflection
int indicesOfInterest[] = { AzslSubProducts::ia, AzslSubProducts::srg, AzslSubProducts::options, AzslSubProducts::bindingdep };
AZStd::unordered_map<int, Outcome<rapidjson::Document, AZStd::string>> outcomes;
for (int i : indicesOfInterest)
{
outcomes[i] = JsonSerializationUtils::ReadJsonFile(pathOfJsonFiles[i]);
if (!outcomes[i].IsSuccess())
{
AZ_Error(builderName, false, "%s", outcomes[i].GetError().c_str());
allReadSuccess = false;
}
}
if (!allReadSuccess)
{
return AssetBuilderSDK::ProcessJobResult_Failed;
}
// Get full list of functions eligible for vertex shader entry points
// along with metadata for constructing the InputAssembly for each of them
if (!azslc.ParseIaPopulateFunctionData(outcomes[AzslSubProducts::ia].GetValue(), azslData.m_functions))
{
return AssetBuilderSDK::ProcessJobResult_Failed;
}
// Each SRG is built as a separate asset in the SrgLayoutBuilder, here we just
// build the list and load the data from multiple dependency assets.
if (!azslc.ParseSrgPopulateSrgData(outcomes[AzslSubProducts::srg].GetValue(), azslData.m_srgData))
{
return AssetBuilderSDK::ProcessJobResult_Failed;
}
// Add all Shader Resource Group Assets that were defined in the shader code to the shader asset
if (!LoadShaderResourceGroupAssets(builderName, azslData.m_srgData, srgAssets))
{
AZ_Error(builderName, false, "Failed to obtain shader resource group assets");
return AssetBuilderSDK::ProcessJobResult_Failed;
}
// The shader options define what options are available, what are the allowed values/range
// for each option and what is its default value.
if (!azslc.ParseOptionsPopulateOptionGroupLayout(outcomes[AzslSubProducts::options].GetValue(), shaderOptionGroupLayout))
{
AZ_Error(builderName, false, "Failed to find a valid list of shader options!");
return AssetBuilderSDK::ProcessJobResult_Failed;
}
// It analyzes the shader external bindings (all SRG contents)
// and informs us on register indexes and shader stages using these resources
if (!azslc.ParseBindingdepPopulateBindingDependencies(outcomes[AzslSubProducts::bindingdep].GetValue(), bindingDependencies)) // consuming data from binding-dep
{
AZ_Error(builderName, false, "Failed to obtain shader resource binding reflection");
return AssetBuilderSDK::ProcessJobResult_Failed;
}
// access the root constants reflection
if (!azslc.ParseSrgPopulateRootConstantData(outcomes[AzslSubProducts::srg].GetValue(), rootConstantData)) // consuming data from --srg ("InlineConstantBuffer" subjson section)
{
AZ_Error(builderName, false, "Failed to obtain root constant data reflection");
return AssetBuilderSDK::ProcessJobResult_Failed;
}
return AssetBuilderSDK::ProcessJobResult_Success;
}
AssetBuilderSDK::ProcessJobResultCode PopulateAzslDataFromJsonFiles(
const char* builderName,
const AzslSubProducts::Paths& pathOfJsonFiles,
@@ -361,7 +217,8 @@ namespace AZ
}
//! the binding dependency structure may store lots of high level function names which are not entry points
static void PruneNonEntryFunctions(BindingDependencies& bindingDependencies /*inout*/, const MapOfStringToStageType& shaderEntryPoints)
static void PruneNonEntryFunctions(
BindingDependencies& bindingDependencies /*inout*/, const MapOfStringToStageType& shaderEntryPoints)
{
auto cleaner = [&shaderEntryPoints](BindingDependencies::FunctionsNameVector& functionVector)
{
@@ -387,120 +244,6 @@ namespace AZ
});
}
}
RHI::Ptr<RHI::PipelineLayoutDescriptor> BuildPipelineLayoutDescriptorForApi(
[[maybe_unused]] const char* builderName,
RHI::ShaderPlatformInterface* shaderPlatformInterface,
BindingDependencies& bindingDependencies /*inout*/,
const ShaderResourceGroupAssets& srgAssets,
const MapOfStringToStageType& shaderEntryPoints,
const RHI::ShaderCompilerArguments& shaderCompilerArguments,
const RootConstantData* rootConstantData /*= nullptr*/)
{
PruneNonEntryFunctions(bindingDependencies, shaderEntryPoints);
// Translates from a list of function names that use a resource to a shader stage mask.
auto getRHIShaderStageMask = [&shaderEntryPoints](const BindingDependencies::FunctionsNameVector& functions)
{
RHI::ShaderStageMask mask = RHI::ShaderStageMask::None;
// Iterate through all the functions that are using the resource.
for (const auto& functionName : functions)
{
// Search the function name into the list of valid entry points into the shader.
auto findId = AZStd::find_if(shaderEntryPoints.begin(), shaderEntryPoints.end(), [&functionName, &mask](const auto& item)
{
return item.first == functionName;
});
if (findId != shaderEntryPoints.end())
{
// Use the entry point shader stage type to calculate the mask.
RHI::ShaderHardwareStage hardwareStage = ToAssetBuilderShaderType(findId->second);
mask |= static_cast<RHI::ShaderStageMask>(AZ_BIT(static_cast<uint32_t>(RHI::ToRHIShaderStage(hardwareStage))));
}
}
return mask;
};
// Build general PipelineLayoutDescriptor data that is provided for all platforms
RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor = shaderPlatformInterface->CreatePipelineLayoutDescriptor();
RHI::ShaderPlatformInterface::ShaderResourceGroupInfoList srgInfos;
for (const auto& srgAsset : srgAssets)
{
// Search the binding info for a Shader Resource Group.
AZStd::string_view srgName = srgAsset->GetName().GetStringView();
const BindingDependencies::SrgResources* srgResources = bindingDependencies.GetSrg(srgName);
if (!srgResources)
{
AZ_Error(builderName, false, "SRG %s not found in the dependency dataset", srgName.data());
return nullptr;
}
RHI::ShaderResourceGroupBindingInfo srgBindingInfo;
srgBindingInfo.m_spaceId = srgResources->m_registerSpace;
const RHI::ShaderResourceGroupLayout* layout = srgAsset->GetLayout(shaderPlatformInterface->GetAPIType());
// Calculate the binding in for the constant data. All constant data share the same binding info.
srgBindingInfo.m_constantDataBindingInfo = {
getRHIShaderStageMask(srgResources->m_srgConstantsDependencies.m_binding.m_dependentFunctions),
srgResources->m_srgConstantsDependencies.m_binding.m_registerId };
// Calculate the binding info for each resource of the Shader Resource Group.
for (auto const& resource : srgResources->m_resources)
{
auto const& resourceInfo = resource.second;
srgBindingInfo.m_resourcesRegisterMap.insert(
{ AZ::Name(resourceInfo.m_selfName),
RHI::ResourceBindingInfo(getRHIShaderStageMask(resourceInfo.m_dependentFunctions), resourceInfo.m_registerId) });
}
pipelineLayoutDescriptor->AddShaderResourceGroupLayoutInfo(*layout, srgBindingInfo);
srgInfos.push_back(RHI::ShaderPlatformInterface::ShaderResourceGroupInfo{ layout, srgBindingInfo });
}
RHI::Ptr<RHI::ConstantsLayout> rootConstantsLayout = RHI::ConstantsLayout::Create();
if (rootConstantData)
{
for (const auto& constantData : rootConstantData->m_constants)
{
RHI::ShaderInputConstantDescriptor rootConstantDesc(
constantData.m_nameId, constantData.m_constantByteOffset, constantData.m_constantByteSize,
rootConstantData->m_bindingInfo.m_registerId);
rootConstantsLayout->AddShaderInput(rootConstantDesc);
}
}
if (!rootConstantsLayout->Finalize())
{
AZ_Error(builderName, false, "Failed to finalize root constants layout");
return nullptr;
}
pipelineLayoutDescriptor->SetRootConstantsLayout(*rootConstantsLayout);
RHI::ShaderPlatformInterface::RootConstantsInfo rootConstantInfo;
if (rootConstantData)
{
rootConstantInfo.m_spaceId = rootConstantData->m_bindingInfo.m_space;
rootConstantInfo.m_registerId = rootConstantData->m_bindingInfo.m_registerId;
}
else
{
RootConstantData dummyRootConstantData;
rootConstantInfo.m_spaceId = dummyRootConstantData.m_bindingInfo.m_space;
rootConstantInfo.m_registerId = dummyRootConstantData.m_bindingInfo.m_registerId;
}
rootConstantInfo.m_totalSizeInBytes = rootConstantsLayout->GetDataSize();
// Build platform-specific PipelineLayoutDescriptor data, and finalize
if (!shaderPlatformInterface->BuildPipelineLayoutDescriptor(
pipelineLayoutDescriptor, srgInfos, rootConstantInfo, shaderCompilerArguments))
{
AZ_Error(builderName, false, "Failed to build pipeline layout descriptor");
return nullptr;
}
return pipelineLayoutDescriptor;
}
static AZStd::string DumpCode(
[[maybe_unused]] const char* builderName,
@@ -539,14 +282,8 @@ namespace AZ
return finalFilePath;
}
// [GFX TODO] Remove 'add2' when [ATOM-15472]
AZStd::string DumpPreprocessedCode(const char* builderName, const AZStd::string& preprocessedCode, const AZStd::string& tempDirPath, const AZStd::string& stemName, const AZStd::string& apiTypeString, bool add2)
AZStd::string DumpPreprocessedCode(const char* builderName, const AZStd::string& preprocessedCode, const AZStd::string& tempDirPath, const AZStd::string& stemName, const AZStd::string& apiTypeString)
{
if (add2)
{
return DumpCode(builderName, preprocessedCode, tempDirPath, stemName, apiTypeString, "azslin2");
}
return DumpCode(builderName, preprocessedCode, tempDirPath, stemName, apiTypeString, "azslin");
}
@@ -584,8 +321,7 @@ namespace AZ
AZStd::remove_if(AZ_BEGIN_END(platformInterfaces),
[&](const RHI::ShaderPlatformInterface* shaderPlatformInterface) {
return !shaderPlatformInterface ||
shaderSourceData.IsRhiBackendDisabled(shaderPlatformInterface->GetAPIName()) ||
(shaderPlatformInterface->GetAPIUniqueIndex() == static_cast<uint32_t>(AZ::RHI::APIIndex::Null));
shaderSourceData.IsRhiBackendDisabled(shaderPlatformInterface->GetAPIName());
}),
platformInterfaces.end());
return platformInterfaces;
@@ -718,15 +454,7 @@ namespace AZ
#endif
}
uint32_t MakeAzslBuildProductSubId(RPI::ShaderAssetSubId subId, RHI::APIType apiType)
{
auto subIdMaxEnumerator = RPI::ShaderAssetSubId::GeneratedHlslSource;
// separate bit space between subid enum, and api-type:
int shiftLeft = static_cast<uint32_t>(log2(static_cast<uint32_t>(subIdMaxEnumerator))) + 1;
return static_cast<uint32_t>(subId) + (apiType << shiftLeft);
}
Outcome<AZStd::string, AZStd::string> ObtainBuildArtifactPathFromShaderAssetBuilder2(
Outcome<AZStd::string, AZStd::string> ObtainBuildArtifactPathFromShaderAssetBuilder(
const uint32_t rhiUniqueIndex, const AZStd::string& platformIdentifier, const AZStd::string& shaderJsonPath,
const uint32_t supervariantIndex, RPI::ShaderAssetSubId shaderAssetSubId)
{
@@ -749,12 +477,12 @@ namespace AZ
platformId = AzFramework::PlatformId::IOS;
}
uint32_t assetSubId = RPI::ShaderAsset2::MakeProductAssetSubId(rhiUniqueIndex, supervariantIndex, aznumeric_cast<uint32_t>(shaderAssetSubId));
uint32_t assetSubId = RPI::ShaderAsset::MakeProductAssetSubId(rhiUniqueIndex, supervariantIndex, aznumeric_cast<uint32_t>(shaderAssetSubId));
auto assetIdOutcome = RPI::AssetUtils::MakeAssetId(shaderJsonPath, assetSubId);
if (!assetIdOutcome.IsSuccess())
{
return Failure(AZStd::string::format(
"Missing ShaderAssetBuilder2 product %s, for sub %d", shaderJsonPath.c_str(), (uint32_t)shaderAssetSubId));
"Missing ShaderAssetBuilder product %s, for sub %d", shaderJsonPath.c_str(), (uint32_t)shaderAssetSubId));
}
Data::AssetId assetId = assetIdOutcome.TakeValue();
@@ -778,113 +506,6 @@ namespace AZ
return AZ::Success(assetFullPath);
}
Outcome<AzslSubProducts::Paths> ObtainBuildArtifactsFromAzslBuilder([[maybe_unused]] const char* builderName, const AZStd::string& sourceFullPath, RHI::APIType apiType, const AZStd::string& platform)
{
AzslSubProducts::Paths products;
// platform id from identifier
AzFramework::PlatformId platformId = AzFramework::PlatformId::PC;
if (platform == "pc")
{
platformId = AzFramework::PlatformId::PC;
}
else if (platform == "mac")
{
platformId = AzFramework::PlatformId::MAC_ID;
}
else if (platform == "android")
{
platformId = AzFramework::PlatformId::ANDROID_ID;
}
else if (platform == "ios")
{
platformId = AzFramework::PlatformId::IOS;
}
for (RPI::ShaderAssetSubId sub : AzslSubProducts::SubList)
{
uint32_t assetSubId = MakeAzslBuildProductSubId(sub, apiType);
auto assetIdOutcome = RPI::AssetUtils::MakeAssetId(sourceFullPath, assetSubId);
AZ_Error(builderName, assetIdOutcome.IsSuccess(), "Missing AZSL product %s, for sub %d", sourceFullPath.c_str(), (uint32_t)sub);
if (!assetIdOutcome.IsSuccess())
{
return Failure();
}
Data::AssetId assetId = assetIdOutcome.TakeValue();
// get the relative path:
AZStd::string assetPath;
Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &Data::AssetCatalogRequests::GetAssetPathById, assetId);
// get the root:
AZStd::string assetRoot = AzToolsFramework::PlatformAddressedAssetCatalog::GetAssetRootForPlatform(platformId);
// join
AZStd::string assetFullPath;
AzFramework::StringFunc::Path::Join(assetRoot.c_str(), assetPath.c_str(), assetFullPath);
bool fileExists = IO::FileIOBase::GetInstance()->Exists(assetFullPath.c_str()) && !IO::FileIOBase::GetInstance()->IsDirectory(assetFullPath.c_str());
if (!fileExists)
{
return Failure();
}
products.push_back(assetFullPath);
}
return AZ::Success(products);
}
// DEPRECATED [ATOM-15472]
// See header for info.
// REMARK: The approach to string searching and matching done in this function is kind of naive
// because the strings can match text within a comment block, etc. So it is not 100% fool proof.
// We would need proper grammar parsing to reach 100% confidence.
// [GFX TODO][ATOM-5302][ATOM-5308] The following function will be removed once, both, [ATOM-5302] & [ATOM-5308] are addressed, and
// azslc allows redundant SrgSemantics for "partial" qualified SRGs.
SrgSkipFileResult ShouldSkipFileForSrgProcessing([[maybe_unused]] const char* builderName, const AZStd::string_view fullPath)
{
AZ::IO::FileIOStream stream(fullPath.data(), AZ::IO::OpenMode::ModeRead);
if (!stream.IsOpen())
{
AZ_Warning(builderName, false, "\"%s\" source file could not be opened.", fullPath.data());
return SrgSkipFileResult::Error;
}
if (!stream.CanRead())
{
AZ_Warning(builderName, false, "\"%s\" source file could not be read.", fullPath.data());
return SrgSkipFileResult::Error;
}
// Do a quick check for "ShaderResourceGroup" to determine if this file might even have a ShaderResourceGroup to parse.
AZStd::string fileContents;
fileContents.resize(stream.GetLength());
stream.Read(stream.GetLength(), fileContents.data());
static const AZStd::regex partialSrgRegex("\n\\s*partial\\s+ShaderResourceGroup\\s+", AZStd::regex::ECMAScript);
if (AZStd::regex_search(fileContents.data(), partialSrgRegex))
{
// It is considered a programmer's error if a file declares both, non-partial and partial SRGs.
static const AZStd::regex srgRegex("\n\\s*ShaderResourceGroup\\s+", AZStd::regex::ECMAScript);
if (AZStd::regex_search(fileContents.data(), srgRegex))
{
AZ_Error(builderName, false, "\"%s\" defines both partial and non-partial SRGs.", fullPath.data());
return SrgSkipFileResult::Error;
}
// We should skip files that define partial Srgs because an srgi file will eventually
// include it.
return SrgSkipFileResult::SkipFile;
}
// This is an optimization to avoid unnecessary preprocessing a whole tree of azsli files; we can detect when a
// ShaderResourceGroupAsset wouldn't be produced and return early. Note, we could remove this early-return check
// if the preprocessing code below is updated to not follow include paths [ATOM-5302].
// (Note this optimization is not valid for srgi files because those do require scanning all include paths)"
if (fileContents.find("ShaderResourceGroup") == AZStd::string::npos)
{
// No ShaderResourceGroup in this file, so there's nothing to do. Create no jobs and report success.
return SrgSkipFileResult::SkipFile;
}
return SrgSkipFileResult::ContinueProcess;
}
RHI::Ptr<RHI::PipelineLayoutDescriptor> BuildPipelineLayoutDescriptorForApi(
[[maybe_unused]] const char* builderName, const RPI::ShaderResourceGroupLayoutList& srgLayoutList, const MapOfStringToStageType& shaderEntryPoints,
const RHI::ShaderCompilerArguments& shaderCompilerArguments, const RootConstantData& rootConstantData,