diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp index afa11d8e16..f6b99cac12 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp @@ -95,7 +95,7 @@ namespace AZ shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder"; // Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update // ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder". - shaderVariantAssetBuilderDescriptor.m_version = 23; // ATOM-15472 + shaderVariantAssetBuilderDescriptor.m_version = 24; // ATOM-15978 shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid(); shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index 7be98ab056..010778575e 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -48,6 +48,7 @@ #include "ShaderAssetBuilder.h" #include "ShaderBuilderUtility.h" +#include "SrgLayoutUtility.h" #include "AzslData.h" #include "AzslCompiler.h" #include @@ -520,6 +521,96 @@ namespace AZ return; } } + + static bool LoadSrgLayoutListFromShaderAssetBuilder( + const RHI::ShaderPlatformInterface* shaderPlatformInterface, + const AssetBuilderSDK::PlatformInfo& platformInfo, + const AzslCompiler& azslCompiler, const AZStd::string& shaderSourceFileFullPath, + const RPI::SupervariantIndex supervariantIndex, + const bool platformUsesRegisterSpaces, + RPI::ShaderResourceGroupLayoutList& srgLayoutList, + RootConstantData& rootConstantData) + { + auto srgJsonPathOutcome = ShaderBuilderUtility::ObtainBuildArtifactPathFromShaderAssetBuilder( + shaderPlatformInterface->GetAPIUniqueIndex(), platformInfo.m_identifier, shaderSourceFileFullPath, supervariantIndex.GetIndex(), AZ::RPI::ShaderAssetSubId::SrgJson); + if (!srgJsonPathOutcome.IsSuccess()) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "%s", srgJsonPathOutcome.GetError().c_str()); + return false; + } + + auto srgJsonPath = srgJsonPathOutcome.TakeValue(); + auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath); + if (!jsonOutcome.IsSuccess()) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str()); + return false; + } + SrgDataContainer srgData; + if (!azslCompiler.ParseSrgPopulateSrgData(jsonOutcome.GetValue(), srgData)) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to parse srg data"); + return false; + } + // Add all Shader Resource Group Assets that were defined in the shader code to the shader asset + if (!SrgLayoutUtility::LoadShaderResourceGroupLayouts(ShaderVariantAssetBuilderName, srgData, platformUsesRegisterSpaces, srgLayoutList)) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to load ShaderResourceGroupLayouts"); + return false; + } + + for (auto srgLayout : srgLayoutList) + { + if (!srgLayout->Finalize()) + { + AZ_Error(ShaderVariantAssetBuilderName, false, + "Failed to finalize SrgLayout %s", srgLayout->GetName().GetCStr()); + return false; + } + } + + // Access the root constants reflection + if (!azslCompiler.ParseSrgPopulateRootConstantData( + jsonOutcome.GetValue(), + rootConstantData)) // consuming data from --srg ("InlineConstantBuffer" subjson section) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to obtain root constant data reflection"); + return false; + } + + return true; + } + + static bool LoadBindingDependenciesFromShaderAssetBuilder( + const RHI::ShaderPlatformInterface* shaderPlatformInterface, + const AssetBuilderSDK::PlatformInfo& platformInfo, + const AzslCompiler& azslCompiler, const AZStd::string& shaderSourceFileFullPath, + const RPI::SupervariantIndex supervariantIndex, + BindingDependencies& bindingDependencies) + { + auto bindingsJsonPathOutcome = ShaderBuilderUtility::ObtainBuildArtifactPathFromShaderAssetBuilder( + shaderPlatformInterface->GetAPIUniqueIndex(), platformInfo.m_identifier, shaderSourceFileFullPath, supervariantIndex.GetIndex(), AZ::RPI::ShaderAssetSubId::BindingdepJson); + if (!bindingsJsonPathOutcome.IsSuccess()) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "%s", bindingsJsonPathOutcome.GetError().c_str()); + return false; + } + + auto bindingsJsonPath = bindingsJsonPathOutcome.TakeValue(); + auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath); + if (!jsonOutcome.IsSuccess()) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str()); + return false; + } + if (!azslCompiler.ParseBindingdepPopulateBindingDependencies(jsonOutcome.GetValue(), bindingDependencies)) + { + AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to parse binding dependencies data"); + return false; + } + + return true; + } // Returns the content of the hlsl file for the given supervariant as produced by ShaderAsssetBuilder. @@ -773,6 +864,50 @@ namespace AZ response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; return; } + + //! It is important to keep this refcounted pointer outside of the if block to prevent it from being destroyed. + RHI::Ptr pipelineLayoutDescriptor; + if (shaderPlatformInterface->VariantCompilationRequiresSrgLayoutData()) + { + AZStd::string azslcCompilerParameters = + shaderPlatformInterface->GetAzslCompilerParameters(buildOptions.m_compilerArguments); + const bool platformUsesRegisterSpaces = + (AzFramework::StringFunc::Find(azslcCompilerParameters, "--use-spaces") != AZStd::string::npos); + + RPI::ShaderResourceGroupLayoutList srgLayoutList; + RootConstantData rootConstantData; + if (!LoadSrgLayoutListFromShaderAssetBuilder( + shaderPlatformInterface, request.m_platformInfo, azslc, shaderSourceFileFullPath, supervariantIndex, + platformUsesRegisterSpaces, + srgLayoutList, + rootConstantData)) + { + response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; + return; + } + + BindingDependencies bindingDependencies; + if (!LoadBindingDependenciesFromShaderAssetBuilder( + shaderPlatformInterface, request.m_platformInfo, azslc, shaderSourceFileFullPath, supervariantIndex, + bindingDependencies)) + { + response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; + return; + } + + pipelineLayoutDescriptor = + ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi( + ShaderVariantAssetBuilderName, srgLayoutList, shaderEntryPoints, buildOptions.m_compilerArguments, rootConstantData, + shaderPlatformInterface, bindingDependencies); + if (!pipelineLayoutDescriptor) + { + AZ_Error( + ShaderVariantAssetBuilderName, false, "Failed to build pipeline layout descriptor for api=[%s]", + shaderPlatformInterface->GetAPIName().GetCStr()); + response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; + return; + } + } // Setup the shader variant creation context: ShaderVariantCreationContext shaderVariantCreationContext = diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderPlatformInterface.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderPlatformInterface.h index d83fbf2267..f7db5f865b 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderPlatformInterface.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Edit/ShaderPlatformInterface.h @@ -144,6 +144,12 @@ namespace AZ const ShaderResourceGroupInfoList& srgInfoList, const RootConstantsInfo& rootConstantsInfo, const ShaderCompilerArguments& shaderCompilerArguments) = 0; + + //! In general, shader compilation doesn't require SRG Layout data, but RHIs like + //! Metal don't do well if unused resources (descriptors) are not bound. If this function returns TRUE + //! the ShaderVariantAssetBuilder will invoke BuildPipelineLayoutDescriptor() so the RHI gets the chance to + //! build SRG Layout data which will be useful when compiling MetalISL to Metal byte code. + virtual bool VariantCompilationRequiresSrgLayoutData() const { return false; } //! See AZ::RHI::Factory::GetAPIUniqueIndex() for details. //! See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax. diff --git a/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp b/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp index 0801101178..2f648acc05 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp @@ -159,7 +159,13 @@ namespace AZ arguments += " -Zi"; // Generate debug information arguments += " -Zss"; // Compute Shader Hash considering source information } - arguments += " " + m_dxcAdditionalFreeArguments; + // strip spaces at both sides + AZStd::string dxcAdditionalFreeArguments = m_dxcAdditionalFreeArguments; + AzFramework::StringFunc::TrimWhiteSpace(dxcAdditionalFreeArguments, true, true); + if (!dxcAdditionalFreeArguments.empty()) + { + arguments += " " + dxcAdditionalFreeArguments; + } return arguments; } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.h b/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.h index 935d2e6471..0be02053cd 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI.Builders/ShaderPlatformInterface.h @@ -40,6 +40,8 @@ namespace AZ const ShaderResourceGroupInfoList& srgInfoList, const RootConstantsInfo& rootConstantsInfo, const RHI::ShaderCompilerArguments& shaderCompilerArguments) override; + + bool VariantCompilationRequiresSrgLayoutData() const override { return true; } bool CompilePlatformInternal( const AssetBuilderSDK::PlatformInfo& platform,