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.
212 lines
7.9 KiB
C++
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;
|
|
};
|
|
}
|
|
}
|