Merge branch 'development' of https://github.com/aws-lumberyard-dev/o3de into mnaumov/2372_signOffFix
Signed-off-by: Mikhail Naumov <mnaumov@amazon.com>
This commit is contained in:
+2
-34
@@ -219,42 +219,10 @@ namespace AzToolsFramework
|
||||
bool PrefabEditorEntityOwnershipService::SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename)
|
||||
{
|
||||
AZ::IO::Path relativePath = m_loaderInterface->GenerateRelativePath(filename);
|
||||
AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath);
|
||||
|
||||
m_rootInstance->SetTemplateSourcePath(relativePath);
|
||||
|
||||
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
|
||||
{
|
||||
m_rootInstance->m_containerEntity->AddComponent(aznew Prefab::EditorPrefabComponent());
|
||||
HandleEntitiesAdded({ m_rootInstance->m_containerEntity.get() });
|
||||
|
||||
AzToolsFramework::Prefab::PrefabDom dom;
|
||||
bool success = AzToolsFramework::Prefab::PrefabDomUtils::StoreInstanceInPrefabDom(*m_rootInstance, dom);
|
||||
if (!success)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Failed to convert current root instance into a DOM when saving file '%.*s'", AZ_STRING_ARG(filename));
|
||||
return false;
|
||||
}
|
||||
templateId = m_prefabSystemComponent->AddTemplate(relativePath, AZStd::move(dom));
|
||||
|
||||
if (templateId == AzToolsFramework::Prefab::InvalidTemplateId)
|
||||
{
|
||||
AZ_Error("Prefab", false, "Couldn't add new template id '%i' when saving file '%.*s'", templateId, AZ_STRING_ARG(filename));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Prefab::TemplateId prevTemplateId = m_rootInstance->GetTemplateId();
|
||||
m_rootInstance->SetTemplateId(templateId);
|
||||
|
||||
if (prevTemplateId != Prefab::InvalidTemplateId && templateId != prevTemplateId)
|
||||
{
|
||||
// Make sure we only have one level template loaded at a time
|
||||
m_prefabSystemComponent->RemoveTemplate(prevTemplateId);
|
||||
}
|
||||
|
||||
|
||||
AZStd::string out;
|
||||
|
||||
if (!m_loaderInterface->SaveTemplateToString(m_rootInstance->GetTemplateId(), out))
|
||||
{
|
||||
return false;
|
||||
@@ -266,7 +234,7 @@ namespace AzToolsFramework
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_prefabSystemComponent->SetTemplateDirtyFlag(templateId, false);
|
||||
m_prefabSystemComponent->SetTemplateDirtyFlag(m_rootInstance->GetTemplateId(), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "ProfilingCaptureSystemComponent.h"
|
||||
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/CpuProfilerImpl.h>
|
||||
#include <Atom/RHI/RHIUtils.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
#include <Atom/RHI.Reflect/CpuTimingStatistics.h>
|
||||
@@ -141,36 +142,6 @@ namespace AZ
|
||||
AZStd::vector<PipelineStatisticsSerializerEntry> m_pipelineStatisticsEntries;
|
||||
};
|
||||
|
||||
// Intermediate class to serialize Cpu TimedRegion data.
|
||||
class CpuProfilingStatisticsSerializer
|
||||
{
|
||||
public:
|
||||
class CpuProfilingStatisticsSerializerEntry
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry, "{26B78F65-EB96-46E2-BE7E-A1233880B225}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
CpuProfilingStatisticsSerializerEntry() = default;
|
||||
CpuProfilingStatisticsSerializerEntry(const RHI::CachedTimeRegion& cachedTimeRegion);
|
||||
|
||||
private:
|
||||
Name m_groupName;
|
||||
Name m_regionName;
|
||||
uint16_t m_stackDepth;
|
||||
AZStd::sys_time_t m_startTick;
|
||||
AZStd::sys_time_t m_endTick;
|
||||
};
|
||||
|
||||
AZ_TYPE_INFO(CpuProfilingStatisticsSerializer, "{D5B02946-0D27-474F-9A44-364C2706DD41}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
CpuProfilingStatisticsSerializer() = default;
|
||||
CpuProfilingStatisticsSerializer(const AZStd::ring_buffer<RHI::CpuProfiler::TimeRegionMap>& continuousData);
|
||||
|
||||
AZStd::vector<CpuProfilingStatisticsSerializerEntry> m_cpuProfilingStatisticsSerializerEntries;
|
||||
};
|
||||
|
||||
// Intermediate class to serialize benchmark metadata.
|
||||
class BenchmarkMetadataSerializer
|
||||
{
|
||||
@@ -327,65 +298,6 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
// --- CpuProfilingStatisticsSerializer ---
|
||||
|
||||
CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializer(const AZStd::ring_buffer<RHI::CpuProfiler::TimeRegionMap>& continuousData)
|
||||
{
|
||||
// Create serializable entries
|
||||
for (const auto& timeRegionMap : continuousData)
|
||||
{
|
||||
for (const auto& threadEntry : timeRegionMap)
|
||||
{
|
||||
for (const auto& cachedRegionEntry : threadEntry.second)
|
||||
{
|
||||
m_cpuProfilingStatisticsSerializerEntries.insert(
|
||||
m_cpuProfilingStatisticsSerializerEntries.end(),
|
||||
cachedRegionEntry.second.begin(),
|
||||
cachedRegionEntry.second.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpuProfilingStatisticsSerializer::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<CpuProfilingStatisticsSerializer>()
|
||||
->Version(1)
|
||||
->Field("cpuProfilingStatisticsSerializerEntry", &CpuProfilingStatisticsSerializer::m_cpuProfilingStatisticsSerializerEntries)
|
||||
;
|
||||
}
|
||||
|
||||
CpuProfilingStatisticsSerializerEntry::Reflect(context);
|
||||
}
|
||||
|
||||
// --- CpuProfilingStatisticsSerializerEntry ---
|
||||
|
||||
CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::CpuProfilingStatisticsSerializerEntry(const RHI::CachedTimeRegion& cachedTimeRegion)
|
||||
{
|
||||
m_groupName = cachedTimeRegion.m_groupRegionName->m_groupName;
|
||||
m_regionName = cachedTimeRegion.m_groupRegionName->m_regionName;
|
||||
m_stackDepth = cachedTimeRegion.m_stackDepth;
|
||||
m_startTick = cachedTimeRegion.m_startTick;
|
||||
m_endTick = cachedTimeRegion.m_endTick;
|
||||
}
|
||||
|
||||
void CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<CpuProfilingStatisticsSerializerEntry>()
|
||||
->Version(1)
|
||||
->Field("groupName", &CpuProfilingStatisticsSerializerEntry::m_groupName)
|
||||
->Field("regionName", &CpuProfilingStatisticsSerializerEntry::m_regionName)
|
||||
->Field("stackDepth", &CpuProfilingStatisticsSerializerEntry::m_stackDepth)
|
||||
->Field("startTick", &CpuProfilingStatisticsSerializerEntry::m_startTick)
|
||||
->Field("endTick", &CpuProfilingStatisticsSerializerEntry::m_endTick)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
// --- BenchmarkMetadataSerializer ---
|
||||
|
||||
BenchmarkMetadataSerializer::BenchmarkMetadataSerializer(const AZStd::string& benchmarkName, const RHI::PhysicalDeviceDescriptor& gpuDescriptor)
|
||||
@@ -458,7 +370,7 @@ namespace AZ
|
||||
TimestampSerializer::Reflect(context);
|
||||
CpuFrameTimeSerializer::Reflect(context);
|
||||
PipelineStatisticsSerializer::Reflect(context);
|
||||
CpuProfilingStatisticsSerializer::Reflect(context);
|
||||
RHI::CpuProfilingStatisticsSerializer::Reflect(context);
|
||||
BenchmarkMetadataSerializer::Reflect(context);
|
||||
}
|
||||
|
||||
@@ -651,10 +563,10 @@ namespace AZ
|
||||
JsonSerializerSettings serializationSettings;
|
||||
serializationSettings.m_keepDefaults = true;
|
||||
|
||||
CpuProfilingStatisticsSerializer serializer(data);
|
||||
RHI::CpuProfilingStatisticsSerializer serializer(data);
|
||||
|
||||
const auto saveResult = JsonSerializationUtils::SaveObjectToFile(&serializer,
|
||||
outputFilePath, (CpuProfilingStatisticsSerializer*)nullptr, &serializationSettings);
|
||||
outputFilePath, (RHI::CpuProfilingStatisticsSerializer*)nullptr, &serializationSettings);
|
||||
|
||||
AZStd::string captureInfo = outputFilePath;
|
||||
if (!saveResult.IsSuccess())
|
||||
@@ -694,7 +606,7 @@ namespace AZ
|
||||
const bool captureStarted = m_cpuProfilingStatisticsCapture.StartCapture([this, outputFilePath, wasEnabled]()
|
||||
{
|
||||
// Blocking call for a single frame of data, avoid thread overhead
|
||||
AZStd::ring_buffer<RHI::CpuProfiler::TimeRegionMap> singleFrameData;
|
||||
AZStd::ring_buffer<RHI::CpuProfiler::TimeRegionMap> singleFrameData(1);
|
||||
singleFrameData.push_back(RHI::CpuProfiler::Get()->GetTimeRegionMap());
|
||||
SerializeCpuProfilingData(singleFrameData, outputFilePath, wasEnabled);
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/unordered_set.h>
|
||||
#include <AzCore/std/parallel/mutex.h>
|
||||
@@ -161,5 +162,33 @@ namespace AZ
|
||||
AZStd::ring_buffer<TimeRegionMap> m_continuousCaptureData;
|
||||
};
|
||||
|
||||
}; // namespace RPI
|
||||
// Intermediate class to serialize Cpu TimedRegion data.
|
||||
class CpuProfilingStatisticsSerializer
|
||||
{
|
||||
public:
|
||||
class CpuProfilingStatisticsSerializerEntry
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry, "{26B78F65-EB96-46E2-BE7E-A1233880B225}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
CpuProfilingStatisticsSerializerEntry() = default;
|
||||
CpuProfilingStatisticsSerializerEntry(const RHI::CachedTimeRegion& cachedTimeRegion);
|
||||
|
||||
Name m_groupName;
|
||||
Name m_regionName;
|
||||
uint16_t m_stackDepth;
|
||||
AZStd::sys_time_t m_startTick;
|
||||
AZStd::sys_time_t m_endTick;
|
||||
};
|
||||
|
||||
AZ_TYPE_INFO(CpuProfilingStatisticsSerializer, "{D5B02946-0D27-474F-9A44-364C2706DD41}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
CpuProfilingStatisticsSerializer() = default;
|
||||
CpuProfilingStatisticsSerializer(const AZStd::ring_buffer<RHI::CpuProfiler::TimeRegionMap>& continuousData);
|
||||
|
||||
AZStd::vector<CpuProfilingStatisticsSerializerEntry> m_cpuProfilingStatisticsSerializerEntries;
|
||||
};
|
||||
}; // namespace RHI
|
||||
}; // namespace AZ
|
||||
|
||||
@@ -409,5 +409,64 @@ namespace AZ
|
||||
m_cachedTimeRegionMutex.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- CpuProfilingStatisticsSerializer ---
|
||||
|
||||
CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializer(const AZStd::ring_buffer<RHI::CpuProfiler::TimeRegionMap>& continuousData)
|
||||
{
|
||||
// Create serializable entries
|
||||
for (const auto& timeRegionMap : continuousData)
|
||||
{
|
||||
for (const auto& threadEntry : timeRegionMap)
|
||||
{
|
||||
for (const auto& cachedRegionEntry : threadEntry.second)
|
||||
{
|
||||
m_cpuProfilingStatisticsSerializerEntries.insert(
|
||||
m_cpuProfilingStatisticsSerializerEntries.end(),
|
||||
cachedRegionEntry.second.begin(),
|
||||
cachedRegionEntry.second.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpuProfilingStatisticsSerializer::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<CpuProfilingStatisticsSerializer>()
|
||||
->Version(1)
|
||||
->Field("cpuProfilingStatisticsSerializerEntries", &CpuProfilingStatisticsSerializer::m_cpuProfilingStatisticsSerializerEntries)
|
||||
;
|
||||
}
|
||||
|
||||
CpuProfilingStatisticsSerializerEntry::Reflect(context);
|
||||
}
|
||||
|
||||
// --- CpuProfilingStatisticsSerializerEntry ---
|
||||
|
||||
CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::CpuProfilingStatisticsSerializerEntry(const RHI::CachedTimeRegion& cachedTimeRegion)
|
||||
{
|
||||
m_groupName = cachedTimeRegion.m_groupRegionName->m_groupName;
|
||||
m_regionName = cachedTimeRegion.m_groupRegionName->m_regionName;
|
||||
m_stackDepth = cachedTimeRegion.m_stackDepth;
|
||||
m_startTick = cachedTimeRegion.m_startTick;
|
||||
m_endTick = cachedTimeRegion.m_endTick;
|
||||
}
|
||||
|
||||
void CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<CpuProfilingStatisticsSerializerEntry>()
|
||||
->Version(1)
|
||||
->Field("groupName", &CpuProfilingStatisticsSerializerEntry::m_groupName)
|
||||
->Field("regionName", &CpuProfilingStatisticsSerializerEntry::m_regionName)
|
||||
->Field("stackDepth", &CpuProfilingStatisticsSerializerEntry::m_stackDepth)
|
||||
->Field("startTick", &CpuProfilingStatisticsSerializerEntry::m_startTick)
|
||||
->Field("endTick", &CpuProfilingStatisticsSerializerEntry::m_endTick)
|
||||
;
|
||||
}
|
||||
}
|
||||
} // namespace RHI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
|
||||
#include <AtomCore/Serialization/Json/JsonUtils.h>
|
||||
|
||||
#include <Atom/RPI.Edit/Common/JsonFileLoadContext.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonReportingHelper.h>
|
||||
|
||||
@@ -118,7 +120,6 @@ namespace AZ
|
||||
AZ_Error("AZ::RPI::JsonUtils", false, "Failed to load object from json string: %s", loadResult.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace JsonUtils
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -40,29 +40,35 @@ namespace AtomToolsFramework
|
||||
|
||||
const AZStd::any& AtomToolsDocument::GetPropertyValue(const AZ::Name& propertyFullName) const
|
||||
{
|
||||
AZ_UNUSED(propertyFullName);
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return m_invalidValue;
|
||||
}
|
||||
|
||||
const AtomToolsFramework::DynamicProperty& AtomToolsDocument::GetProperty(const AZ::Name& propertyFullName) const
|
||||
{
|
||||
AZ_UNUSED(propertyFullName);
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return m_invalidProperty;
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const
|
||||
{
|
||||
AZ_UNUSED(propertyGroupFullName);
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
void AtomToolsDocument::SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value)
|
||||
{
|
||||
AZ_UNUSED(propertyFullName);
|
||||
AZ_UNUSED(value);
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
}
|
||||
|
||||
bool AtomToolsDocument::Open(AZStd::string_view loadPath)
|
||||
{
|
||||
AZ_UNUSED(loadPath);
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
@@ -81,6 +87,7 @@ namespace AtomToolsFramework
|
||||
|
||||
bool AtomToolsDocument::SaveAsCopy(AZStd::string_view savePath)
|
||||
{
|
||||
AZ_UNUSED(savePath);
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
@@ -88,6 +95,7 @@ namespace AtomToolsFramework
|
||||
|
||||
bool AtomToolsDocument::SaveAsChild(AZStd::string_view savePath)
|
||||
{
|
||||
AZ_UNUSED(savePath);
|
||||
AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Math/Random.h>
|
||||
|
||||
#include <Atom/RHI.Reflect/CpuTimingStatistics.h>
|
||||
@@ -102,6 +103,12 @@ namespace AZ
|
||||
//! Draws the statistical view of the CPU profiling data.
|
||||
void DrawStatisticsView();
|
||||
|
||||
//! Callback invoked when the "Load File" button is pressed in the file picker.
|
||||
void LoadFile();
|
||||
|
||||
//! Draws the file picker window.
|
||||
void DrawFilePicker();
|
||||
|
||||
//! Draws the CPU profiling visualizer.
|
||||
void DrawVisualizer();
|
||||
|
||||
@@ -198,6 +205,14 @@ namespace AZ
|
||||
AZ::RHI::CpuTimingStatistics m_cpuTimingStatisticsWhenPause;
|
||||
|
||||
AZStd::string m_lastCapturedFilePath;
|
||||
|
||||
bool m_showFilePicker = false;
|
||||
|
||||
// Cached file paths to previous traces on disk, sorted with the most recent trace at the front.
|
||||
AZStd::vector<IO::Path> m_cachedCapturePaths;
|
||||
|
||||
// Index into the file picker, used to determine which file to load when "Load File" is pressed.
|
||||
int m_currentFileIndex = 0;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -9,9 +9,14 @@
|
||||
#include <Atom/Feature/Utils/ProfilingCaptureBus.h>
|
||||
#include <Atom/RHI.Reflect/CpuTimingStatistics.h>
|
||||
#include <Atom/RHI/CpuProfiler.h>
|
||||
#include <Atom/RHI/CpuProfilerImpl.h>
|
||||
#include <Atom/RPI.Edit/Common/JsonUtils.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
|
||||
#include <AzCore/IO/Path/Path_fwd.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/JSON/filereadstream.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/set.h>
|
||||
#include <AzCore/std/limits.h>
|
||||
@@ -45,6 +50,74 @@ namespace AZ
|
||||
AZ_Assert(ticksPerSecond >= 1000, "Error in converting ticks to ms, expected ticksPerSecond >= 1000");
|
||||
return static_cast<float>((ticks * 1000) / (ticksPerSecond / 1000)) / 1000.0f;
|
||||
}
|
||||
|
||||
using DeserializedCpuData = AZStd::vector<RHI::CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry>;
|
||||
inline Outcome<DeserializedCpuData, AZStd::string> LoadSavedCpuProfilingStatistics(const AZStd::string& capturePath)
|
||||
{
|
||||
auto* base = IO::FileIOBase::GetInstance();
|
||||
|
||||
char resolvedPath[IO::MaxPathLength];
|
||||
if (!base->ResolvePath(capturePath.c_str(), resolvedPath, IO::MaxPathLength))
|
||||
{
|
||||
return Failure(AZStd::string::format("Could not resolve the path to file %s, is the path correct?", resolvedPath));
|
||||
}
|
||||
|
||||
u64 captureSizeBytes;
|
||||
const IO::Result fileSizeResult = base->Size(resolvedPath, captureSizeBytes);
|
||||
if (!fileSizeResult)
|
||||
{
|
||||
return Failure(AZStd::string::format("Could not read the size of file %s, is the path correct?", resolvedPath));
|
||||
}
|
||||
|
||||
// NOTE: this uses raw file pointers over the abstractions and utility functions provided by AZ::JsonSerializationUtils because
|
||||
// saved profiling captures can be upwards of 400 MB. This necessitates a buffered approach to avoid allocating huge chunks of memory.
|
||||
FILE* fp = nullptr;
|
||||
azfopen(&fp, resolvedPath, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
return Failure(AZStd::string::format("Could not fopen file %s, is the path correct?\n", resolvedPath));
|
||||
}
|
||||
|
||||
constexpr AZStd::size_t MaxBufSize = 65536;
|
||||
const AZStd::size_t bufSize = AZStd::min(MaxBufSize, aznumeric_cast<AZStd::size_t>(captureSizeBytes));
|
||||
char* buf = reinterpret_cast<char*>(azmalloc(bufSize));
|
||||
|
||||
rapidjson::Document document;
|
||||
rapidjson::FileReadStream inputStream(fp, buf, bufSize);
|
||||
document.ParseStream(inputStream);
|
||||
|
||||
azfree(buf);
|
||||
fclose(fp);
|
||||
|
||||
if (document.HasParseError())
|
||||
{
|
||||
const auto pe = document.GetParseError();
|
||||
return Failure(AZStd::string::format(
|
||||
"Rapidjson could not parse the document with ParseErrorCode %u. See 3rdParty/rapidjson/error.h for definitions.\n", pe));
|
||||
}
|
||||
|
||||
if (!document.IsObject() || !document.HasMember("ClassData"))
|
||||
{
|
||||
return Failure(AZStd::string::format(
|
||||
"Error in loading saved capture: top-level object does not have a ClassData field. Did the serialization format change recently?\n"));
|
||||
}
|
||||
|
||||
AZ_TracePrintf("JsonUtils", "Successfully loaded JSON into memory.\n");
|
||||
|
||||
const auto& root = document["ClassData"];
|
||||
RHI::CpuProfilingStatisticsSerializer serializer;
|
||||
const JsonSerializationResult::ResultCode deserializationResult = JsonSerialization::Load(serializer, root);
|
||||
if (deserializationResult.GetProcessing() == JsonSerializationResult::Processing::Halted
|
||||
|| serializer.m_cpuProfilingStatisticsSerializerEntries.empty())
|
||||
{
|
||||
return Failure(AZStd::string::format("Error in deserializing document: %s\n", deserializationResult.ToString(capturePath.c_str()).c_str()));
|
||||
}
|
||||
|
||||
AZ_TracePrintf("JsonUtils", "Successfully loaded CPU profiling data with %zu profiling entries.\n",
|
||||
serializer.m_cpuProfilingStatisticsSerializerEntries.size());
|
||||
|
||||
return Success(AZStd::move(serializer.m_cpuProfilingStatisticsSerializerEntries));
|
||||
}
|
||||
} // namespace CpuProfilerImGuiHelper
|
||||
|
||||
inline void ImGuiCpuProfiler::Draw(bool& keepDrawing, const AZ::RHI::CpuTimingStatistics& currentCpuTimingStatistics)
|
||||
@@ -80,6 +153,11 @@ namespace AZ
|
||||
{
|
||||
DrawStatisticsView();
|
||||
}
|
||||
|
||||
if (m_showFilePicker)
|
||||
{
|
||||
DrawFilePicker();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
@@ -110,6 +188,11 @@ namespace AZ
|
||||
|
||||
inline void ImGuiCpuProfiler::DrawCommonHeader()
|
||||
{
|
||||
if (!m_lastCapturedFilePath.empty())
|
||||
{
|
||||
ImGui::Text("Saved: %s", m_lastCapturedFilePath.c_str());
|
||||
}
|
||||
|
||||
if (ImGui::Button(m_enableVisualizer ? "Swap to statistics" : "Swap to visualizer"))
|
||||
{
|
||||
m_enableVisualizer = !m_enableVisualizer;
|
||||
@@ -157,10 +240,31 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_lastCapturedFilePath.empty())
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Load file"))
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Saved: %s", m_lastCapturedFilePath.c_str());
|
||||
m_showFilePicker = true;
|
||||
|
||||
// Only update the cached file list when opened so that we aren't making IO calls on every frame.
|
||||
auto* base = AZ::IO::FileIOBase::GetInstance();
|
||||
const AZStd::string defaultSavedCapturePath = "@user@/CpuProfiler";
|
||||
|
||||
m_cachedCapturePaths.clear();
|
||||
base->FindFiles(
|
||||
defaultSavedCapturePath.c_str(), "*.json",
|
||||
[&paths = m_cachedCapturePaths](const char* path) -> bool
|
||||
{
|
||||
auto foundPath = IO::Path(path);
|
||||
paths.push_back(foundPath);
|
||||
return true;
|
||||
});
|
||||
|
||||
// Sort by decreasing modification time (most recent at the top)
|
||||
AZStd::sort(m_cachedCapturePaths.begin(), m_cachedCapturePaths.end(),
|
||||
[&base](const IO::Path& lhs, const IO::Path& rhs)
|
||||
{
|
||||
return base->ModificationTime(lhs.c_str()) > base->ModificationTime(rhs.c_str());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +417,45 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
inline void ImGuiCpuProfiler::DrawFilePicker()
|
||||
{
|
||||
ImGui::SetNextWindowSize({ 500, 200 }, ImGuiCond_Once);
|
||||
if (ImGui::Begin("File Picker", &m_showFilePicker))
|
||||
{
|
||||
if (ImGui::Button("Load selected"))
|
||||
{
|
||||
LoadFile();
|
||||
}
|
||||
|
||||
auto getter = [](void* vectorPointer, int idx, const char** out_text) -> bool
|
||||
{
|
||||
const auto& pathVec = *static_cast<AZStd::vector<IO::Path>*>(vectorPointer);
|
||||
if (idx < 0 || idx >= pathVec.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*out_text = pathVec[idx].c_str();
|
||||
return true;
|
||||
};
|
||||
|
||||
ImGui::SetNextItemWidth(ImGui::GetWindowContentRegionWidth());
|
||||
ImGui::ListBox("", &m_currentFileIndex, getter, &m_cachedCapturePaths, aznumeric_cast<int>(m_cachedCapturePaths.size()));
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
inline void ImGuiCpuProfiler::LoadFile()
|
||||
{
|
||||
const IO::Path& pathToLoad = m_cachedCapturePaths[m_currentFileIndex];
|
||||
auto res = CpuProfilerImGuiHelper::LoadSavedCpuProfilingStatistics(pathToLoad.String());
|
||||
if (!res.IsSuccess())
|
||||
{
|
||||
AZ_TracePrintf("ImGuiCpuProfiler", "%s", res.GetError().c_str());
|
||||
return;
|
||||
}
|
||||
// TODO ATOM-16022 Parse this data and display it in the visualizer widget.
|
||||
}
|
||||
|
||||
// -- CPU Visualizer --
|
||||
inline void ImGuiCpuProfiler::DrawVisualizer()
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
#
|
||||
|
||||
set(LY_UNITY_BUILD OFF CACHE BOOL "UNITY builds")
|
||||
set(LY_UNITY_BUILD ON CACHE BOOL "UNITY builds")
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
include(cmake/LyAutoGen.cmake)
|
||||
|
||||
Reference in New Issue
Block a user