merge development
Signed-off-by: chcurran <82187351+carlitosan@users.noreply.github.com>
This commit is contained in:
@@ -1235,7 +1235,8 @@ namespace AZ
|
||||
// ProductMesh. That large buffer gets set on the LOD directly
|
||||
// rather than a Mesh in the LOD.
|
||||
ProductMeshContentAllocInfo lodBufferInfo;
|
||||
|
||||
|
||||
bool isFirstMesh = true;
|
||||
for (const ProductMeshContent& mesh : lodMeshList)
|
||||
{
|
||||
if (lodBufferInfo.m_uvSetFloatCounts.size() < mesh.m_uvSets.size())
|
||||
@@ -1347,6 +1348,14 @@ namespace AZ
|
||||
|
||||
if (!mesh.m_skinJointIndices.empty() && !mesh.m_skinWeights.empty())
|
||||
{
|
||||
if (!isFirstMesh && lodBufferInfo.m_skinInfluencesCount == 0)
|
||||
{
|
||||
AZ_Error(
|
||||
s_builderName, false,
|
||||
"Attempting to merge a mix of static and skinned meshes, this will fail on buffer generation later. Mesh with "
|
||||
"name %s is skinned, but previous meshes were not skinned.",
|
||||
mesh.m_name.GetCStr());
|
||||
}
|
||||
AZ_Assert(mesh.m_skinJointIndices.size() == mesh.m_skinWeights.size(),
|
||||
"Number of skin influence joint indices (%d) should match the number of weights (%d).",
|
||||
mesh.m_skinJointIndices.size(), mesh.m_skinWeights.size());
|
||||
@@ -1363,6 +1372,11 @@ namespace AZ
|
||||
|
||||
lodBufferInfo.m_skinInfluencesCount += numNewSkinInfluences;
|
||||
}
|
||||
else if (lodBufferInfo.m_skinInfluencesCount > 0)
|
||||
{
|
||||
AZ_Error(s_builderName, false, "Attempting to merge a mix of static and skinned meshes, this will fail on buffer generation later. Mesh with name %s is not skinned, but previous meshes were skinned.",
|
||||
mesh.m_name.GetCStr());
|
||||
}
|
||||
|
||||
if (!mesh.m_morphTargetVertexData.empty())
|
||||
{
|
||||
@@ -1375,6 +1389,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
meshViews.emplace_back(AZStd::move(meshView));
|
||||
isFirstMesh = false;
|
||||
}
|
||||
|
||||
// Now that we have the views settled, we can just merge the mesh
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace AZ
|
||||
{
|
||||
AssetBuilderSDK::AssetBuilderDesc builder;
|
||||
builder.m_name = PassBuilderJobKey;
|
||||
builder.m_version = 12; // ATOM-15472
|
||||
builder.m_version = 13; // antonmic: making .pass files declare dependency on shaders they reference
|
||||
builder.m_busId = azrtti_typeid<PassBuilder>();
|
||||
builder.m_createJobFunction = AZStd::bind(&PassBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
||||
builder.m_processJobFunction = AZStd::bind(&PassBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
||||
@@ -65,36 +65,52 @@ namespace AZ
|
||||
m_isShuttingDown = true;
|
||||
}
|
||||
|
||||
void PassBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const
|
||||
// --- Code related to dependency shader asset handling ---
|
||||
|
||||
// Helper class to pass parameters to the AddDependency and FindReferencedAssets functions below
|
||||
struct FindPassReferenceAssetParams
|
||||
{
|
||||
if (m_isShuttingDown)
|
||||
void* passAssetObject = nullptr;
|
||||
Uuid passAssetUuid;
|
||||
SerializeContext* serializeContext = nullptr;
|
||||
AZStd::string_view passAssetSourceFile; // File path of the pass asset
|
||||
AZStd::string_view dependencySourceFile; // File pass of the asset the pass asset depends on
|
||||
const char* jobKey = nullptr; // Job key for adding job dependency
|
||||
};
|
||||
|
||||
// Helper function to get a file reference and create a corresponding job dependency
|
||||
bool AddDependency(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job)
|
||||
{
|
||||
AZStd::string_view& file = params.dependencySourceFile;
|
||||
AZ::Data::AssetInfo sourceInfo;
|
||||
AZStd::string watchFolder;
|
||||
bool fileFound = false;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fileFound, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, file.data(), sourceInfo, watchFolder);
|
||||
|
||||
if (fileFound)
|
||||
{
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown;
|
||||
return;
|
||||
AssetBuilderSDK::JobDependency jobDependency;
|
||||
jobDependency.m_jobKey = params.jobKey;
|
||||
jobDependency.m_type = AssetBuilderSDK::JobDependencyType::Order;
|
||||
jobDependency.m_sourceFile.m_sourceFileDependencyPath = file;
|
||||
job->m_jobDependencyList.push_back(jobDependency);
|
||||
AZ_TracePrintf(PassBuilderName, "Creating job dependency on file [%s] \n", file.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms)
|
||||
else
|
||||
{
|
||||
AssetBuilderSDK::JobDescriptor job;
|
||||
job.m_jobKey = PassBuilderJobKey;
|
||||
job.SetPlatformIdentifier(platformInfo.m_identifier.c_str());
|
||||
|
||||
// Passes are a critical part of the rendering system
|
||||
job.m_critical = true;
|
||||
|
||||
response.m_createJobOutputs.push_back(job);
|
||||
AZ_Error(PassBuilderName, false, "Could not find referenced file [%s]", file.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
||||
}
|
||||
|
||||
// Helper function to find all assetId's and object references
|
||||
bool PassBuilder::FindPassReferencedAssets(void* objectPtr, Uuid passAssetUuid, SerializeContext* context, AZStd::unordered_set<Data::AssetId> &referencedAssetList) const
|
||||
bool FindReferencedAssets(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job)
|
||||
{
|
||||
SerializeContext::ErrorHandler errorLogger;
|
||||
errorLogger.Reset();
|
||||
|
||||
bool foundProblems = false;
|
||||
|
||||
bool success = true;
|
||||
|
||||
// This callback will check whether the given element is an asset reference. If so, it will add it to the list of asset references
|
||||
auto beginCallback = [&](void* ptr, const SerializeContext::ClassData* classData, [[maybe_unused]] const SerializeContext::ClassElement* classElement)
|
||||
@@ -103,30 +119,33 @@ namespace AZ
|
||||
if (classData->m_typeId == azrtti_typeid<AssetReference>())
|
||||
{
|
||||
AssetReference* assetReference = reinterpret_cast<AssetReference*>(ptr);
|
||||
|
||||
|
||||
// If the asset id isn't already provided, get it using the source file path
|
||||
if (!assetReference->m_assetId.IsValid() && !assetReference->m_filePath.empty())
|
||||
{
|
||||
AZStd::string path = assetReference->m_filePath;
|
||||
const AZStd::string& path = assetReference->m_filePath;
|
||||
uint32_t subId = 0;
|
||||
|
||||
auto assetIdOutcome = AssetUtils::MakeAssetId(path, subId);
|
||||
if (job != nullptr) // Create Job Phase
|
||||
{
|
||||
params.dependencySourceFile = path;
|
||||
bool dependencyAddedSuccessfully = AddDependency(params, job);
|
||||
success = dependencyAddedSuccessfully && success;
|
||||
}
|
||||
else // Process Job Phase
|
||||
{
|
||||
auto assetIdOutcome = AssetUtils::MakeAssetId(path, subId);
|
||||
|
||||
if (assetIdOutcome)
|
||||
{
|
||||
assetReference->m_assetId = assetIdOutcome.GetValue();
|
||||
if (assetIdOutcome)
|
||||
{
|
||||
assetReference->m_assetId = assetIdOutcome.GetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(PassBuilderName, false, "Could not get AssetId for [%s]", assetReference->m_filePath.c_str());
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error(PassBuilderName, false, "Could not get AssetId for [%s]", assetReference->m_filePath.c_str());
|
||||
foundProblems = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the asset ID is valid, add it as a dependency
|
||||
if (assetReference->m_assetId.IsValid())
|
||||
{
|
||||
referencedAssetList.insert(assetReference->m_assetId);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -136,26 +155,100 @@ namespace AZ
|
||||
SerializeContext::EnumerateInstanceCallContext callContext(
|
||||
AZStd::move(beginCallback),
|
||||
nullptr,
|
||||
context,
|
||||
params.serializeContext,
|
||||
SerializeContext::ENUM_ACCESS_FOR_READ,
|
||||
&errorLogger
|
||||
);
|
||||
|
||||
// Recursively iterate over all elements in the object to find asset references with the above callback
|
||||
context->EnumerateInstance(
|
||||
params.serializeContext->EnumerateInstance(
|
||||
&callContext
|
||||
, objectPtr
|
||||
, passAssetUuid
|
||||
, params.passAssetObject
|
||||
, params.passAssetUuid
|
||||
, nullptr
|
||||
, nullptr
|
||||
);
|
||||
|
||||
return !foundProblems;
|
||||
return success;
|
||||
}
|
||||
|
||||
// --- Code related to dependency shader asset handling ---
|
||||
|
||||
void PassBuilder::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) const
|
||||
{
|
||||
// --- Handle shutdown case ---
|
||||
|
||||
if (m_isShuttingDown)
|
||||
{
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown;
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Get serialization context ---
|
||||
|
||||
SerializeContext* serializeContext = nullptr;
|
||||
ComponentApplicationBus::BroadcastResult(serializeContext, &ComponentApplicationBus::Events::GetSerializeContext);
|
||||
if (!serializeContext)
|
||||
{
|
||||
AZ_Assert(false, "No serialize context");
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Load PassAsset ---
|
||||
|
||||
AZStd::string fullPath;
|
||||
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.c_str(), request.m_sourceFile.c_str(), fullPath, true);
|
||||
|
||||
PassAsset passAsset;
|
||||
AZ::Outcome<void, AZStd::string> loadResult = JsonSerializationUtils::LoadObjectFromFile(passAsset, fullPath);
|
||||
|
||||
if (!loadResult.IsSuccess())
|
||||
{
|
||||
AZ_Error(PassBuilderName, false, "Failed to load pass asset [%s]", request.m_sourceFile.c_str());
|
||||
AZ_Error(PassBuilderName, false, "Loading issues: %s", loadResult.GetError().data());
|
||||
return;
|
||||
}
|
||||
|
||||
AssetBuilderSDK::JobDescriptor job;
|
||||
job.m_jobKey = PassBuilderJobKey;
|
||||
job.m_critical = true; // Passes are a critical part of the rendering system
|
||||
|
||||
// --- Find all dependencies ---
|
||||
|
||||
AZStd::unordered_set<Data::AssetId> dependentList;
|
||||
Uuid passAssetUuid = AzTypeInfo<PassAsset>::Uuid();
|
||||
|
||||
FindPassReferenceAssetParams params;
|
||||
params.passAssetObject = &passAsset;
|
||||
params.passAssetSourceFile = request.m_sourceFile;
|
||||
params.passAssetUuid = passAssetUuid;
|
||||
params.serializeContext = serializeContext;
|
||||
params.jobKey = "Shader Asset";
|
||||
|
||||
if (!FindReferencedAssets(params, &job))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Create a job per platform ---
|
||||
|
||||
for (const AssetBuilderSDK::PlatformInfo& platformInfo : request.m_enabledPlatforms)
|
||||
{
|
||||
for (auto& jobDependency : job.m_jobDependencyList)
|
||||
{
|
||||
jobDependency.m_platformIdentifier = platformInfo.m_identifier.c_str();
|
||||
}
|
||||
job.SetPlatformIdentifier(platformInfo.m_identifier.c_str());
|
||||
response.m_createJobOutputs.push_back(job);
|
||||
}
|
||||
|
||||
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
|
||||
}
|
||||
|
||||
void PassBuilder::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) const
|
||||
{
|
||||
// Handle job cancellation and shutdown cases
|
||||
// --- Handle job cancellation and shutdown cases ---
|
||||
|
||||
AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
|
||||
if (jobCancelListener.IsCancelled() || m_isShuttingDown)
|
||||
{
|
||||
@@ -163,16 +256,18 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
|
||||
// Get serialization context
|
||||
SerializeContext* context = nullptr;
|
||||
ComponentApplicationBus::BroadcastResult(context, &ComponentApplicationBus::Events::GetSerializeContext);
|
||||
if (!context)
|
||||
// --- Get serialization context ---
|
||||
|
||||
SerializeContext* serializeContext = nullptr;
|
||||
ComponentApplicationBus::BroadcastResult(serializeContext, &ComponentApplicationBus::Events::GetSerializeContext);
|
||||
if (!serializeContext)
|
||||
{
|
||||
AZ_Assert(false, "No serialize context");
|
||||
return;
|
||||
}
|
||||
|
||||
// Load PassAsset
|
||||
// --- Load PassAsset ---
|
||||
|
||||
PassAsset passAsset;
|
||||
AZ::Outcome<void, AZStd::string> loadResult = JsonSerializationUtils::LoadObjectFromFile(passAsset, request.m_fullPath);
|
||||
|
||||
@@ -183,36 +278,42 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
|
||||
// Find all Asset IDs we depend on
|
||||
AZStd::unordered_set<Data::AssetId> dependentList;
|
||||
// --- Find all dependencies ---
|
||||
|
||||
Uuid passAssetUuid = AzTypeInfo<PassAsset>::Uuid();
|
||||
if (!FindPassReferencedAssets(&passAsset, passAssetUuid, context, dependentList))
|
||||
|
||||
FindPassReferenceAssetParams params;
|
||||
params.passAssetObject = &passAsset;
|
||||
params.passAssetSourceFile = request.m_sourceFile;
|
||||
params.passAssetUuid = passAssetUuid;
|
||||
params.serializeContext = serializeContext;
|
||||
params.jobKey = "Shader Asset";
|
||||
|
||||
if (!FindReferencedAssets(params, nullptr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get destination file name and path
|
||||
// --- Get destination file name and path ---
|
||||
|
||||
AZStd::string destFileName;
|
||||
AZStd::string destPath;
|
||||
AzFramework::StringFunc::Path::GetFullFileName(request.m_fullPath.c_str(), destFileName);
|
||||
AzFramework::StringFunc::Path::ConstructFull(request.m_tempDirPath.c_str(), destFileName.c_str(), destPath, true);
|
||||
|
||||
// Save the asset to binary format for production
|
||||
bool result = Utils::SaveObjectToFile(destPath, DataStream::ST_BINARY, &passAsset, passAssetUuid, context);
|
||||
// --- Save the asset to binary format for production ---
|
||||
|
||||
bool result = Utils::SaveObjectToFile(destPath, DataStream::ST_BINARY, &passAsset, passAssetUuid, serializeContext);
|
||||
if (result == false)
|
||||
{
|
||||
AZ_Error(PassBuilderName, false, "Failed to save asset to %s", destPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Success. Save output product(s) to response
|
||||
AssetBuilderSDK::JobProduct jobProduct(destPath, PassAsset::RTTI_Type(), 0);
|
||||
for (auto& assetId : dependentList)
|
||||
{
|
||||
jobProduct.m_dependencies.emplace_back(AssetBuilderSDK::ProductDependency(assetId, 0));
|
||||
}
|
||||
// --- Save output product(s) to response ---
|
||||
|
||||
jobProduct.m_dependenciesHandled = true; // We've output the dependencies immediately above so it's OK to tell the AP we've handled dependencies
|
||||
AssetBuilderSDK::JobProduct jobProduct(destPath, PassAsset::RTTI_Type(), 0);
|
||||
jobProduct.m_dependenciesHandled = true;
|
||||
response.m_outputProducts.push_back(jobProduct);
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ namespace AZ
|
||||
void RegisterBuilder();
|
||||
|
||||
private:
|
||||
bool FindPassReferencedAssets(void* objectPtr, Uuid passAssetUuid, SerializeContext* context, AZStd::unordered_set<Data::AssetId> &referencedAssetList) const;
|
||||
bool m_isShuttingDown = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -474,10 +474,10 @@ namespace AZ
|
||||
// Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers
|
||||
uint32_t vertexDataSize = vertexCount * m_perVertexDataSize;
|
||||
RHI::Ptr<DynamicBuffer> vertexBuffer;
|
||||
vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize);
|
||||
vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly);
|
||||
|
||||
uint32_t indexDataSize = indexCount * RHI::GetIndexFormatSize(indexFormat);
|
||||
RHI::Ptr<DynamicBuffer> indexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(indexDataSize);
|
||||
RHI::Ptr<DynamicBuffer> indexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(indexDataSize, RHI::Alignment::InputAssembly);
|
||||
|
||||
if (indexBuffer == nullptr || vertexBuffer == nullptr)
|
||||
{
|
||||
@@ -572,7 +572,7 @@ namespace AZ
|
||||
// Get dynamic buffers for vertex and index buffer. Skip draw if failed to allocate buffers
|
||||
uint32_t vertexDataSize = vertexCount * m_perVertexDataSize;
|
||||
RHI::Ptr<DynamicBuffer> vertexBuffer;
|
||||
vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize);
|
||||
vertexBuffer = DynamicDrawInterface::Get()->GetDynamicBuffer(vertexDataSize, RHI::Alignment::InputAssembly);
|
||||
|
||||
if (vertexBuffer == nullptr)
|
||||
{
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace AZ
|
||||
|
||||
// Load shader and srg
|
||||
const char* ShaderPath = "shader/decomposemsimage.azshader";
|
||||
m_decomposeShader = LoadShader(ShaderPath);
|
||||
m_decomposeShader = LoadCriticalShader(ShaderPath);
|
||||
|
||||
if (m_decomposeShader == nullptr)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
|
||||
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
@@ -20,7 +21,7 @@ namespace AZ
|
||||
namespace RPI
|
||||
{
|
||||
|
||||
Data::AssetId GetShaderAssetId(const AZStd::string& shaderFilePath)
|
||||
Data::AssetId GetShaderAssetId(const AZStd::string& shaderFilePath, bool isCritical)
|
||||
{
|
||||
Data::AssetId shaderAssetId;
|
||||
|
||||
@@ -34,6 +35,19 @@ namespace AZ
|
||||
|
||||
if (!shaderAssetId.IsValid())
|
||||
{
|
||||
if (isCritical)
|
||||
{
|
||||
Data::Asset<RPI::ShaderAsset> shaderAsset = RPI::AssetUtils::LoadCriticalAsset<RPI::ShaderAsset>(shaderFilePath);
|
||||
if (shaderAsset.IsReady())
|
||||
{
|
||||
return shaderAsset.GetId();
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("RPI Utils", false, "Could not load critical shader [%s]", shaderFilePath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Error("RPI Utils", false, "Failed to get asset id for shader [%s]", shaderFilePath.c_str());
|
||||
}
|
||||
|
||||
@@ -83,11 +97,23 @@ namespace AZ
|
||||
return FindShaderAsset(GetShaderAssetId(shaderFilePath), shaderFilePath);
|
||||
}
|
||||
|
||||
Data::Asset<ShaderAsset> FindCriticalShaderAsset(const AZStd::string& shaderFilePath)
|
||||
{
|
||||
const bool isCritical = true;
|
||||
return FindShaderAsset(GetShaderAssetId(shaderFilePath, isCritical), shaderFilePath);
|
||||
}
|
||||
|
||||
Data::Instance<Shader> LoadShader(const AZStd::string& shaderFilePath)
|
||||
{
|
||||
return LoadShader(GetShaderAssetId(shaderFilePath), shaderFilePath);
|
||||
}
|
||||
|
||||
Data::Instance<Shader> LoadCriticalShader(const AZStd::string& shaderFilePath)
|
||||
{
|
||||
const bool isCritical = true;
|
||||
return LoadShader(GetShaderAssetId(shaderFilePath, isCritical), shaderFilePath);
|
||||
}
|
||||
|
||||
AZ::Data::Instance<RPI::StreamingImage> LoadStreamingTexture(AZStd::string_view path)
|
||||
{
|
||||
AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown;
|
||||
|
||||
Reference in New Issue
Block a user