summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineD3D12/src/CommandQueueD3D12Impl.cpp
blob: 5244d4f9f6fc5c440900ae78cf65687e1e8dc999 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
 *  Copyright 2019-2021 Diligent Graphics LLC
 *  Copyright 2015-2019 Egor Yusov
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  In no event and under no legal theory, whether in tort (including negligence), 
 *  contract, or otherwise, unless required by applicable law (such as deliberate 
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental, 
 *  or consequential damages of any character arising as a result of this License or 
 *  out of the use or inability to use the software (including but not limited to damages 
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and 
 *  all other commercial damages or losses), even if such Contributor has been advised 
 *  of the possibility of such damages.
 */

#include "pch.h"
#include "CommandQueueD3D12Impl.hpp"

namespace Diligent
{

CommandQueueD3D12Impl::CommandQueueD3D12Impl(IReferenceCounters* pRefCounters,
                                             ID3D12CommandQueue* pd3d12NativeCmdQueue,
                                             ID3D12Fence*        pd3d12Fence) :
    // clang-format off
    TBase{pRefCounters},
    m_pd3d12CmdQueue       {pd3d12NativeCmdQueue},
    m_d3d12Fence           {pd3d12Fence         },
    m_NextFenceValue       {1                   },
    m_WaitForGPUEventHandle{CreateEvent(nullptr, false, false, nullptr)}
// clang-format on
{
    VERIFY_EXPR(m_WaitForGPUEventHandle != INVALID_HANDLE_VALUE);
    m_d3d12Fence->Signal(0);
}

CommandQueueD3D12Impl::~CommandQueueD3D12Impl()
{
    CloseHandle(m_WaitForGPUEventHandle);
}

Uint64 CommandQueueD3D12Impl::Submit(Uint32                    NumCommandLists,
                                     ID3D12CommandList* const* ppCommandLists)
{
    std::lock_guard<std::mutex> Lock{m_QueueMtx};

    // Increment the value before submitting the list
    auto FenceValue = m_NextFenceValue.fetch_add(1);

    // Render device submits null command list to signal the fence and
    // discard all resources.
    if (NumCommandLists != 0 && ppCommandLists != nullptr)
    {
#ifdef DILIGENT_DEBUG
        for (Uint32 i = 0; i < NumCommandLists; ++i)
        {
            VERIFY(ppCommandLists[i] != nullptr, "Command list must not be null");
        }
#endif
        m_pd3d12CmdQueue->ExecuteCommandLists(NumCommandLists, ppCommandLists);
    }

    // Signal the fence. This must be done atomically with command list submission.
    m_pd3d12CmdQueue->Signal(m_d3d12Fence, FenceValue);

    return FenceValue;
}

Uint64 CommandQueueD3D12Impl::WaitForIdle()
{
    std::lock_guard<std::mutex> Lock{m_QueueMtx};

    Uint64 LastSignaledFenceValue = m_NextFenceValue.fetch_add(1);

    m_pd3d12CmdQueue->Signal(m_d3d12Fence, LastSignaledFenceValue);

    if (GetCompletedFenceValue() < LastSignaledFenceValue)
    {
        m_d3d12Fence->SetEventOnCompletion(LastSignaledFenceValue, m_WaitForGPUEventHandle);
        WaitForSingleObject(m_WaitForGPUEventHandle, INFINITE);
        VERIFY(GetCompletedFenceValue() == LastSignaledFenceValue, "Unexpected signaled fence value");
    }
    return LastSignaledFenceValue;
}

Uint64 CommandQueueD3D12Impl::GetCompletedFenceValue()
{
    auto CompletedFenceValue = m_d3d12Fence->GetCompletedValue();
    VERIFY(CompletedFenceValue != UINT64_MAX, "If the device has been removed, the return value will be UINT64_MAX");

    auto CurrValue = m_LastCompletedFenceValue.load();
    while (!m_LastCompletedFenceValue.compare_exchange_strong(CurrValue, std::max(CurrValue, CompletedFenceValue)))
    {
        // If exchange fails, CurrValue will hold the actual value of m_LastCompletedFenceValue
    }

    return m_LastCompletedFenceValue.load();
}

void CommandQueueD3D12Impl::SignalFence(ID3D12Fence* pFence, Uint64 Value)
{
    std::lock_guard<std::mutex> Lock{m_QueueMtx};
    m_pd3d12CmdQueue->Signal(pFence, Value);
}

} // namespace Diligent