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/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp

212 lines
7.9 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "RHI/Atom_RHI_DX12_precompiled.h"
#include <Atom/RHI/CpuProfiler.h>
#include <Atom/RHI/Device.h>
#include <Atom/RHI.Reflect/CpuTimingStatistics.h>
#include <AzCore/Debug/EventTraceDrillerBus.h>
#include <RHI/CommandQueueContext.h>
#include <RHI/Device.h>
namespace AZ
{
namespace DX12
{
namespace EventTrace
{
const AZStd::thread_id GpuQueueIds[] =
{
/// Graphics
AZStd::thread_id{(size_t)2},
/// Compute
AZStd::thread_id{(size_t)3}
};
const char* GpuQueueNames[] =
{
"Graphics Queue",
"Compute Queue",
"Copy Queue"
};
}
void CommandQueueContext::Init(RHI::Device& deviceBase)
{
Device& device = static_cast<Device&>(deviceBase);
m_currentFrameIndex = 0;
m_frameFences.resize(RHI::Limits::Device::FrameCountMax - 1);
for (FenceSet& fences : m_frameFences)
{
fences.Init(device.GetDevice(), RHI::FenceState::Signaled);
}
m_compiledFences.Init(device.GetDevice(), RHI::FenceState::Reset);
for (uint32_t hardwareQueueIdx = 0; hardwareQueueIdx < RHI::HardwareQueueClassCount; ++hardwareQueueIdx)
{
m_commandQueues[hardwareQueueIdx] = CommandQueue::Create();
CommandQueueDescriptor commandQueueDesc;
commandQueueDesc.m_hardwareQueueClass = static_cast<RHI::HardwareQueueClass>(hardwareQueueIdx);
commandQueueDesc.m_hardwareQueueSubclass = HardwareQueueSubclass::Primary;
m_commandQueues[hardwareQueueIdx]->SetName(Name{ EventTrace::GpuQueueNames[hardwareQueueIdx] });
m_commandQueues[hardwareQueueIdx]->Init(device, commandQueueDesc);
}
Debug::EventTraceDrillerSetupBus::Broadcast(
&Debug::EventTraceDrillerSetupBus::Events::SetThreadName,
EventTrace::GpuQueueIds[static_cast<size_t>(RHI::HardwareQueueClass::Graphics)],
EventTrace::GpuQueueNames[static_cast<size_t>(RHI::HardwareQueueClass::Graphics)]);
Debug::EventTraceDrillerSetupBus::Broadcast(
&Debug::EventTraceDrillerSetupBus::Events::SetThreadName,
EventTrace::GpuQueueIds[static_cast<size_t>(RHI::HardwareQueueClass::Compute)],
EventTrace::GpuQueueNames[static_cast<size_t>(RHI::HardwareQueueClass::Compute)]);
CalibrateClocks();
}
void CommandQueueContext::Shutdown()
{
WaitForIdle();
m_compiledFences.Shutdown();
for (FenceSet& fenceSet : m_frameFences)
{
fenceSet.Shutdown();
}
m_frameFences.clear();
for (uint32_t hardwareQueueIdx = 0; hardwareQueueIdx < RHI::HardwareQueueClassCount; ++hardwareQueueIdx)
{
m_commandQueues[hardwareQueueIdx] = nullptr;
}
}
void CommandQueueContext::QueueGpuSignals(FenceSet& fenceSet)
{
for (uint32_t hardwareQueueIdx = 0; hardwareQueueIdx < RHI::HardwareQueueClassCount; ++hardwareQueueIdx)
{
const RHI::HardwareQueueClass hardwareQueueClass = static_cast<RHI::HardwareQueueClass>(hardwareQueueIdx);
Fence& fence = fenceSet.GetFence(hardwareQueueClass);
m_commandQueues[hardwareQueueIdx]->QueueGpuSignal(fence);
}
}
void CommandQueueContext::WaitForIdle()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
for (uint32_t hardwareQueueIdx = 0; hardwareQueueIdx < RHI::HardwareQueueClassCount; ++hardwareQueueIdx)
{
if (m_commandQueues[hardwareQueueIdx])
{
m_commandQueues[hardwareQueueIdx]->WaitForIdle();
}
}
}
void CommandQueueContext::Begin()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
{
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzRender, "Clearing Command Queue Timers");
for (const RHI::Ptr<CommandQueue>& commandQueue : m_commandQueues)
{
commandQueue->ClearTimers();
}
}
}
uint64_t CommandQueueContext::IncrementFence(RHI::HardwareQueueClass hardwareQueueClass)
{
return m_compiledFences.GetFence(hardwareQueueClass).Increment();
}
void CommandQueueContext::End()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzRender);
AZ_ATOM_PROFILE_FUNCTION("DX12", "CommandQueueContext: End");
QueueGpuSignals(m_frameFences[m_currentFrameIndex]);
for (uint32_t hardwareQueueIdx = 0; hardwareQueueIdx < RHI::HardwareQueueClassCount; ++hardwareQueueIdx)
{
m_commandQueues[hardwareQueueIdx]->FlushCommands();
}
// Advance to the next frame and wait for its resources to be available before continuing.
m_currentFrameIndex = (m_currentFrameIndex + 1) % aznumeric_cast<uint32_t>(m_frameFences.size());
{
AZ_PROFILE_SCOPE_IDLE(AZ::Debug::ProfileCategory::AzRender, "Wait and Reset Fence");
AZ_ATOM_PROFILE_TIME_GROUP_REGION("DX12", "CommandQueueContext: Wait on Fences");
FenceEvent event("FrameFence");
m_frameFences[m_currentFrameIndex].Wait(event);
m_frameFences[m_currentFrameIndex].Reset();
}
CalibrateClocks();
}
void CommandQueueContext::CalibrateClocks()
{
for (uint32_t i = 0; i < RHI::HardwareQueueClassCount; ++i)
{
m_commandQueues[i]->CalibrateClock();
}
}
void CommandQueueContext::ExecuteWork(
RHI::HardwareQueueClass hardwareQueueClass,
const ExecuteWorkRequest& request)
{
GetCommandQueue(hardwareQueueClass).ExecuteWork(request);
#if defined (AZ_DX12_FORCE_FLUSH_SCOPES)
WaitForIdle();
#endif
}
CommandQueue& CommandQueueContext::GetCommandQueue(RHI::HardwareQueueClass hardwareQueueClass)
{
return *m_commandQueues[static_cast<uint32_t>(hardwareQueueClass)];
}
const CommandQueue& CommandQueueContext::GetCommandQueue(RHI::HardwareQueueClass hardwareQueueClass) const
{
return *m_commandQueues[static_cast<uint32_t>(hardwareQueueClass)];
}
void CommandQueueContext::UpdateCpuTimingStatistics(RHI::CpuTimingStatistics& cpuTimingStatistics) const
{
cpuTimingStatistics.Reset();
AZStd::sys_time_t presentDuration = 0;
for (const RHI::Ptr<CommandQueue>& commandQueue : m_commandQueues)
{
cpuTimingStatistics.m_queueStatistics.push_back({ commandQueue->GetName(), commandQueue->GetLastExecuteDuration() });
presentDuration += commandQueue->GetLastPresentDuration();
}
cpuTimingStatistics.m_presentDuration = presentDuration;
}
const FenceSet& CommandQueueContext::GetCompiledFences()
{
return m_compiledFences;
};
}
}