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/Code/CryEngine/RenderDll/XRenderD3D9/DX12/API/DX12CommandListFence.cpp

180 lines
6.1 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "DX12CommandListFence.hpp"
#include "DriverD3D.h"
#define TRACK_RENDERTREAD_WAIT_TIME SScopedExecutionTimeTracker renderThreadWaitTimeTracker(gcpRendD3D->m_fTimeWaitForGPU[gcpRendD3D->m_RP.m_nProcessThreadID]);
struct SScopedExecutionTimeTracker
{
SScopedExecutionTimeTracker(float& var)
: trackerVariable(var)
, startTime(iTimer->GetAsyncTime())
{}
~SScopedExecutionTimeTracker()
{
trackerVariable += iTimer->GetAsyncTime().GetDifferenceInSeconds(startTime);
}
float& trackerVariable;
CTimeValue startTime;
};
namespace DX12
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CommandListFence::CommandListFence(Device* device)
: m_pDevice(device)
, m_LastCompletedValue(0)
, m_CurrentValue(0)
{
}
//---------------------------------------------------------------------------------------------------------------------
CommandListFence::~CommandListFence()
{
m_pFence->Release();
CloseHandle(m_FenceEvent);
}
//---------------------------------------------------------------------------------------------------------------------
bool CommandListFence::Init()
{
ID3D12Fence* fence = NULL;
if (S_OK != m_pDevice->GetD3D12Device()->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(&fence)))
{
DX12_ERROR("Could not create fence object!");
return false;
}
m_pFence = fence;
m_pFence->Signal(m_LastCompletedValue);
m_FenceEvent = CreateEventEx(NULL, FALSE, FALSE, EVENT_ALL_ACCESS);
return true;
}
void CommandListFence::WaitForFence(AZ::u64 fenceValue)
{
if (!IsCompleted(fenceValue))
{
DX12_LOG("Waiting CPU for fence %d -> %d", m_pFence->GetCompletedValue(), fenceValue);
{
TRACK_RENDERTREAD_WAIT_TIME
m_pFence->SetEventOnCompletion(fenceValue, m_FenceEvent);
WaitForSingleObject(m_FenceEvent, INFINITE);
}
DX12_LOG("Completed fence value: %d", m_pFence->GetCompletedValue());
AdvanceCompletion();
}
}
//---------------------------------------------------------------------------------------------------------------------
CommandListFenceSet::CommandListFenceSet(Device* device)
: m_pDevice(device)
{
m_LastCompletedValues[CMDQUEUE_COPY ] =
m_LastCompletedValues[CMDQUEUE_GRAPHICS] = 0;
m_SubmittedValues[CMDQUEUE_COPY] =
m_SubmittedValues[CMDQUEUE_GRAPHICS] = 0;
m_CurrentValues[CMDQUEUE_COPY ] =
m_CurrentValues[CMDQUEUE_GRAPHICS] = 0;
}
//---------------------------------------------------------------------------------------------------------------------
CommandListFenceSet::~CommandListFenceSet()
{
for (int i = 0; i < CMDQUEUE_NUM; ++i)
{
m_pFences[i]->Release();
CloseHandle(m_FenceEvents[i]);
}
}
//---------------------------------------------------------------------------------------------------------------------
bool CommandListFenceSet::Init()
{
for (int i = 0; i < CMDQUEUE_NUM; ++i)
{
ID3D12Fence* fence = NULL;
if (S_OK != m_pDevice->GetD3D12Device()->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_GRAPHICS_PPV_ARGS(&fence)))
{
DX12_ERROR("Could not create fence object!");
return false;
}
m_pFences[i] = fence;
m_pFences[i]->Signal(m_LastCompletedValues[i]);
m_FenceEvents[i] = CreateEventEx(NULL, FALSE, FALSE, EVENT_ALL_ACCESS);
}
return true;
}
void CommandListFenceSet::WaitForFence(const AZ::u64 fenceValue, const int id) const
{
DX12_LOG("Waiting CPU for fence %d -> %d", m_pFences[id]->GetCompletedValue(), fenceValue);
{
TRACK_RENDERTREAD_WAIT_TIME
m_pFences[id]->SetEventOnCompletion(fenceValue, m_FenceEvents[id]);
WaitForSingleObject(m_FenceEvents[id], INFINITE);
}
DX12_LOG("Completed fence value: %d", m_pFences[id]->GetCompletedValue());
AdvanceCompletion(id);
}
void CommandListFenceSet::WaitForFence(const AZ::u64 (&fenceValues)[CMDQUEUE_NUM]) const
{
// TODO: the pool which waits for the fence can be omitted (in-order-execution)
DX12_LOG("Waiting for GPU fences [%d,%d] -> [%d,%d]",
m_pFences[CMDQUEUE_COPY ]->GetCompletedValue(),
m_pFences[CMDQUEUE_GRAPHICS]->GetCompletedValue(),
fenceValues[CMDQUEUE_COPY ],
fenceValues[CMDQUEUE_GRAPHICS]);
{
TRACK_RENDERTREAD_WAIT_TIME
// NOTE: event does ONLY trigger when the value has been set (it'll lock when trying with 0)
int numObjects = 0;
for (int id = 0; id < CMDQUEUE_NUM; ++id)
{
if (fenceValues[id] && (m_LastCompletedValues[id] < fenceValues[id]))
{
m_pFences[id]->SetEventOnCompletion(fenceValues[id], m_FenceEvents[numObjects++]);
}
}
WaitForMultipleObjects(numObjects, m_FenceEvents, true, INFINITE);
}
DX12_LOG("Completed GPU fences [%d,%d]",
m_pFences[CMDQUEUE_COPY ]->GetCompletedValue(),
m_pFences[CMDQUEUE_GRAPHICS]->GetCompletedValue());
AdvanceCompletion();
}
}