Merge branch 'main' into scripting/function_node_fixes
This commit is contained in:
@@ -18,3 +18,4 @@ _savebackup/
|
||||
#Output folder for test results when running Automated Tests
|
||||
TestResults/**
|
||||
*.swatches
|
||||
/imgui.ini
|
||||
|
||||
@@ -19,9 +19,6 @@ namespace AZ
|
||||
{
|
||||
class Vector3;
|
||||
|
||||
//! Do not allow the scale to be zero to avoid problems with inverting scale.
|
||||
static constexpr float MinNonUniformScale = 1e-3f;
|
||||
|
||||
using NonUniformScaleChangedEvent = AZ::Event<const AZ::Vector3&>;
|
||||
|
||||
//! Requests for working with non-uniform scale.
|
||||
|
||||
@@ -38,6 +38,13 @@ namespace AZ
|
||||
bool CompareValueData(const void* lhs, const void* rhs) override;
|
||||
};
|
||||
|
||||
//! Limits for transform scale values.
|
||||
//! The scale should not be zero to avoid problems with inverting.
|
||||
//! @{
|
||||
static constexpr float MinTransformScale = 1e-2f;
|
||||
static constexpr float MaxTransformScale = 1e9f;
|
||||
//! @}
|
||||
|
||||
//! The basic transformation class, represented using a quaternion rotation, vector scale and vector translation.
|
||||
//! By design, cannot represent skew transformations.
|
||||
class Transform
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <AzFramework/Components/NonUniformScaleComponent.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/ToString.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
|
||||
@@ -81,13 +82,13 @@ namespace AzFramework
|
||||
|
||||
void NonUniformScaleComponent::SetScale(const AZ::Vector3& scale)
|
||||
{
|
||||
if (scale.GetMinElement() >= AZ::MinNonUniformScale)
|
||||
if (scale.GetMinElement() >= AZ::MinTransformScale && scale.GetMaxElement() <= AZ::MaxTransformScale)
|
||||
{
|
||||
m_scale = scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::Vector3 clampedScale = scale.GetMax(AZ::Vector3(AZ::MinNonUniformScale));
|
||||
AZ::Vector3 clampedScale = scale.GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale));
|
||||
AZ_Warning("Non-uniform Scale Component", false, "SetScale value was clamped from %s to %s for entity %s",
|
||||
AZ::ToString(scale).c_str(), AZ::ToString(clampedScale).c_str(), GetEntity()->GetName().c_str());
|
||||
m_scale = clampedScale;
|
||||
|
||||
@@ -256,6 +256,8 @@ namespace AzToolsFramework
|
||||
|
||||
m_userSettings = AZ::UserSettings::CreateFind<AssetEditorWidgetUserSettings>(k_assetEditorWidgetSettings, AZ::UserSettings::CT_LOCAL);
|
||||
|
||||
UpdateRecentFileListState();
|
||||
|
||||
QObject::connect(m_recentFileMenu, &QMenu::aboutToShow, this, &AssetEditorWidget::PopulateRecentMenu);
|
||||
}
|
||||
|
||||
@@ -952,7 +954,8 @@ namespace AzToolsFramework
|
||||
|
||||
void AssetEditorWidget::AddRecentPath(const AZStd::string& recentPath)
|
||||
{
|
||||
m_userSettings->AddRecentPath(recentPath);
|
||||
m_userSettings->AddRecentPath(recentPath);
|
||||
UpdateRecentFileListState();
|
||||
}
|
||||
|
||||
void AssetEditorWidget::PopulateRecentMenu()
|
||||
@@ -989,6 +992,21 @@ namespace AzToolsFramework
|
||||
m_saveAsAssetAction->setEnabled(true);
|
||||
}
|
||||
|
||||
void AssetEditorWidget::UpdateRecentFileListState()
|
||||
{
|
||||
if (m_recentFileMenu)
|
||||
{
|
||||
if (!m_userSettings || m_userSettings->m_recentPaths.empty())
|
||||
{
|
||||
m_recentFileMenu->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_recentFileMenu->setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AssetEditor
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
|
||||
@@ -122,6 +122,8 @@ namespace AzToolsFramework
|
||||
void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override;
|
||||
void OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo) override;
|
||||
|
||||
void UpdateRecentFileListState();
|
||||
|
||||
private:
|
||||
void DirtyAsset();
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace AzToolsFramework
|
||||
m_prefabUndoCache.Destroy();
|
||||
}
|
||||
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath)
|
||||
PrefabOperationResult PrefabPublicHandler::CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath)
|
||||
{
|
||||
// Retrieve entityList from entityIds
|
||||
EntityList inputEntityList;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace AzToolsFramework
|
||||
void UnregisterPrefabPublicHandlerInterface();
|
||||
|
||||
// PrefabPublicInterface...
|
||||
PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) override;
|
||||
PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) override;
|
||||
PrefabOperationResult InstantiatePrefab(AZStd::string_view filePath, AZ::EntityId parent, AZ::Vector3 position) override;
|
||||
PrefabOperationResult SavePrefab(AZ::IO::Path filePath) override;
|
||||
PrefabEntityResult CreateEntity(AZ::EntityId parentId, const AZ::Vector3& position) override;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace AzToolsFramework
|
||||
* @param filePath The path for the new prefab file.
|
||||
* @return An outcome object; on failure, it comes with an error message detailing the cause of the error.
|
||||
*/
|
||||
virtual PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZStd::string_view filePath) = 0;
|
||||
virtual PrefabOperationResult CreatePrefab(const AZStd::vector<AZ::EntityId>& entityIds, AZ::IO::PathView filePath) = 0;
|
||||
|
||||
/**
|
||||
* Instantiate a prefab from a prefab file.
|
||||
|
||||
+6
-3
@@ -13,6 +13,7 @@
|
||||
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzFramework/Components/NonUniformScaleComponent.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/ToString.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -44,7 +45,9 @@ namespace AzToolsFramework
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &EditorNonUniformScaleComponent::m_scale, "Non-uniform Scale",
|
||||
"Non-uniform scale for this entity only (does not propagate through hierarchy)")
|
||||
->Attribute(AZ::Edit::Attributes::Min, AZ::MinNonUniformScale)
|
||||
->Attribute(AZ::Edit::Attributes::Min, AZ::MinTransformScale)
|
||||
->Attribute(AZ::Edit::Attributes::Max, AZ::MaxTransformScale)
|
||||
->Attribute(AZ::Edit::Attributes::Step, 0.1f)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorNonUniformScaleComponent::OnScaleChanged)
|
||||
;
|
||||
}
|
||||
@@ -106,13 +109,13 @@ namespace AzToolsFramework
|
||||
|
||||
void EditorNonUniformScaleComponent::SetScale(const AZ::Vector3& scale)
|
||||
{
|
||||
if (scale.GetMinElement() >= AZ::MinNonUniformScale)
|
||||
if (scale.GetMinElement() >= AZ::MinTransformScale && scale.GetMaxElement() <= AZ::MaxTransformScale)
|
||||
{
|
||||
m_scale = scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ::Vector3 clampedScale = scale.GetMax(AZ::Vector3(AZ::MinNonUniformScale));
|
||||
AZ::Vector3 clampedScale = scale.GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale));
|
||||
AZ_Warning("Editor Non-uniform Scale Component", false, "SetScale value was clamped from %s to %s for entity %s",
|
||||
AZ::ToString(scale).c_str(), AZ::ToString(clampedScale).c_str(), GetEntity()->GetName().c_str());
|
||||
m_scale = clampedScale;
|
||||
|
||||
-1
@@ -1276,7 +1276,6 @@ namespace AzToolsFramework
|
||||
Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushableOnSliceRoot)->
|
||||
DataElement(TransformScaleHandler, &EditorTransform::m_scale, "Scale", "Local Scale")->
|
||||
Attribute(AZ::Edit::Attributes::Step, 0.1f)->
|
||||
Attribute(AZ::Edit::Attributes::Min, 0.01f)->
|
||||
Attribute(AZ::Edit::Attributes::ReadOnly, &EditorTransform::m_locked)
|
||||
;
|
||||
}
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "AzToolsFramework_precompiled.h"
|
||||
#include <ToolsComponents/TransformScalePropertyHandler.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -36,8 +37,8 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::PropertyEditorGUIMessages::Bus::Broadcast(&AzToolsFramework::PropertyEditorGUIMessages::RequestWrite, newCtrl);
|
||||
});
|
||||
|
||||
newCtrl->setMinimum(0.01f);
|
||||
newCtrl->setMaximum(std::numeric_limits<float>::max());
|
||||
newCtrl->setMinimum(AZ::MinTransformScale);
|
||||
newCtrl->setMaximum(AZ::MaxTransformScale);
|
||||
|
||||
return newCtrl;
|
||||
}
|
||||
|
||||
+14
-2
@@ -24,6 +24,7 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabLoaderInterface.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorLayerComponentBus.h>
|
||||
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
|
||||
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
|
||||
@@ -39,9 +40,12 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
|
||||
EditorEntityUiInterface* PrefabIntegrationManager::s_editorEntityUiInterface = nullptr;
|
||||
PrefabPublicInterface* PrefabIntegrationManager::s_prefabPublicInterface = nullptr;
|
||||
PrefabEditInterface* PrefabIntegrationManager::s_prefabEditInterface = nullptr;
|
||||
PrefabLoaderInterface* PrefabIntegrationManager::s_prefabLoaderInterface = nullptr;
|
||||
|
||||
const AZStd::string PrefabIntegrationManager::s_prefabFileExtension = ".prefab";
|
||||
|
||||
void PrefabUserSettings::Reflect(AZ::ReflectContext* context)
|
||||
@@ -79,6 +83,13 @@ namespace AzToolsFramework
|
||||
return;
|
||||
}
|
||||
|
||||
s_prefabLoaderInterface = AZ::Interface<PrefabLoaderInterface>::Get();
|
||||
if (s_prefabLoaderInterface == nullptr)
|
||||
{
|
||||
AZ_Assert(false, "Prefab - could not get PrefabLoaderInterface on PrefabIntegrationManager construction.");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorContextMenuBus::Handler::BusConnect();
|
||||
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
|
||||
AZ::Interface<PrefabIntegrationInterface>::Register(this);
|
||||
@@ -320,14 +331,15 @@ namespace AzToolsFramework
|
||||
|
||||
GenerateSuggestedFilenameFromEntities(prefabRootEntities, suggestedName);
|
||||
|
||||
if (!QueryUserForPrefabSaveLocation(suggestedName, targetDirectory, AZ_CRC("PrefabUserSettings"), activeWindow, prefabName, prefabFilePath))
|
||||
if (!QueryUserForPrefabSaveLocation(
|
||||
suggestedName, targetDirectory, AZ_CRC("PrefabUserSettings"), activeWindow, prefabName, prefabFilePath))
|
||||
{
|
||||
// User canceled prefab creation, or error prevented continuation.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->CreatePrefab(selectedEntities, prefabFilePath);
|
||||
auto createPrefabOutcome = s_prefabPublicInterface->CreatePrefab(selectedEntities, s_prefabLoaderInterface->GetRelativePathToProject(prefabFilePath.data()));
|
||||
|
||||
if (!createPrefabOutcome.IsSuccess())
|
||||
{
|
||||
|
||||
@@ -29,6 +29,9 @@ namespace AzToolsFramework
|
||||
{
|
||||
namespace Prefab
|
||||
{
|
||||
|
||||
class PrefabLoaderInterface;
|
||||
|
||||
//! Structure for saving/retrieving user settings related to prefab workflows.
|
||||
class PrefabUserSettings
|
||||
: public AZ::UserSettings
|
||||
@@ -129,6 +132,7 @@ namespace AzToolsFramework
|
||||
static EditorEntityUiInterface* s_editorEntityUiInterface;
|
||||
static PrefabPublicInterface* s_prefabPublicInterface;
|
||||
static PrefabEditInterface* s_prefabEditInterface;
|
||||
static PrefabLoaderInterface* s_prefabLoaderInterface;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1603,7 +1603,7 @@ namespace AzToolsFramework
|
||||
|
||||
const AZ::Vector3 uniformScale = AZ::Vector3(action.m_start.m_sign * sumVectorElements(action.LocalScaleOffset()));
|
||||
const AZ::Vector3 scale = (AZ::Vector3::CreateOne() +
|
||||
(uniformScale / initialScale)).GetMax(AZ::Vector3(0.01f));
|
||||
(uniformScale / initialScale)).GetClamp(AZ::Vector3(AZ::MinTransformScale), AZ::Vector3(AZ::MaxTransformScale));
|
||||
const AZ::Transform scaleTransform = AZ::Transform::CreateScale(scale);
|
||||
|
||||
if (action.m_modifiers.Alt())
|
||||
|
||||
@@ -96,6 +96,11 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(
|
||||
speedScale *= gSettings.cameraFastMoveSpeed;
|
||||
}
|
||||
|
||||
if (m_inMoveMode || m_inOrbitMode || m_inRotateMode || m_inZoomMode)
|
||||
{
|
||||
m_totalMouseMoveDelta += (QPoint(currentMousePos.m_x, currentMousePos.m_y)-QPoint(previousMousePos.m_x, previousMousePos.m_y)).manhattanLength();
|
||||
}
|
||||
|
||||
if ((m_inRotateMode && m_inMoveMode) || m_inZoomMode)
|
||||
{
|
||||
Matrix34 m = AZTransformToLYTransform(viewportContext->GetCameraTransform());
|
||||
@@ -343,11 +348,15 @@ bool LegacyViewportCameraControllerInstance::HandleInputChannelEvent(const AzFra
|
||||
}
|
||||
|
||||
shouldCaptureCursor = true;
|
||||
// Record how much the cursor has been moved to see if we should own the mouse up event.
|
||||
m_totalMouseMoveDelta = 0;
|
||||
}
|
||||
else if (state == InputChannel::State::Ended)
|
||||
{
|
||||
m_inZoomMode = false;
|
||||
m_inRotateMode = false;
|
||||
// If we've moved the cursor more than a couple pixels, we should eat this mouse up event to prevent the context menu controller from seeing it.
|
||||
shouldConsumeEvent = m_totalMouseMoveDelta > 2;
|
||||
shouldCaptureCursor = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace SandboxEditor
|
||||
bool m_inMoveMode = false;
|
||||
bool m_inOrbitMode = false;
|
||||
bool m_inZoomMode = false;
|
||||
int m_totalMouseMoveDelta = 0;
|
||||
float m_orbitDistance = 10.f;
|
||||
float m_moveSpeed = 1.f;
|
||||
AZ::Vector3 m_orbitTarget = {};
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace AZ
|
||||
{
|
||||
for (const RPI::Pass* pass : passes)
|
||||
{
|
||||
m_timestampEntries.push_back({ pass->GetName(), pass->GetTimestampResult().GetTimestampInNanoseconds() });
|
||||
m_timestampEntries.push_back({pass->GetName(), pass->GetLatestTimestampResult().GetDurationInNanoseconds()});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace AZ
|
||||
{
|
||||
for (const RPI::Pass* pass : passes)
|
||||
{
|
||||
m_pipelineStatisticsEntries.push_back({ pass->GetName(), pass->GetPipelineStatisticsResult() });
|
||||
m_pipelineStatisticsEntries.push_back({pass->GetName(), pass->GetLatestPipelineStatisticsResult()});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Atom/RHI.Reflect/AttachmentEnums.h>
|
||||
#include <Atom/RHI.Reflect/QueryPoolDescriptor.h>
|
||||
|
||||
#include <AtomCore/std/containers/array_view.h>
|
||||
@@ -43,15 +44,19 @@ namespace AZ
|
||||
{
|
||||
public:
|
||||
TimestampResult() = default;
|
||||
TimestampResult(uint64_t timestampInTicks);
|
||||
TimestampResult(uint64_t timestampQueryResultLow, uint64_t timestampQueryResultHigh);
|
||||
TimestampResult(AZStd::array_view<TimestampResult>&& timestampResultArray);
|
||||
TimestampResult(uint64_t beginTick, uint64_t endTick, RHI::HardwareQueueClass hardwareQueueClass);
|
||||
|
||||
uint64_t GetTimestampInNanoseconds() const;
|
||||
uint64_t GetTimestampInTicks() const;
|
||||
uint64_t GetDurationInNanoseconds() const;
|
||||
uint64_t GetDurationInTicks() const;
|
||||
uint64_t GetTimestampBeginInTicks() const;
|
||||
|
||||
void Add(const TimestampResult& extent);
|
||||
|
||||
private:
|
||||
uint64_t m_timestampInTicks = 0u;
|
||||
// the timestamp of begin and duration in ticks.
|
||||
uint64_t m_begin = 0;
|
||||
uint64_t m_duration = 0;
|
||||
RHI::HardwareQueueClass m_hardwareQueueClass = RHI::HardwareQueueClass::Graphics;
|
||||
};
|
||||
|
||||
//! The structure that is used to read back the results form the PipelineStatistics queries
|
||||
|
||||
@@ -122,7 +122,6 @@ namespace AZ
|
||||
|
||||
private:
|
||||
// RPI::Pass overrides...
|
||||
TimestampResult GetTimestampResultInternal() const override;
|
||||
PipelineStatisticsResult GetPipelineStatisticsResultInternal() const override;
|
||||
|
||||
// --- Hierarchy related functions ---
|
||||
|
||||
@@ -211,11 +211,11 @@ namespace AZ
|
||||
//! Prints the pass
|
||||
virtual void DebugPrint() const;
|
||||
|
||||
//! Return the Timestamp result of this pass
|
||||
TimestampResult GetTimestampResult() const;
|
||||
//! Return the latest Timestamp result of this pass
|
||||
TimestampResult GetLatestTimestampResult() const;
|
||||
|
||||
//! Return the PipelineStatistic result of this pass
|
||||
PipelineStatisticsResult GetPipelineStatisticsResult() const;
|
||||
//! Return the latest PipelineStatistic result of this pass
|
||||
PipelineStatisticsResult GetLatestPipelineStatisticsResult() const;
|
||||
|
||||
//! Enables/Disables Timestamp queries for this pass
|
||||
virtual void SetTimestampQueryEnabled(bool enable);
|
||||
|
||||
@@ -100,12 +100,12 @@ namespace AZ
|
||||
bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Write;
|
||||
break;
|
||||
case CommonBufferPoolType::StaticInputAssembly:
|
||||
bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
|
||||
bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::InputAssembly | RHI::BufferBindFlags::ShaderRead;
|
||||
bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
|
||||
bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Write;
|
||||
break;
|
||||
case CommonBufferPoolType::DynamicInputAssembly:
|
||||
bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::DynamicInputAssembly;
|
||||
bufferPoolDesc.m_bindFlags = RHI::BufferBindFlags::DynamicInputAssembly | RHI::BufferBindFlags::ShaderRead;
|
||||
bufferPoolDesc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Host;
|
||||
bufferPoolDesc.m_hostMemoryAccess = RHI::HostMemoryAccess::Write;
|
||||
break;
|
||||
|
||||
@@ -21,41 +21,39 @@ namespace AZ
|
||||
namespace RPI
|
||||
{
|
||||
// --- TimestampResult ---
|
||||
|
||||
TimestampResult::TimestampResult(uint64_t timestampInTicks)
|
||||
TimestampResult::TimestampResult(uint64_t beginTick, uint64_t endTick, RHI::HardwareQueueClass hardwareQueueClass)
|
||||
{
|
||||
m_timestampInTicks = timestampInTicks;
|
||||
AZ_Assert(endTick >= beginTick, "TimestampResult: bad inputs");
|
||||
m_begin = beginTick;
|
||||
m_duration = endTick - beginTick;
|
||||
m_hardwareQueueClass = hardwareQueueClass;
|
||||
}
|
||||
|
||||
TimestampResult::TimestampResult(uint64_t timestampQueryResultLow, uint64_t timestampQueryResultHigh)
|
||||
{
|
||||
const uint64_t low = AZStd::min(timestampQueryResultLow, timestampQueryResultHigh);
|
||||
const uint64_t high = AZStd::max(timestampQueryResultLow, timestampQueryResultHigh);
|
||||
|
||||
m_timestampInTicks = high - low;
|
||||
}
|
||||
|
||||
TimestampResult::TimestampResult(AZStd::array_view<TimestampResult>&& timestampResultArray)
|
||||
{
|
||||
// Loop through all the child passes, and accumulate all the timestampTicks
|
||||
for (const TimestampResult& timestampResult : timestampResultArray)
|
||||
{
|
||||
m_timestampInTicks += timestampResult.m_timestampInTicks;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t TimestampResult::GetTimestampInNanoseconds() const
|
||||
uint64_t TimestampResult::GetDurationInNanoseconds() const
|
||||
{
|
||||
const RHI::Ptr<RHI::Device> device = RHI::GetRHIDevice();
|
||||
const AZStd::chrono::microseconds timeInMicroseconds = device->GpuTimestampToMicroseconds(m_timestampInTicks, RHI::HardwareQueueClass::Graphics);
|
||||
const AZStd::chrono::microseconds timeInMicroseconds = device->GpuTimestampToMicroseconds(m_duration, m_hardwareQueueClass);
|
||||
const auto timeInNanoseconds = AZStd::chrono::nanoseconds(timeInMicroseconds);
|
||||
|
||||
return static_cast<uint64_t>(timeInNanoseconds.count());
|
||||
}
|
||||
|
||||
uint64_t TimestampResult::GetTimestampInTicks() const
|
||||
uint64_t TimestampResult::GetDurationInTicks() const
|
||||
{
|
||||
return m_timestampInTicks;
|
||||
return m_duration;
|
||||
}
|
||||
|
||||
uint64_t TimestampResult::GetTimestampBeginInTicks() const
|
||||
{
|
||||
return m_begin;
|
||||
}
|
||||
|
||||
void TimestampResult::Add(const TimestampResult& extent)
|
||||
{
|
||||
uint64_t end1 = m_begin + m_duration;
|
||||
uint64_t end2 = extent.m_begin + extent.m_duration;
|
||||
m_begin = m_begin < extent.m_begin ? m_begin : extent.m_begin;
|
||||
m_duration = (end1 > end2 ? end1 : end2) - m_begin;
|
||||
}
|
||||
|
||||
// --- PipelineStatisticsResult ---
|
||||
|
||||
@@ -393,19 +393,6 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
TimestampResult ParentPass::GetTimestampResultInternal() const
|
||||
{
|
||||
AZStd::vector<TimestampResult> timestampResultArray;
|
||||
timestampResultArray.reserve(m_children.size());
|
||||
|
||||
// Calculate the Timestamp result by summing all of its child's TimestampResults
|
||||
for (const Ptr<Pass>& childPass : m_children)
|
||||
{
|
||||
timestampResultArray.emplace_back(childPass->GetTimestampResult());
|
||||
}
|
||||
return TimestampResult(timestampResultArray);
|
||||
}
|
||||
|
||||
PipelineStatisticsResult ParentPass::GetPipelineStatisticsResultInternal() const
|
||||
{
|
||||
AZStd::vector<PipelineStatisticsResult> pipelineStatisticsResultArray;
|
||||
@@ -414,7 +401,7 @@ namespace AZ
|
||||
// Calculate the PipelineStatistics result by summing all of its child's PipelineStatistics
|
||||
for (const Ptr<Pass>& childPass : m_children)
|
||||
{
|
||||
pipelineStatisticsResultArray.emplace_back(childPass->GetPipelineStatisticsResult());
|
||||
pipelineStatisticsResultArray.emplace_back(childPass->GetLatestPipelineStatisticsResult());
|
||||
}
|
||||
return PipelineStatisticsResult(pipelineStatisticsResultArray);
|
||||
}
|
||||
|
||||
@@ -1273,24 +1273,14 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
TimestampResult Pass::GetTimestampResult() const
|
||||
TimestampResult Pass::GetLatestTimestampResult() const
|
||||
{
|
||||
if (IsEnabled() && IsTimestampQueryEnabled())
|
||||
{
|
||||
return GetTimestampResultInternal();
|
||||
}
|
||||
|
||||
return TimestampResult();
|
||||
return GetTimestampResultInternal();
|
||||
}
|
||||
|
||||
PipelineStatisticsResult Pass::GetPipelineStatisticsResult() const
|
||||
PipelineStatisticsResult Pass::GetLatestPipelineStatisticsResult() const
|
||||
{
|
||||
if (IsEnabled() && IsPipelineStatisticsQueryEnabled())
|
||||
{
|
||||
return GetPipelineStatisticsResultInternal();
|
||||
}
|
||||
|
||||
return PipelineStatisticsResult();
|
||||
return GetPipelineStatisticsResultInternal();
|
||||
}
|
||||
|
||||
TimestampResult Pass::GetTimestampResultInternal() const
|
||||
|
||||
@@ -539,7 +539,7 @@ namespace AZ
|
||||
const uint32_t TimestampResultQueryCount = 2u;
|
||||
uint64_t timestampResult[TimestampResultQueryCount] = {0};
|
||||
query->GetLatestResult(×tampResult, sizeof(uint64_t) * TimestampResultQueryCount);
|
||||
m_timestampResult = TimestampResult(timestampResult[0], timestampResult[1]);
|
||||
m_timestampResult = TimestampResult(timestampResult[0], timestampResult[1], RHI::HardwareQueueClass::Graphics);
|
||||
});
|
||||
|
||||
ExecuteOnPipelineStatisticsQuery([this](RHI::Ptr<Query> query)
|
||||
|
||||
@@ -109,8 +109,8 @@ namespace MaterialEditor
|
||||
AZ::RHI::Ptr<AZ::RPI::ParentPass> rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass();
|
||||
if (rootPass)
|
||||
{
|
||||
AZ::RPI::TimestampResult timestampResult = rootPass->GetTimestampResult();
|
||||
double gpuFrameTimeMs = aznumeric_cast<double>(timestampResult.GetTimestampInNanoseconds()) / 1000000;
|
||||
AZ::RPI::TimestampResult timestampResult = rootPass->GetLatestTimestampResult();
|
||||
double gpuFrameTimeMs = aznumeric_cast<double>(timestampResult.GetDurationInNanoseconds()) / 1000000;
|
||||
m_gpuFrameTimeMs.PushSample(gpuFrameTimeMs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,9 @@ namespace AZ
|
||||
ImGuiPipelineStatisticsView();
|
||||
|
||||
//! Draw the PipelineStatistics window.
|
||||
void DrawPipelineStatisticsWindow(bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<AZ::Name, PassEntry>& m_timestampEntryDatabase);
|
||||
void DrawPipelineStatisticsWindow(bool& draw, const PassEntry* rootPassEntry,
|
||||
AZStd::unordered_map<AZ::Name, PassEntry>& m_timestampEntryDatabase,
|
||||
AZ::RHI::Ptr<AZ::RPI::ParentPass> rootPass);
|
||||
|
||||
//! Total number of columns (Attribute columns + PassName column).
|
||||
static const uint32_t HeaderAttributeCount = PassEntry::PipelineStatisticsAttributeCount + 1u;
|
||||
@@ -139,6 +141,9 @@ namespace AZ
|
||||
|
||||
// ImGui filter used to filter passes by the user's input.
|
||||
ImGuiTextFilter m_passFilter;
|
||||
|
||||
// Pause and showing the pipeline statistics result when it's paused.
|
||||
bool m_paused = false;
|
||||
};
|
||||
|
||||
class ImGuiTimestampView
|
||||
@@ -180,9 +185,19 @@ namespace AZ
|
||||
Count
|
||||
};
|
||||
|
||||
// Timestamp refresh type .
|
||||
enum class RefreshType : int32_t
|
||||
{
|
||||
Realtime = 0,
|
||||
OncePerSecond,
|
||||
Count
|
||||
};
|
||||
|
||||
public:
|
||||
//! Draw the Timestamp window.
|
||||
void DrawTimestampWindow(bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& m_timestampEntryDatabase);
|
||||
void DrawTimestampWindow(bool& draw, const PassEntry* rootPassEntry,
|
||||
AZStd::unordered_map<Name, PassEntry>& m_timestampEntryDatabase,
|
||||
AZ::RHI::Ptr<AZ::RPI::ParentPass> rootPass);
|
||||
|
||||
private:
|
||||
// Draw option for the hierarchical view of the passes.
|
||||
@@ -223,6 +238,20 @@ namespace AZ
|
||||
|
||||
// ImGui filter used to filter passes.
|
||||
ImGuiTextFilter m_passFilter;
|
||||
|
||||
// Pause and showing the timestamp result when it's paused.
|
||||
bool m_paused = false;
|
||||
|
||||
// Hide non-parent passes which has 0 execution time.
|
||||
bool m_hideZeroPasses = false;
|
||||
|
||||
// Show pass execution timeline
|
||||
bool m_showTimeline = false;
|
||||
|
||||
// Controls how often the timestamp data is refreshed
|
||||
RefreshType m_refreshType = RefreshType::OncePerSecond;
|
||||
AZStd::sys_time_t m_lastUpdateTimeMicroSecond;
|
||||
|
||||
};
|
||||
|
||||
class ImGuiGpuProfiler
|
||||
|
||||
@@ -105,9 +105,9 @@ namespace AZ
|
||||
|
||||
// [GFX TODO][ATOM-4001] Cache the timestamp and PipelineStatistics results.
|
||||
// Get the query results from the passes.
|
||||
m_timestampResult = pass->GetTimestampResult();
|
||||
m_timestampResult = pass->GetLatestTimestampResult();
|
||||
|
||||
const RPI::PipelineStatisticsResult rps = pass->GetPipelineStatisticsResult();
|
||||
const RPI::PipelineStatisticsResult rps = pass->GetLatestPipelineStatisticsResult();
|
||||
m_pipelineStatistics = { rps.m_vertexCount, rps.m_primitiveCount, rps.m_vertexShaderInvocationCount,
|
||||
rps.m_rasterizedPrimitiveCount, rps.m_renderedPrimitiveCount, rps.m_pixelShaderInvocationCount, rps.m_computeShaderInvocationCount };
|
||||
|
||||
@@ -153,7 +153,9 @@ namespace AZ
|
||||
|
||||
}
|
||||
|
||||
inline void ImGuiPipelineStatisticsView::DrawPipelineStatisticsWindow(bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& passEntryDatabase)
|
||||
inline void ImGuiPipelineStatisticsView::DrawPipelineStatisticsWindow(bool& draw,
|
||||
const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& passEntryDatabase,
|
||||
AZ::RHI::Ptr<RPI::ParentPass> rootPass)
|
||||
{
|
||||
// Early out if nothing is supposed to be drawn
|
||||
if (!draw)
|
||||
@@ -188,12 +190,6 @@ namespace AZ
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter out disabled passes for the PipelineStatistics window if necessary.
|
||||
if (!m_showDisabledPasses && !passEntry.IsPipelineStatisticsEnabled())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter out parent passes if necessary.
|
||||
if (!m_showParentPasses && passEntry.m_isParent)
|
||||
{
|
||||
@@ -230,6 +226,13 @@ namespace AZ
|
||||
// Start drawing the PipelineStatistics window.
|
||||
if (ImGui::Begin("PipelineStatistics Window", &draw, ImGuiWindowFlags_NoResize))
|
||||
{
|
||||
// Pause/unpause the profiling
|
||||
if (ImGui::Button(m_paused ? "Resume" : "Pause"))
|
||||
{
|
||||
m_paused = !m_paused;
|
||||
rootPass->SetPipelineStatisticsQueryEnabled(!m_paused);
|
||||
}
|
||||
|
||||
ImGui::Columns(2, "HeaderColumns");
|
||||
|
||||
// Draw the statistics of the RootPass.
|
||||
@@ -426,23 +429,16 @@ namespace AZ
|
||||
}
|
||||
|
||||
AZStd::string label;
|
||||
if (passEntry->IsPipelineStatisticsEnabled())
|
||||
if (rootEntry && m_showAttributeContribution)
|
||||
{
|
||||
if (rootEntry && m_showAttributeContribution)
|
||||
{
|
||||
label = AZStd::string::format("%llu (%u%%)",
|
||||
static_cast<AZ::u64>(passEntry->m_pipelineStatistics[attributeIdx]),
|
||||
static_cast<uint32_t>(normalized * 100.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
label = AZStd::string::format("%llu",
|
||||
static_cast<AZ::u64>(passEntry->m_pipelineStatistics[attributeIdx]));
|
||||
}
|
||||
label = AZStd::string::format("%llu (%u%%)",
|
||||
static_cast<AZ::u64>(passEntry->m_pipelineStatistics[attributeIdx]),
|
||||
static_cast<uint32_t>(normalized * 100.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
label = "-";
|
||||
label = AZStd::string::format("%llu",
|
||||
static_cast<AZ::u64>(passEntry->m_pipelineStatistics[attributeIdx]));
|
||||
}
|
||||
|
||||
if (rootEntry)
|
||||
@@ -523,7 +519,9 @@ namespace AZ
|
||||
|
||||
// --- ImGuiTimestampView ---
|
||||
|
||||
inline void ImGuiTimestampView::DrawTimestampWindow(bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& timestampEntryDatabase)
|
||||
inline void ImGuiTimestampView::DrawTimestampWindow(
|
||||
bool& draw, const PassEntry* rootPassEntry, AZStd::unordered_map<Name, PassEntry>& timestampEntryDatabase,
|
||||
AZ::RHI::Ptr<RPI::ParentPass> rootPass)
|
||||
{
|
||||
// Early out if nothing is supposed to be drawn
|
||||
if (!draw)
|
||||
@@ -534,10 +532,28 @@ namespace AZ
|
||||
// Clear the references from the previous frame.
|
||||
m_passEntryReferences.clear();
|
||||
|
||||
// pass entry grid based on its timestamp
|
||||
AZStd::vector<PassEntry*> sortedPassEntries;
|
||||
AZStd::vector<AZStd::vector<PassEntry*>> sortedPassGrid;
|
||||
|
||||
// Set the child of the parent, only if it passes the filter.
|
||||
for (auto& passEntryIt : timestampEntryDatabase)
|
||||
{
|
||||
PassEntry* passEntry = &passEntryIt.second;
|
||||
|
||||
// Collect all pass entries with non-zero durations
|
||||
if (passEntry->m_timestampResult.GetDurationInTicks() > 0)
|
||||
{
|
||||
sortedPassEntries.push_back(passEntry);
|
||||
}
|
||||
|
||||
// Skip the pass if the pass' timestamp duration is 0
|
||||
if (m_hideZeroPasses && (!passEntry->m_isParent) && passEntry->m_timestampResult.GetDurationInTicks() == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only add pass if it pass the filter.
|
||||
if (m_passFilter.PassFilter(passEntry->m_name.GetCStr()))
|
||||
{
|
||||
if (passEntry->m_parent && !passEntry->m_linked)
|
||||
@@ -545,19 +561,94 @@ namespace AZ
|
||||
passEntry->m_parent->LinkChild(passEntry);
|
||||
}
|
||||
|
||||
AZ_Assert(m_passEntryReferences.size() < TimestampEntryCount, "Too many PassEntry references. Increase the size of the array.");
|
||||
AZ_Assert(
|
||||
m_passEntryReferences.size() < TimestampEntryCount,
|
||||
"Too many PassEntry references. Increase the size of the array.");
|
||||
m_passEntryReferences.push_back(passEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the pass entries based on their starting time and duration
|
||||
AZStd::sort(sortedPassEntries.begin(), sortedPassEntries.end(), [](const PassEntry* passEntry1, const PassEntry* passEntry2) {
|
||||
if (passEntry1->m_timestampResult.GetTimestampBeginInTicks() == passEntry2->m_timestampResult.GetTimestampBeginInTicks())
|
||||
{
|
||||
return passEntry1->m_timestampResult.GetDurationInTicks() < passEntry2->m_timestampResult.GetDurationInTicks();
|
||||
}
|
||||
return passEntry1->m_timestampResult.GetTimestampBeginInTicks() < passEntry2->m_timestampResult.GetTimestampBeginInTicks();
|
||||
});
|
||||
|
||||
// calculate the total GPU duration.
|
||||
RPI::TimestampResult gpuTimestamp;
|
||||
if (sortedPassEntries.size() > 0)
|
||||
{
|
||||
gpuTimestamp = sortedPassEntries.front()->m_timestampResult;
|
||||
gpuTimestamp.Add(sortedPassEntries.back()->m_timestampResult);
|
||||
}
|
||||
|
||||
// Add a pass to the pass grid which none of the pass's timestamp range won't overlap each other.
|
||||
// Search each row until the pass can be added to the end of row without overlap the previous one.
|
||||
for (auto& passEntry : sortedPassEntries)
|
||||
{
|
||||
auto row = sortedPassGrid.begin();
|
||||
for (; row != sortedPassGrid.end(); row++)
|
||||
{
|
||||
if (row->empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
auto last = (*row).back();
|
||||
if (passEntry->m_timestampResult.GetTimestampBeginInTicks() >=
|
||||
last->m_timestampResult.GetTimestampBeginInTicks() + last->m_timestampResult.GetDurationInTicks())
|
||||
{
|
||||
row->push_back(passEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (row == sortedPassGrid.end())
|
||||
{
|
||||
sortedPassGrid.push_back();
|
||||
sortedPassGrid.back().push_back(passEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh timestamp query
|
||||
bool needEnable = false;
|
||||
if (!m_paused)
|
||||
{
|
||||
if (m_refreshType == RefreshType::OncePerSecond)
|
||||
{
|
||||
auto now = AZStd::GetTimeNowMicroSecond();
|
||||
if (m_lastUpdateTimeMicroSecond == 0 || now - m_lastUpdateTimeMicroSecond > 1000000)
|
||||
{
|
||||
needEnable = true;
|
||||
m_lastUpdateTimeMicroSecond = now;
|
||||
}
|
||||
}
|
||||
else if (m_refreshType == RefreshType::Realtime)
|
||||
{
|
||||
needEnable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (rootPass->IsTimestampQueryEnabled() != needEnable)
|
||||
{
|
||||
rootPass->SetTimestampQueryEnabled(needEnable);
|
||||
}
|
||||
|
||||
const ImVec2 windowSize(680.0f, 620.0f);
|
||||
ImGui::SetNextWindowSize(windowSize, ImGuiCond_Always);
|
||||
if (ImGui::Begin("Timestamp View", &draw, ImGuiWindowFlags_NoResize))
|
||||
{
|
||||
// Draw the header.
|
||||
{
|
||||
// Pause/unpause the profiling
|
||||
if (ImGui::Button(m_paused? "Resume":"Pause"))
|
||||
{
|
||||
m_paused = !m_paused;
|
||||
}
|
||||
|
||||
// Draw the frame time (GPU).
|
||||
const AZStd::string formattedTimestamp = FormatTimestampLabel(rootPassEntry->m_interpolatedTimestampInNanoseconds);
|
||||
const AZStd::string formattedTimestamp = FormatTimestampLabel(gpuTimestamp.GetDurationInNanoseconds());
|
||||
const AZStd::string headerFrameTime = AZStd::string::format("Total frame duration (GPU): %s", formattedTimestamp.c_str());
|
||||
ImGui::Text(headerFrameTime.c_str());
|
||||
|
||||
@@ -566,6 +657,17 @@ namespace AZ
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Flat", reinterpret_cast<int32_t*>(&m_viewType), static_cast<int32_t>(ProfilerViewType::Flat));
|
||||
|
||||
// Draw the refresh option
|
||||
ImGui::RadioButton("Realtime", reinterpret_cast<int32_t*>(&m_refreshType), static_cast<int32_t>(RefreshType::Realtime));
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Once Per Second", reinterpret_cast<int32_t*>(&m_refreshType), static_cast<int32_t>(RefreshType::OncePerSecond));
|
||||
|
||||
// Show/hide non-parent passes which have zero execution time
|
||||
ImGui::Checkbox("Hide Zero Cost Passes", &m_hideZeroPasses);
|
||||
|
||||
// Show/hide the timeline bar of all the passes which has non-zero execution time
|
||||
ImGui::Checkbox("Show Timeline", &m_showTimeline);
|
||||
|
||||
// Draw advanced options.
|
||||
const ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_None;
|
||||
GpuProfilerImGuiHelper::TreeNode("Advanced options", flags, [this](bool unrolled)
|
||||
@@ -587,6 +689,56 @@ namespace AZ
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Draw the pass entry grid
|
||||
if (!sortedPassEntries.empty() && m_showTimeline)
|
||||
{
|
||||
const float passBarHeight = 20.f;
|
||||
const float passBarSpace = 3.f;
|
||||
float areaWidth = ImGui::GetContentRegionAvail().x - 20.f;
|
||||
|
||||
if (ImGui::BeginChild("Timeline", ImVec2(areaWidth, (passBarHeight + passBarSpace) * sortedPassGrid.size()), false))
|
||||
{
|
||||
// start tick and end tick for the area
|
||||
uint64_t areaStartTick = sortedPassEntries.front()->m_timestampResult.GetTimestampBeginInTicks();
|
||||
uint64_t areaEndTick = sortedPassEntries.back()->m_timestampResult.GetTimestampBeginInTicks() +
|
||||
sortedPassEntries.back()->m_timestampResult.GetDurationInTicks();
|
||||
uint64_t areaDurationInTicks = areaEndTick - areaStartTick;
|
||||
|
||||
float rowStartY = 0.f;
|
||||
for (auto& row : sortedPassGrid)
|
||||
{
|
||||
// row start y
|
||||
for (auto passEntry : row)
|
||||
{
|
||||
// button start and end
|
||||
float buttonStartX = (passEntry->m_timestampResult.GetTimestampBeginInTicks() - areaStartTick) * areaWidth /
|
||||
areaDurationInTicks;
|
||||
float buttonWidth = passEntry->m_timestampResult.GetDurationInTicks() * areaWidth / areaDurationInTicks;
|
||||
ImGui::SetCursorPosX(buttonStartX);
|
||||
ImGui::SetCursorPosY(rowStartY);
|
||||
|
||||
// Adds a button and the hover colors.
|
||||
ImGui::Button(passEntry->m_name.GetCStr(), ImVec2(buttonWidth, passBarHeight));
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("Name: %s", passEntry->m_name.GetCStr());
|
||||
ImGui::Text("Path: %s", passEntry->m_path.GetCStr());
|
||||
ImGui::Text("Duration in ticks: %lu", passEntry->m_timestampResult.GetDurationInTicks());
|
||||
ImGui::Text("Duration in microsecond: %.3f us", passEntry->m_timestampResult.GetDurationInNanoseconds()/1000.f);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
rowStartY += passBarHeight + passBarSpace;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
// Draw the timestamp view.
|
||||
{
|
||||
static const AZStd::array<const char*, static_cast<int32_t>(TimestampMetricUnit::Count)> MetricUnitText =
|
||||
@@ -713,20 +865,18 @@ namespace AZ
|
||||
const auto drawWorkloadBar = [this](const AZStd::string& entryTime, const PassEntry* entry)
|
||||
{
|
||||
ImGui::NextColumn();
|
||||
ImGui::Text(entryTime.c_str());
|
||||
ImGui::NextColumn();
|
||||
|
||||
// Only draw the workload bar when the entry is enabled.
|
||||
if (entry->IsTimestampEnabled())
|
||||
if (entry->m_isParent)
|
||||
{
|
||||
DrawFrameWorkloadBar(NormalizeFrameWorkload(entry->m_interpolatedTimestampInNanoseconds));
|
||||
ImGui::NextColumn();
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::ProgressBar(0.0f, ImVec2(-1.0f, 0.0f), "Disabled");
|
||||
ImGui::Text(entryTime.c_str());
|
||||
ImGui::NextColumn();
|
||||
DrawFrameWorkloadBar(NormalizeFrameWorkload(entry->m_interpolatedTimestampInNanoseconds));
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
|
||||
ImGui::NextColumn();
|
||||
};
|
||||
|
||||
static const auto createHoverMarker = [](const char* text)
|
||||
@@ -800,23 +950,17 @@ namespace AZ
|
||||
// Draw the flat view.
|
||||
for (const PassEntry* entry : m_passEntryReferences)
|
||||
{
|
||||
if (entry->m_isParent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const AZStd::string entryTime = FormatTimestampLabel(entry->m_interpolatedTimestampInNanoseconds);
|
||||
|
||||
ImGui::Text(entry->m_name.GetCStr());
|
||||
ImGui::NextColumn();
|
||||
ImGui::Text(entryTime.c_str());
|
||||
ImGui::NextColumn();
|
||||
|
||||
// Only draw the workload bar if the entry is enabled.
|
||||
if (entry->IsTimestampEnabled())
|
||||
{
|
||||
DrawFrameWorkloadBar(NormalizeFrameWorkload(entry->m_interpolatedTimestampInNanoseconds));
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::ProgressBar(0.0f, ImVec2(-1.0f, 0.0f), "Disabled");
|
||||
}
|
||||
|
||||
DrawFrameWorkloadBar(NormalizeFrameWorkload(entry->m_interpolatedTimestampInNanoseconds));
|
||||
ImGui::NextColumn();
|
||||
}
|
||||
}
|
||||
@@ -890,23 +1034,33 @@ namespace AZ
|
||||
// Update the PassEntry database.
|
||||
const PassEntry* rootPassEntryRef = CreatePassEntries(rootPass);
|
||||
|
||||
bool wasDraw = draw;
|
||||
|
||||
GpuProfilerImGuiHelper::Begin("Gpu Profiler", &draw, ImGuiWindowFlags_NoResize, [this, &rootPass]()
|
||||
{
|
||||
ImGui::Checkbox("Enable TimestampView", &m_drawTimestampView);
|
||||
if (ImGui::Checkbox("Enable TimestampView", &m_drawTimestampView))
|
||||
{
|
||||
rootPass->SetTimestampQueryEnabled(m_drawTimestampView);
|
||||
}
|
||||
ImGui::Spacing();
|
||||
ImGui::Checkbox("Enable PipelineStatisticsView", &m_drawPipelineStatisticsView);
|
||||
if(ImGui::Checkbox("Enable PipelineStatisticsView", &m_drawPipelineStatisticsView))
|
||||
{
|
||||
rootPass->SetPipelineStatisticsQueryEnabled(m_drawPipelineStatisticsView);
|
||||
}
|
||||
});
|
||||
|
||||
// Draw the PipelineStatistics window.
|
||||
m_timestampView.DrawTimestampWindow(m_drawTimestampView, rootPassEntryRef, m_passEntryDatabase);
|
||||
m_timestampView.DrawTimestampWindow(m_drawTimestampView, rootPassEntryRef, m_passEntryDatabase, rootPass);
|
||||
|
||||
// Draw the PipelineStatistics window.
|
||||
m_pipelineStatisticsView.DrawPipelineStatisticsWindow(m_drawPipelineStatisticsView, rootPassEntryRef, m_passEntryDatabase);
|
||||
m_pipelineStatisticsView.DrawPipelineStatisticsWindow(m_drawPipelineStatisticsView, rootPassEntryRef, m_passEntryDatabase, rootPass);
|
||||
|
||||
// [GFX TODO][ATOM-13792] Optimization: ImGui GpuProfiler Pass hierarchy traversal.
|
||||
// Enable/Disable the Timestamp and PipelineStatistics on the RootPass
|
||||
rootPass->SetTimestampQueryEnabled(draw && m_drawTimestampView);
|
||||
rootPass->SetPipelineStatisticsQueryEnabled(draw && m_drawPipelineStatisticsView);
|
||||
//closing window
|
||||
if (wasDraw && !draw)
|
||||
{
|
||||
rootPass->SetTimestampQueryEnabled(false);
|
||||
rootPass->SetPipelineStatisticsQueryEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
inline void ImGuiGpuProfiler::InterpolatePassEntries(AZStd::unordered_map<Name, PassEntry>& passEntryDatabase, float weight) const
|
||||
@@ -918,7 +1072,7 @@ namespace AZ
|
||||
{
|
||||
// Interpolate the timestamps.
|
||||
const double interpolated = Lerp(static_cast<double>(oldEntryIt->second.m_interpolatedTimestampInNanoseconds),
|
||||
static_cast<double>(entry.second.m_timestampResult.GetTimestampInNanoseconds()),
|
||||
static_cast<double>(entry.second.m_timestampResult.GetDurationInNanoseconds()),
|
||||
static_cast<double>(weight));
|
||||
entry.second.m_interpolatedTimestampInNanoseconds = static_cast<uint64_t>(interpolated);
|
||||
}
|
||||
|
||||
@@ -222,6 +222,10 @@ void ImGuiManager::Initialize()
|
||||
io.DisplaySize.x = 1920;
|
||||
io.DisplaySize.y = 1080;
|
||||
|
||||
// Create a default font
|
||||
io.Fonts->AddFontDefault();
|
||||
io.Fonts->Build();
|
||||
|
||||
// Broadcast ImGui Ready to Listeners
|
||||
ImGuiUpdateListenerBus::Broadcast(&IImGuiUpdateListener::OnImGuiInitialize);
|
||||
m_currentControllerIndex = -1;
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace WhiteBox
|
||||
|
||||
// specify the data format for vertex stream data
|
||||
AZ::RHI::BufferDescriptor bufferDescriptor;
|
||||
bufferDescriptor.m_bindFlags = AZ::RHI::BufferBindFlags::InputAssembly;
|
||||
bufferDescriptor.m_bindFlags = AZ::RHI::BufferBindFlags::InputAssembly | AZ::RHI::BufferBindFlags::ShaderRead;
|
||||
bufferDescriptor.m_byteCount = bufferSize;
|
||||
bufferDescriptor.m_alignment = elementSize;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user