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.
o3de/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp

242 lines
8.8 KiB
C++

/*
* 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 "AssetSystemDebugComponent.h"
#include "ISystem.h"
#include "IRenderAuxGeom.h"
#include "AzCore/Asset/AssetManager.h"
#include <AzCore/Console/IConsole.h>
#include <AzCore/Jobs/JobFunction.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace LmbrCentral
{
AZ_CVAR(bool, cl_assetStatusDebugActiveAssets, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Show debug stats about loading assets."
" Data is not collected while disabled so it is recommended to enable this via command line or config");
AZ_CVAR(bool, cl_assetStatusDebugLoadedAssets, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Show debug stats about loaded assets."
" Data is not collected while disabled so it is recommended to enable this via command line or config");
AZ_CVAR(std::uint8_t, cl_assetStatusDebugDisplayCount, 20, nullptr, AZ::ConsoleFunctorFlags::Null,
"Sets the max number of assets to record and display in debug stats. This will only update after more assets have loaded.");
void AssetSystemDebugComponent::Activate()
{
BusConnect();
AZ::Interface<IDebugAssetEvent>::Register(this);
}
void AssetSystemDebugComponent::Deactivate()
{
AZ::Interface<IDebugAssetEvent>::Unregister(this);
BusDisconnect();
}
AZStd::string StatusToString(AZ::Data::AssetData::AssetStatus status)
{
switch (status)
{
case AZ::Data::AssetData::AssetStatus::NotLoaded:
return "Not Loaded";
case AZ::Data::AssetData::AssetStatus::Queued:
return "Queued";
case AZ::Data::AssetData::AssetStatus::StreamReady:
return "Stream Ready";
case AZ::Data::AssetData::AssetStatus::Loading:
return "Loading";
case AZ::Data::AssetData::AssetStatus::LoadedPreReady:
return "Loaded Pre-Ready";
case AZ::Data::AssetData::AssetStatus::ReadyPreNotify:
return "Ready Pre-Notify";
case AZ::Data::AssetData::AssetStatus::Ready:
return "Ready";
case AZ::Data::AssetData::AssetStatus::Error:
return "Error";
default:
return "Unknown State";
}
}
void AssetSystemDebugComponent::DrawGlobalDebugInfo()
{
if(!cl_assetStatusDebugActiveAssets && !cl_assetStatusDebugLoadedAssets)
{
return;
}
// ToDo: Remove class or update to work with Atom? LYN-3672
/*float x = 10;
float y = 15;
ColorF color(1, 1, 1);
constexpr bool center = false;
constexpr float ySpacing = 14;
constexpr float fontSize = 1.3;
const int maxCount = cl_assetStatusDebugDisplayCount;
if (cl_assetStatusDebugActiveAssets)
{
// Make a local copy of the "oldest active" list. We don't want to hold the eventMutex while calling FindAsset below
// or else we open up the possibility of lock inversion deadlocks. This routines would lock eventMutex then AssetManager
// locks, but modifications to the load data history can happen from multiple loading threads that lock AssetManager mutexes
// before locking the eventMutex.
AZStd::vector<AZ::Data::AssetId> oldestActive(m_oldestActive.size());
{
AZStd::scoped_lock lock(m_eventMutex);
for (auto& info : m_oldestActive)
{
oldestActive.emplace_back(info->m_id);
}
}
auxGeom->Draw2dLabel(x, y, fontSize, color, center, "Last %d assets to start loading, oldest to newest:", maxCount);
y += ySpacing; // Extra space after the "title"
for (auto& oldestActiveId : oldestActive)
{
y += ySpacing;
auto asset = AZ::Data::AssetManager::Instance().FindAsset(oldestActiveId, AZ::Data::AssetLoadBehavior::Default);
auxGeom->Draw2dLabel(x, y, fontSize, color, center, "%s - %s",
asset.GetHint().length() > 0 ? asset.GetHint().c_str() : oldestActiveId.ToString<AZStd::string>().c_str(),
StatusToString(asset.GetStatus()).c_str());
}
}
if (cl_assetStatusDebugLoadedAssets)
{
// Same as above - make a local copy of the list to avoid lock inversion deadlocks.
AZStd::vector<AZStd::pair<AZ::Data::AssetId, AZStd::chrono::duration<float, AZStd::milli>>> activeAssets(m_recentlyCompleted.size());
{
AZStd::scoped_lock lock(m_eventMutex);
for (auto& info : m_recentlyCompleted)
{
activeAssets.emplace_back(info->m_id, info->m_loadFinish - info->m_loadStart);
}
}
if(cl_assetStatusDebugActiveAssets)
{
y = 15;
x = 1200;
}
auxGeom->Draw2dLabelCustom(x, y, fontSize, color, eDrawText_Right, "Last %d assets loaded, most recent first:", maxCount);
y += ySpacing; // Extra space after the "title"
for (auto& [activeAssetId, activeAssetLoadTime] : activeAssets)
{
y += ySpacing;
auto asset = AZ::Data::AssetManager::Instance().FindAsset(activeAssetId, AZ::Data::AssetLoadBehavior::Default);
auxGeom->Draw2dLabelCustom(x, y, fontSize, color, eDrawText_Right, "%s - %s - %fms",
asset.GetHint().length() > 0 ? asset.GetHint().c_str() : activeAssetId.ToString<AZStd::string>().c_str(),
StatusToString(asset.GetStatus()).c_str(),
activeAssetLoadTime.count());
}
}*/
}
void AssetSystemDebugComponent::AssetStatusUpdate(AZ::Data::AssetId id, AZ::Data::AssetData::AssetStatus status)
{
using namespace AZ::Data;
if (!cl_assetStatusDebugActiveAssets && !cl_assetStatusDebugLoadedAssets)
{
return;
}
AZStd::scoped_lock lock(m_eventMutex);
auto itr = m_events.find(id);
bool exists = itr != m_events.end();
if (exists)
{
itr->second.m_status = status;
}
switch (status)
{
case AssetData::AssetStatus::Queued:
{
EventInfo info;
info.m_id = id;
info.m_status = status;
info.m_loadStart = AZStd::chrono::system_clock::now();
m_events[id] = info;
m_oldestActive.insert(&m_events[id]);
while (m_oldestActive.size() > cl_assetStatusDebugDisplayCount)
{
m_oldestActive.erase(--(m_oldestActive.end()));
}
}
break;
case AssetData::AssetStatus::Error:
case AssetData::AssetStatus::ReadyPreNotify:
{
if(exists)
{
itr->second.m_loadFinish = AZStd::chrono::system_clock::now();
m_recentlyCompleted.insert(&itr->second);
m_oldestActive.erase(&itr->second);
while (m_recentlyCompleted.size() > cl_assetStatusDebugDisplayCount)
{
auto last = --(m_recentlyCompleted.end());
m_events.erase((*last)->m_id);
m_recentlyCompleted.erase(last);
}
}
}
break;
}
}
void AssetSystemDebugComponent::ReleaseAsset(AZ::Data::AssetId id)
{
AZStd::scoped_lock lock(m_eventMutex);
auto itr = m_events.find(id);
if(itr != m_events.end())
{
m_oldestActive.erase(&itr->second);
m_recentlyCompleted.erase(&itr->second);
m_events.erase(itr);
}
}
void AssetSystemDebugComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("AssetSystemDebug"));
}
void AssetSystemDebugComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("AssetSystemDebug"));
}
void AssetSystemDebugComponent::Reflect(AZ::ReflectContext* reflection)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(reflection))
{
serialize->Class<AssetSystemDebugComponent, AZ::Component>()
->Version(0)
;
}
}
}