core: Define VK_USE_PLATFORM_XCB_KHR before including vkd3d_utils.h.
[vkmodelviewer.git] / Core / CommandListManager.cpp
blob113146f45fb355cf81fe62837172af6d54404b41
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // This code is licensed under the MIT License (MIT).
4 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
5 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
6 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
7 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
8 //
9 // Developed by Minigraph
11 // Author: James Stanard
14 #include "pch.h"
15 #include "CommandListManager.h"
17 CommandQueue::CommandQueue(D3D12_COMMAND_LIST_TYPE Type) :
18 m_CommandQueue(nullptr),
19 m_Type(Type),
20 m_AllocatorPool(Type),
21 m_pFence(nullptr),
22 m_NextFenceValue((uint64_t)Type << 56 | 1),
23 m_LastCompletedFenceValue((uint64_t)Type << 56)
27 CommandQueue::~CommandQueue()
29 Shutdown();
32 void CommandQueue::Shutdown()
34 if (m_CommandQueue == nullptr)
35 return;
37 m_AllocatorPool.Shutdown();
39 port_destroy_event(m_FenceEventHandle);
41 m_pFence->Release();
42 m_pFence = nullptr;
44 m_CommandQueue->Release();
45 m_CommandQueue = nullptr;
48 CommandListManager::CommandListManager() :
49 m_Device(nullptr),
50 m_GraphicsQueue(D3D12_COMMAND_LIST_TYPE_DIRECT),
51 m_ComputeQueue(D3D12_COMMAND_LIST_TYPE_COMPUTE),
52 m_CopyQueue(D3D12_COMMAND_LIST_TYPE_COPY)
56 CommandListManager::~CommandListManager()
58 Shutdown();
61 void CommandListManager::Shutdown()
63 m_GraphicsQueue.Shutdown();
64 m_ComputeQueue.Shutdown();
65 m_CopyQueue.Shutdown();
68 void CommandQueue::Create(ID3D12Device* pDevice)
70 ASSERT(pDevice != nullptr);
71 ASSERT(!IsReady());
72 ASSERT(m_AllocatorPool.Size() == 0);
74 D3D12_COMMAND_QUEUE_DESC QueueDesc = {};
75 QueueDesc.Type = m_Type;
76 QueueDesc.NodeMask = 1;
77 pDevice->CreateCommandQueue(&QueueDesc, MY_IID_PPV_ARGS(&m_CommandQueue));
78 m_CommandQueue->SetName(L"CommandListManager::m_CommandQueue");
80 ASSERT_SUCCEEDED(pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, MY_IID_PPV_ARGS(&m_pFence)));
81 m_pFence->SetName(L"CommandListManager::m_pFence");
82 m_pFence->Signal((uint64_t)m_Type << 56);
84 m_FenceEventHandle = port_create_event();
85 ASSERT(m_FenceEventHandle != INVALID_HANDLE_VALUE);
87 m_AllocatorPool.Create(pDevice);
89 ASSERT(IsReady());
92 void CommandListManager::Create(ID3D12Device* pDevice)
94 ASSERT(pDevice != nullptr);
96 m_Device = pDevice;
98 m_GraphicsQueue.Create(pDevice);
99 m_ComputeQueue.Create(pDevice);
100 m_CopyQueue.Create(pDevice);
103 void CommandListManager::CreateNewCommandList( D3D12_COMMAND_LIST_TYPE Type, ID3D12GraphicsCommandList** List, ID3D12CommandAllocator** Allocator )
105 ASSERT(Type != D3D12_COMMAND_LIST_TYPE_BUNDLE, "Bundles are not yet supported");
106 switch (Type)
108 case D3D12_COMMAND_LIST_TYPE_DIRECT: *Allocator = m_GraphicsQueue.RequestAllocator(); break;
109 case D3D12_COMMAND_LIST_TYPE_BUNDLE: break;
110 case D3D12_COMMAND_LIST_TYPE_COMPUTE: *Allocator = m_ComputeQueue.RequestAllocator(); break;
111 case D3D12_COMMAND_LIST_TYPE_COPY: *Allocator = m_CopyQueue.RequestAllocator(); break;
114 ASSERT_SUCCEEDED( m_Device->CreateCommandList(1, Type, *Allocator, nullptr, MY_IID_PPV_ARGS(List)) );
115 (*List)->SetName(L"CommandList");
118 uint64_t CommandQueue::ExecuteCommandList( ID3D12CommandList* List )
120 std::lock_guard<std::mutex> LockGuard(m_FenceMutex);
122 ASSERT_SUCCEEDED(((ID3D12GraphicsCommandList*)List)->Close());
124 // Kickoff the command list
125 m_CommandQueue->ExecuteCommandLists(1, &List);
127 // Signal the next fence value (with the GPU)
128 m_CommandQueue->Signal(m_pFence, m_NextFenceValue);
130 // And increment the fence value.
131 return m_NextFenceValue++;
134 uint64_t CommandQueue::IncrementFence(void)
136 std::lock_guard<std::mutex> LockGuard(m_FenceMutex);
137 m_CommandQueue->Signal(m_pFence, m_NextFenceValue);
138 return m_NextFenceValue++;
141 bool CommandQueue::IsFenceComplete(uint64_t FenceValue)
143 // Avoid querying the fence value by testing against the last one seen.
144 // The max() is to protect against an unlikely race condition that could cause the last
145 // completed fence value to regress.
146 if (FenceValue > m_LastCompletedFenceValue)
147 m_LastCompletedFenceValue = std::max(m_LastCompletedFenceValue, m_pFence->GetCompletedValue());
149 return FenceValue <= m_LastCompletedFenceValue;
152 namespace Graphics
154 extern CommandListManager g_CommandManager;
157 void CommandQueue::StallForFence(uint64_t FenceValue)
159 CommandQueue& Producer = Graphics::g_CommandManager.GetQueue((D3D12_COMMAND_LIST_TYPE)(FenceValue >> 56));
160 m_CommandQueue->Wait(Producer.m_pFence, FenceValue);
163 void CommandQueue::StallForProducer(CommandQueue& Producer)
165 ASSERT(Producer.m_NextFenceValue > 0);
166 m_CommandQueue->Wait(Producer.m_pFence, Producer.m_NextFenceValue - 1);
169 void CommandQueue::WaitForFence(uint64_t FenceValue)
171 if (IsFenceComplete(FenceValue))
172 return;
174 // TODO: Think about how this might affect a multi-threaded situation. Suppose thread A
175 // wants to wait for fence 100, then thread B comes along and wants to wait for 99. If
176 // the fence can only have one event set on completion, then thread B has to wait for
177 // 100 before it knows 99 is ready. Maybe insert sequential events?
179 std::lock_guard<std::mutex> LockGuard(m_EventMutex);
181 m_pFence->SetEventOnCompletion(FenceValue, m_FenceEventHandle);
182 port_wait_event(m_FenceEventHandle, INFINITE);
183 m_LastCompletedFenceValue = FenceValue;
187 void CommandListManager::WaitForFence(uint64_t FenceValue)
189 CommandQueue& Producer = Graphics::g_CommandManager.GetQueue((D3D12_COMMAND_LIST_TYPE)(FenceValue >> 56));
190 Producer.WaitForFence(FenceValue);
193 ID3D12CommandAllocator* CommandQueue::RequestAllocator()
195 uint64_t CompletedFence = m_pFence->GetCompletedValue();
197 return m_AllocatorPool.RequestAllocator(CompletedFence);
200 void CommandQueue::DiscardAllocator(uint64_t FenceValue, ID3D12CommandAllocator* Allocator)
202 m_AllocatorPool.DiscardAllocator(FenceValue, Allocator);