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.
542 lines
27 KiB
C++
542 lines
27 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
|
|
#include <regex>
|
|
|
|
#include <Atom/RHI.Edit/ShaderPlatformInterface.h>
|
|
#include <Atom/RHI.Edit/Utils.h>
|
|
#include <Atom/RHI.Reflect/ShaderResourceGroupLayoutDescriptor.h>
|
|
|
|
#include <Atom/RPI.Reflect/Shader/ShaderResourceGroupAsset.h>
|
|
#include <Atom/RPI.Reflect/Shader/ShaderResourceGroupAssetCreator.h>
|
|
|
|
#include <AtomCore/Serialization/Json/JsonUtils.h>
|
|
|
|
#include <AzCore/Asset/AssetManager.h>
|
|
#include <AzCore/IO/FileIO.h>
|
|
|
|
#include <AzFramework/API/ApplicationAPI.h>
|
|
#include <AzFramework/Asset/AssetSystemBus.h>
|
|
#include <AzFramework/StringFunc/StringFunc.h>
|
|
|
|
#include <Atom/RPI.Reflect/Shader/ShaderResourceGroupAsset.h>
|
|
|
|
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
|
|
|
#include <AzslData.h>
|
|
#include <AzslCompiler.h>
|
|
#include <CommonFiles/Preprocessor.h>
|
|
#include <CommonFiles/GlobalBuildOptions.h>
|
|
#include <SrgLayoutBuilder.h>
|
|
#include <ShaderPlatformInterfaceRequest.h>
|
|
#include <ShaderBuilderUtility.h>
|
|
|
|
namespace AZ
|
|
{
|
|
namespace ShaderBuilder
|
|
{
|
|
AZ::Uuid SrgLayoutBuilder::GetUUID()
|
|
{
|
|
return AZ::Uuid::CreateString("{ABC78905-B3FC-497A-916A-217D1460E52F}");
|
|
}
|
|
|
|
void SrgLayoutBuilder::Reflect([[maybe_unused]] AZ::ReflectContext* context)
|
|
{
|
|
}
|
|
|
|
SrgLayoutBuilder::SrgLayoutBuilder()
|
|
{
|
|
}
|
|
|
|
SrgLayoutBuilder::~SrgLayoutBuilder()
|
|
{
|
|
}
|
|
|
|
void SrgLayoutBuilder::Activate()
|
|
{
|
|
}
|
|
|
|
void SrgLayoutBuilder::Deactivate()
|
|
{
|
|
}
|
|
|
|
void SrgLayoutBuilder::ShutDown()
|
|
{
|
|
}
|
|
|
|
RHI::ShaderInputBufferType ToShaderInputBufferType(BufferType bufferType)
|
|
{
|
|
switch (bufferType)
|
|
{
|
|
case BufferType::Buffer:
|
|
case BufferType::RwBuffer:
|
|
case BufferType::RasterizerOrderedBuffer:
|
|
return RHI::ShaderInputBufferType::Typed;
|
|
case BufferType::AppendStructuredBuffer:
|
|
case BufferType::ConsumeStructuredBuffer:
|
|
case BufferType::RasterizerOrderedStructuredBuffer:
|
|
case BufferType::RwStructuredBuffer:
|
|
case BufferType::StructuredBuffer:
|
|
return RHI::ShaderInputBufferType::Structured;
|
|
case BufferType::RasterizerOrderedByteAddressBuffer:
|
|
case BufferType::ByteAddressBuffer:
|
|
case BufferType::RwByteAddressBuffer:
|
|
return RHI::ShaderInputBufferType::Raw;
|
|
case BufferType::RaytracingAccelerationStructure:
|
|
return RHI::ShaderInputBufferType::AccelerationStructure;
|
|
default:
|
|
AZ_Assert(false, "Unhandled BufferType");
|
|
return RHI::ShaderInputBufferType::Unknown;
|
|
}
|
|
}
|
|
|
|
RHI::ShaderInputBufferAccess ToShaderInputBufferAccess(BufferType bufferType)
|
|
{
|
|
switch (bufferType)
|
|
{
|
|
case BufferType::Buffer:
|
|
case BufferType::ByteAddressBuffer:
|
|
case BufferType::ConsumeStructuredBuffer:
|
|
case BufferType::StructuredBuffer:
|
|
return RHI::ShaderInputBufferAccess::Read;
|
|
case BufferType::AppendStructuredBuffer:
|
|
case BufferType::RasterizerOrderedStructuredBuffer:
|
|
case BufferType::RasterizerOrderedByteAddressBuffer:
|
|
case BufferType::RasterizerOrderedBuffer:
|
|
case BufferType::RwByteAddressBuffer:
|
|
case BufferType::RwStructuredBuffer:
|
|
case BufferType::RwBuffer:
|
|
return RHI::ShaderInputBufferAccess::ReadWrite;
|
|
default:
|
|
AZ_Assert(false, "Unhandled BufferType");
|
|
return RHI::ShaderInputBufferAccess::Read;
|
|
}
|
|
}
|
|
|
|
RHI::ShaderInputImageType ToShaderInputImageType(TextureType textureType)
|
|
{
|
|
switch (textureType)
|
|
{
|
|
case TextureType::Texture1D: return RHI::ShaderInputImageType::Image1D;
|
|
case TextureType::Texture1DArray: return RHI::ShaderInputImageType::Image1DArray;
|
|
case TextureType::Texture2D: return RHI::ShaderInputImageType::Image2D;
|
|
case TextureType::Texture2DArray: return RHI::ShaderInputImageType::Image2DArray;
|
|
case TextureType::Texture2DMS: return RHI::ShaderInputImageType::Image2DMultisample;
|
|
case TextureType::Texture2DMSArray: return RHI::ShaderInputImageType::Image2DMultisampleArray;
|
|
case TextureType::Texture3D: return RHI::ShaderInputImageType::Image3D;
|
|
case TextureType::TextureCube: return RHI::ShaderInputImageType::ImageCube;
|
|
case TextureType::RwTexture1D: return RHI::ShaderInputImageType::Image1D;
|
|
case TextureType::RwTexture1DArray: return RHI::ShaderInputImageType::Image1DArray;
|
|
case TextureType::RwTexture2D: return RHI::ShaderInputImageType::Image2D;
|
|
case TextureType::RwTexture2DArray: return RHI::ShaderInputImageType::Image2DArray;
|
|
case TextureType::RwTexture3D: return RHI::ShaderInputImageType::Image3D;
|
|
case TextureType::RasterizerOrderedTexture1D: return RHI::ShaderInputImageType::Image1D;
|
|
case TextureType::RasterizerOrderedTexture1DArray: return RHI::ShaderInputImageType::Image1DArray;
|
|
case TextureType::RasterizerOrderedTexture2D: return RHI::ShaderInputImageType::Image2D;
|
|
case TextureType::RasterizerOrderedTexture2DArray: return RHI::ShaderInputImageType::Image2DArray;
|
|
case TextureType::RasterizerOrderedTexture3D: return RHI::ShaderInputImageType::Image3D;
|
|
case TextureType::SubpassInput: return RHI::ShaderInputImageType::SubpassInput;
|
|
default:
|
|
AZ_Assert(false, "Unhandled TextureType");
|
|
return RHI::ShaderInputImageType::Unknown;
|
|
}
|
|
}
|
|
|
|
RHI::ShaderInputImageAccess ToShaderInputImageAccess(TextureType textureType)
|
|
{
|
|
switch (textureType)
|
|
{
|
|
case TextureType::Texture1D:
|
|
case TextureType::Texture1DArray:
|
|
case TextureType::Texture2D:
|
|
case TextureType::Texture2DArray:
|
|
case TextureType::Texture2DMS:
|
|
case TextureType::Texture2DMSArray:
|
|
case TextureType::Texture3D:
|
|
case TextureType::TextureCube:
|
|
return RHI::ShaderInputImageAccess::Read;
|
|
case TextureType::RwTexture1D:
|
|
case TextureType::RwTexture1DArray:
|
|
case TextureType::RwTexture2D:
|
|
case TextureType::RwTexture2DArray:
|
|
case TextureType::RwTexture3D:
|
|
case TextureType::RasterizerOrderedTexture1D:
|
|
case TextureType::RasterizerOrderedTexture1DArray:
|
|
case TextureType::RasterizerOrderedTexture2D:
|
|
case TextureType::RasterizerOrderedTexture2DArray:
|
|
case TextureType::RasterizerOrderedTexture3D:
|
|
return RHI::ShaderInputImageAccess::ReadWrite;
|
|
default:
|
|
AZ_Assert(false, "Unhandled TextureType");
|
|
return RHI::ShaderInputImageAccess::Read;
|
|
}
|
|
}
|
|
|
|
void SrgLayoutBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const
|
|
{
|
|
AZStd::string fullPath;
|
|
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullPath, false);
|
|
AzFramework::StringFunc::Path::Normalize(fullPath);
|
|
|
|
AZ_TracePrintf(SrgLayoutBuilderName, "CreateJobs for Srg Layouts \"%s\"\n", fullPath.data());
|
|
|
|
for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms)
|
|
{
|
|
AssetBuilderSDK::JobDescriptor jobDescriptor;
|
|
jobDescriptor.m_priority = 2;
|
|
// [GFX TODO][ATOM-2830] Set 'm_critical' back to 'false' once proper fix for Atom startup issues are in
|
|
jobDescriptor.m_critical = true;
|
|
jobDescriptor.m_jobKey = SrgLayoutBuilderJobKey;
|
|
jobDescriptor.SetPlatformIdentifier(info.m_identifier.data());
|
|
|
|
// Get the platform interfaces to be able to access the prepend file
|
|
AZStd::vector<RHI::ShaderPlatformInterface*> platformInterfaces = ShaderBuilderUtility::DiscoverValidShaderPlatformInterfaces(info);
|
|
// queue up AzslBuilder dependencies:
|
|
for (RHI::ShaderPlatformInterface* shaderPlatformInterface : platformInterfaces)
|
|
{
|
|
AddAzslBuilderJobDependency(jobDescriptor, info.m_identifier, shaderPlatformInterface->GetAPIName().GetCStr(), fullPath);
|
|
}
|
|
response.m_createJobOutputs.push_back(jobDescriptor);
|
|
}
|
|
|
|
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
|
}
|
|
|
|
void SrgLayoutBuilder::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) const
|
|
{
|
|
AZStd::string sourcePath;
|
|
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.c_str(), request.m_sourceFile.c_str(), sourcePath, false);
|
|
AzFramework::StringFunc::Path::Normalize(sourcePath);
|
|
|
|
if (!AzFramework::StringFunc::Path::IsExtension(sourcePath.c_str(), MergedPartialSrgsExtension)) // not .srgi
|
|
{
|
|
auto skipCheck = ShaderBuilderUtility::ShouldSkipFileForSrgProcessing(SrgLayoutBuilderName, sourcePath);
|
|
if (skipCheck != ShaderBuilderUtility::SrgSkipFileResult::ContinueProcess)
|
|
{
|
|
response.m_resultCode = skipCheck == ShaderBuilderUtility::SrgSkipFileResult::Error ?
|
|
AssetBuilderSDK::ProcessJobResult_Failed : AssetBuilderSDK::ProcessJobResult_Success;
|
|
return;
|
|
}
|
|
}
|
|
|
|
AZ_TracePrintf(SrgLayoutBuilderName, "Processing Shader Resource Group \"%s\".\n", sourcePath.c_str());
|
|
|
|
AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
|
|
if (jobCancelListener.IsCancelled())
|
|
{
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
|
|
return;
|
|
}
|
|
|
|
// Note this will update response.m_resultCode
|
|
CreateSRGAsset(sourcePath, request, response, jobCancelListener);
|
|
|
|
AZ_TracePrintf(SrgLayoutBuilderName, "Finished processing %s\n", sourcePath.c_str());
|
|
}
|
|
|
|
void SrgLayoutBuilder::CreateSRGAsset(
|
|
AZStd::string fullSourcePath,
|
|
const AssetBuilderSDK::ProcessJobRequest& request,
|
|
AssetBuilderSDK::ProcessJobResponse& response,
|
|
AssetBuilderSDK::JobCancelListener& jobCancelListener)
|
|
{
|
|
// Request the list of valid shader platform interfaces for the target platform.
|
|
AZStd::vector<RHI::ShaderPlatformInterface*> platformInterfaces;
|
|
ShaderPlatformInterfaceRequestBus::BroadcastResult(platformInterfaces, &ShaderPlatformInterfaceRequest::GetShaderPlatformInterface, request.m_platformInfo);
|
|
if (platformInterfaces.empty())
|
|
{
|
|
AZ_Error(SrgLayoutBuilderName, false, "No ShaderPlatformInterfaces found.");
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
|
|
using SrgDataEntry = AZStd::pair<RHI::ShaderPlatformInterface*, SrgData>;
|
|
// List with all SRGs that need to be processed.
|
|
AZStd::unordered_map<AZStd::string, AZStd::vector<SrgDataEntry>> srgsToProcess;
|
|
// Emit all SRGs per each of the platform interfaces.
|
|
for (RHI::ShaderPlatformInterface* shaderPlatformInterface : platformInterfaces)
|
|
{
|
|
if (!shaderPlatformInterface)
|
|
{
|
|
AZ_Error(SrgLayoutBuilderName, false, "ShaderPlatformInterface for [%s] is not registered, can't compile [%s]", request.m_platformInfo.m_identifier.c_str(), request.m_sourceFile.c_str());
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
SrgDataContainer srgDataContainer;
|
|
|
|
auto azslArtifactsOutcome = ShaderBuilderUtility::ObtainBuildArtifactsFromAzslBuilder(SrgLayoutBuilderName, fullSourcePath, shaderPlatformInterface->GetAPIType(), request.m_platformInfo.m_identifier);
|
|
if (!azslArtifactsOutcome.IsSuccess())
|
|
{
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
// create an AzslCompiler instance to use it's json parsing facilities, but we won't call any emit facility. So the compiler actually never runs.
|
|
AzslCompiler azslc(azslArtifactsOutcome.GetValue()[ShaderBuilderUtility::AzslSubProducts::azslin]); // set the input file for eventual error messages.
|
|
|
|
AZ::Outcome<rapidjson::Document, AZStd::string> outcome;
|
|
outcome = JsonSerializationUtils::ReadJsonFile(azslArtifactsOutcome.GetValue()[ShaderBuilderUtility::AzslSubProducts::srg]);
|
|
if (!outcome.IsSuccess())
|
|
{
|
|
AZ_Error(SrgLayoutBuilderName, false, "%s", outcome.GetError().c_str());
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
|
|
if (!azslc.ParseSrgPopulateSrgData(outcome.GetValue(), srgDataContainer))
|
|
{
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
|
|
for (const SrgData& srgData : srgDataContainer)
|
|
{
|
|
// Ignore the SRGs included from other files.
|
|
AZStd::string normalizedContainer = srgData.m_containingFileName;
|
|
AzFramework::StringFunc::Path::Normalize(normalizedContainer);
|
|
if (normalizedContainer != fullSourcePath)
|
|
{
|
|
AZ_TracePrintf(SrgLayoutBuilderName, "SRG [%s] found in [%s] but is foreign to [%s]. skipped.",
|
|
srgData.m_name.c_str(), normalizedContainer.c_str(), fullSourcePath.c_str());
|
|
continue;
|
|
}
|
|
AZ_TracePrintf(SrgLayoutBuilderName, "SRG [%s] found in [%s] (native to this file). added.",
|
|
srgData.m_name.c_str(), normalizedContainer.c_str());
|
|
srgsToProcess[srgData.m_name].push_back(SrgDataEntry(shaderPlatformInterface, AZStd::move(srgData)));
|
|
}
|
|
}
|
|
|
|
AZStd::string fileNameOnly;
|
|
AzFramework::StringFunc::Path::GetFileName(request.m_sourceFile.c_str(), fileNameOnly);
|
|
|
|
if (srgsToProcess.empty())
|
|
{
|
|
AZ_TracePrintf(SrgLayoutBuilderName, "No ShaderResourceGroups found in '%s'.", fullSourcePath.c_str());
|
|
}
|
|
|
|
// Process all SRGs that were emitted.
|
|
for (const auto& entry : srgsToProcess)
|
|
{
|
|
const auto& srgName = entry.first;
|
|
if (jobCancelListener.IsCancelled())
|
|
{
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
|
|
return;
|
|
}
|
|
|
|
AZStd::string fullFileName = fileNameOnly + "_" + srgName;
|
|
AZStd::string shaderResourceGroupAssetPath;
|
|
AzFramework::StringFunc::Path::ConstructFull(request.m_tempDirPath.c_str(), fullFileName.c_str(), shaderResourceGroupAssetPath, true);
|
|
AzFramework::StringFunc::Path::ReplaceExtension(shaderResourceGroupAssetPath, "azsrg");
|
|
|
|
RPI::ShaderResourceGroupAssetCreator srgAssetCreator;
|
|
srgAssetCreator.Begin(Uuid::CreateRandom(), Name{ srgName });
|
|
|
|
bool success = true;
|
|
// Process the SRG per each shader platform interface.
|
|
for(const SrgDataEntry& srgDataEntry : entry.second)
|
|
{
|
|
RHI::ShaderPlatformInterface* shaderPlatformInterface = srgDataEntry.first;
|
|
|
|
// The register number only makes sense if the platform uses "spaces",
|
|
// since the register Id of the resource will not change even if the pipeline layout changes.
|
|
// We can pass in a default ShaderCompilerArguments because all we care about is whether the shaderPlatformInterface
|
|
// appends the
|
|
// "--use-spaces" flag.
|
|
AZStd::string azslCompilerParameters =
|
|
shaderPlatformInterface->GetAzslCompilerParameters(RHI::ShaderCompilerArguments{});
|
|
bool useRegisterId = (AzFramework::StringFunc::Find(azslCompilerParameters, "--use-spaces") != AZStd::string::npos);
|
|
|
|
const SrgData& srgData = srgDataEntry.second;
|
|
|
|
srgAssetCreator.BeginAPI(shaderPlatformInterface->GetAPIType());
|
|
srgAssetCreator.SetBindingSlot(srgData.m_bindingSlot.m_index);
|
|
|
|
// Samplers
|
|
for (const SamplerSrgData& samplerData : srgData.m_samplers)
|
|
{
|
|
if (samplerData.m_isDynamic)
|
|
{
|
|
srgAssetCreator.AddShaderInput({
|
|
samplerData.m_nameId,
|
|
samplerData.m_count,
|
|
useRegisterId ? samplerData.m_registerId : RHI::UndefinedRegisterSlot });
|
|
}
|
|
else
|
|
{
|
|
srgAssetCreator.AddStaticSampler({
|
|
samplerData.m_nameId,
|
|
samplerData.m_descriptor,
|
|
useRegisterId ? samplerData.m_registerId : RHI::UndefinedRegisterSlot });
|
|
}
|
|
}
|
|
|
|
// Images
|
|
for (const TextureSrgData& textureData : srgData.m_textures)
|
|
{
|
|
const RHI::ShaderInputImageAccess imageAccess =
|
|
textureData.m_isReadOnlyType ?
|
|
RHI::ShaderInputImageAccess::Read :
|
|
RHI::ShaderInputImageAccess::ReadWrite;
|
|
|
|
const RHI::ShaderInputImageType imageType = ToShaderInputImageType(textureData.m_type);
|
|
|
|
if (imageType != RHI::ShaderInputImageType::Unknown)
|
|
{
|
|
if (textureData.m_count != aznumeric_cast<uint32_t>(-1))
|
|
{
|
|
srgAssetCreator.AddShaderInput({
|
|
textureData.m_nameId,
|
|
imageAccess,
|
|
imageType,
|
|
textureData.m_count,
|
|
useRegisterId ? textureData.m_registerId : RHI::UndefinedRegisterSlot });
|
|
}
|
|
else
|
|
{
|
|
// unbounded array
|
|
srgAssetCreator.AddShaderInput({
|
|
textureData.m_nameId,
|
|
imageAccess,
|
|
imageType,
|
|
useRegisterId ? textureData.m_registerId : RHI::UndefinedRegisterSlot });
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AZ_Error(SrgLayoutBuilderName, false, "Failed to build Shader Resource Group Asset: Image %s has an unknown type.", textureData.m_nameId.GetCStr());
|
|
success = false;
|
|
}
|
|
}
|
|
|
|
// Buffers
|
|
{
|
|
for (const ConstantBufferData& cbData : srgData.m_constantBuffers)
|
|
{
|
|
srgAssetCreator.AddShaderInput({
|
|
cbData.m_nameId,
|
|
RHI::ShaderInputBufferAccess::Constant,
|
|
RHI::ShaderInputBufferType::Constant,
|
|
cbData.m_count,
|
|
cbData.m_strideSize,
|
|
useRegisterId ? cbData.m_registerId : RHI::UndefinedRegisterSlot });
|
|
}
|
|
|
|
for (const BufferSrgData& bufferData : srgData.m_buffers)
|
|
{
|
|
const RHI::ShaderInputBufferAccess bufferAccess =
|
|
bufferData.m_isReadOnlyType ?
|
|
RHI::ShaderInputBufferAccess::Read :
|
|
RHI::ShaderInputBufferAccess::ReadWrite;
|
|
|
|
const RHI::ShaderInputBufferType bufferType = ToShaderInputBufferType(bufferData.m_type);
|
|
|
|
if (bufferType != RHI::ShaderInputBufferType::Unknown)
|
|
{
|
|
if (bufferData.m_count != aznumeric_cast<uint32_t>(-1))
|
|
{
|
|
srgAssetCreator.AddShaderInput({
|
|
bufferData.m_nameId,
|
|
bufferAccess,
|
|
bufferType,
|
|
bufferData.m_count,
|
|
bufferData.m_strideSize,
|
|
useRegisterId ? bufferData.m_registerId : RHI::UndefinedRegisterSlot });
|
|
}
|
|
else
|
|
{
|
|
// unbounded array
|
|
srgAssetCreator.AddShaderInput({
|
|
bufferData.m_nameId,
|
|
bufferAccess,
|
|
bufferType,
|
|
bufferData.m_strideSize,
|
|
useRegisterId ? bufferData.m_registerId : RHI::UndefinedRegisterSlot });
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AZ_Error(SrgLayoutBuilderName, false, "Failed to build Shader Resource Group Asset: Buffer %s has un unknown type.", bufferData.m_nameId.GetCStr());
|
|
success = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// SRG Constants
|
|
uint32_t constantDataRegisterId = useRegisterId ? srgData.m_srgConstantDataRegisterId : RHI::UndefinedRegisterSlot;
|
|
for (const SrgConstantData& srgConstants : srgData.m_srgConstantData)
|
|
{
|
|
srgAssetCreator.AddShaderInput({
|
|
srgConstants.m_nameId,
|
|
srgConstants.m_constantByteOffset,
|
|
srgConstants.m_constantByteSize,
|
|
constantDataRegisterId });
|
|
}
|
|
|
|
// Shader Variant Key fallback
|
|
if (srgData.m_fallbackSize > 0)
|
|
{
|
|
// Designates this SRG as a ShaderVariantKey fallback
|
|
srgAssetCreator.SetShaderVariantKeyFallback(srgData.m_fallbackName, srgData.m_fallbackSize);
|
|
}
|
|
|
|
if (!srgAssetCreator.EndAPI())
|
|
{
|
|
AZ_Error(SrgLayoutBuilderName, false, "Failed to End API.");
|
|
success = false;
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
}
|
|
|
|
Data::Asset<RPI::ShaderResourceGroupAsset> shaderResourceGroupAsset;
|
|
if (!srgAssetCreator.End(shaderResourceGroupAsset))
|
|
{
|
|
AZ_Error(SrgLayoutBuilderName, false, "Failed to build Shader Resource Group Asset");
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
|
|
if (AZ::IO::FileIOBase::GetInstance()->Exists(shaderResourceGroupAssetPath.c_str()))
|
|
{
|
|
// This would indicate a problem above, making sure each product SRG asset file path is unique.
|
|
AZ_Error(SrgLayoutBuilderName, false, "Cannot overwrite existing file [%s]. This likely indicates conflicting SRG names.", shaderResourceGroupAssetPath.c_str());
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
|
|
success = AZ::Utils::SaveObjectToFile(shaderResourceGroupAssetPath, AZ::DataStream::ST_JSON, shaderResourceGroupAsset.Get());
|
|
if (!success)
|
|
{
|
|
AZ_Error(SrgLayoutBuilderName, false, "Failed to save Shader Resource Group Asset to \"%s\"", shaderResourceGroupAssetPath.c_str());
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
|
return;
|
|
}
|
|
|
|
AssetBuilderSDK::JobProduct srgAssetProduct;
|
|
srgAssetProduct.m_productSubID = static_cast<uint32_t>(AZStd::hash<AZStd::string>()(srgName) & 0xFFFFFFFF);
|
|
srgAssetProduct.m_productFileName = shaderResourceGroupAssetPath;
|
|
srgAssetProduct.m_productAssetType = azrtti_typeid<RPI::ShaderResourceGroupAsset>();
|
|
srgAssetProduct.m_dependenciesHandled = true; // This builder has no dependencies to output
|
|
response.m_outputProducts.push_back(srgAssetProduct);
|
|
|
|
AZ_TracePrintf(SrgLayoutBuilderName, "Shader Resource Group Asset compiled successfully.\n");
|
|
}
|
|
|
|
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
|
}
|
|
} // namespace ShaderBuilder
|
|
} // namespace AZ
|