• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/d3d12/DeviceD3D12.h"
16 
17 #include "common/Assert.h"
18 #include "dawn_native/BackendConnection.h"
19 #include "dawn_native/DynamicUploader.h"
20 #include "dawn_native/d3d12/AdapterD3D12.h"
21 #include "dawn_native/d3d12/BackendD3D12.h"
22 #include "dawn_native/d3d12/BindGroupD3D12.h"
23 #include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
24 #include "dawn_native/d3d12/BufferD3D12.h"
25 #include "dawn_native/d3d12/CommandAllocatorManager.h"
26 #include "dawn_native/d3d12/CommandBufferD3D12.h"
27 #include "dawn_native/d3d12/ComputePipelineD3D12.h"
28 #include "dawn_native/d3d12/DescriptorHeapAllocator.h"
29 #include "dawn_native/d3d12/PipelineLayoutD3D12.h"
30 #include "dawn_native/d3d12/PlatformFunctions.h"
31 #include "dawn_native/d3d12/QueueD3D12.h"
32 #include "dawn_native/d3d12/RenderPipelineD3D12.h"
33 #include "dawn_native/d3d12/ResourceAllocator.h"
34 #include "dawn_native/d3d12/SamplerD3D12.h"
35 #include "dawn_native/d3d12/ShaderModuleD3D12.h"
36 #include "dawn_native/d3d12/StagingBufferD3D12.h"
37 #include "dawn_native/d3d12/SwapChainD3D12.h"
38 #include "dawn_native/d3d12/TextureD3D12.h"
39 
40 namespace dawn_native { namespace d3d12 {
41 
ASSERT_SUCCESS(HRESULT hr)42     void ASSERT_SUCCESS(HRESULT hr) {
43         ASSERT(SUCCEEDED(hr));
44     }
45 
Device(Adapter * adapter,const DeviceDescriptor * descriptor)46     Device::Device(Adapter* adapter, const DeviceDescriptor* descriptor)
47         : DeviceBase(adapter, descriptor) {
48         if (descriptor != nullptr) {
49             ApplyToggleOverrides(descriptor);
50         }
51     }
52 
Initialize()53     MaybeError Device::Initialize() {
54         mD3d12Device = ToBackend(GetAdapter())->GetDevice();
55 
56         ASSERT(mD3d12Device != nullptr);
57 
58         // Create device-global objects
59         D3D12_COMMAND_QUEUE_DESC queueDesc = {};
60         queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
61         queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
62         ASSERT_SUCCESS(mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)));
63 
64         ASSERT_SUCCESS(mD3d12Device->CreateFence(mLastSubmittedSerial, D3D12_FENCE_FLAG_NONE,
65                                                  IID_PPV_ARGS(&mFence)));
66         mFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
67         ASSERT(mFenceEvent != nullptr);
68 
69         // Initialize backend services
70         mCommandAllocatorManager = std::make_unique<CommandAllocatorManager>(this);
71         mDescriptorHeapAllocator = std::make_unique<DescriptorHeapAllocator>(this);
72         mMapRequestTracker = std::make_unique<MapRequestTracker>(this);
73         mResourceAllocator = std::make_unique<ResourceAllocator>(this);
74 
75         NextSerial();
76 
77         // Initialize indirect commands
78         D3D12_INDIRECT_ARGUMENT_DESC argumentDesc = {};
79         argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH;
80 
81         D3D12_COMMAND_SIGNATURE_DESC programDesc = {};
82         programDesc.ByteStride = 3 * sizeof(uint32_t);
83         programDesc.NumArgumentDescs = 1;
84         programDesc.pArgumentDescs = &argumentDesc;
85 
86         GetD3D12Device()->CreateCommandSignature(&programDesc, NULL,
87                                                  IID_PPV_ARGS(&mDispatchIndirectSignature));
88 
89         argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
90         programDesc.ByteStride = 4 * sizeof(uint32_t);
91 
92         GetD3D12Device()->CreateCommandSignature(&programDesc, NULL,
93                                                  IID_PPV_ARGS(&mDrawIndirectSignature));
94 
95         argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
96         programDesc.ByteStride = 5 * sizeof(uint32_t);
97 
98         GetD3D12Device()->CreateCommandSignature(&programDesc, NULL,
99                                                  IID_PPV_ARGS(&mDrawIndexedIndirectSignature));
100 
101         return {};
102     }
103 
~Device()104     Device::~Device() {
105         // Immediately forget about all pending commands
106         if (mPendingCommands.open) {
107             mPendingCommands.commandList->Close();
108             mPendingCommands.open = false;
109             mPendingCommands.commandList = nullptr;
110         }
111         NextSerial();
112         WaitForSerial(mLastSubmittedSerial);  // Wait for all in-flight commands to finish executing
113         TickImpl();                    // Call tick one last time so resources are cleaned up
114 
115         // Free services explicitly so that they can free D3D12 resources before destruction of the
116         // device.
117         mDynamicUploader = nullptr;
118 
119         // Releasing the uploader enqueues buffers to be released.
120         // Call Tick() again to clear them before releasing the allocator.
121         mResourceAllocator->Tick(mCompletedSerial);
122 
123         ASSERT(mUsedComObjectRefs.Empty());
124         ASSERT(mPendingCommands.commandList == nullptr);
125     }
126 
GetD3D12Device() const127     ComPtr<ID3D12Device> Device::GetD3D12Device() const {
128         return mD3d12Device;
129     }
130 
GetCommandQueue() const131     ComPtr<ID3D12CommandQueue> Device::GetCommandQueue() const {
132         return mCommandQueue;
133     }
134 
GetDispatchIndirectSignature() const135     ComPtr<ID3D12CommandSignature> Device::GetDispatchIndirectSignature() const {
136         return mDispatchIndirectSignature;
137     }
138 
GetDrawIndirectSignature() const139     ComPtr<ID3D12CommandSignature> Device::GetDrawIndirectSignature() const {
140         return mDrawIndirectSignature;
141     }
142 
GetDrawIndexedIndirectSignature() const143     ComPtr<ID3D12CommandSignature> Device::GetDrawIndexedIndirectSignature() const {
144         return mDrawIndexedIndirectSignature;
145     }
146 
GetDescriptorHeapAllocator() const147     DescriptorHeapAllocator* Device::GetDescriptorHeapAllocator() const {
148         return mDescriptorHeapAllocator.get();
149     }
150 
GetFactory() const151     ComPtr<IDXGIFactory4> Device::GetFactory() const {
152         return ToBackend(GetAdapter())->GetBackend()->GetFactory();
153     }
154 
GetFunctions() const155     const PlatformFunctions* Device::GetFunctions() const {
156         return ToBackend(GetAdapter())->GetBackend()->GetFunctions();
157     }
158 
GetMapRequestTracker() const159     MapRequestTracker* Device::GetMapRequestTracker() const {
160         return mMapRequestTracker.get();
161     }
162 
GetResourceAllocator() const163     ResourceAllocator* Device::GetResourceAllocator() const {
164         return mResourceAllocator.get();
165     }
166 
OpenCommandList(ComPtr<ID3D12GraphicsCommandList> * commandList)167     void Device::OpenCommandList(ComPtr<ID3D12GraphicsCommandList>* commandList) {
168         ComPtr<ID3D12GraphicsCommandList>& cmdList = *commandList;
169         if (!cmdList) {
170             ASSERT_SUCCESS(mD3d12Device->CreateCommandList(
171                 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
172                 mCommandAllocatorManager->ReserveCommandAllocator().Get(), nullptr,
173                 IID_PPV_ARGS(&cmdList)));
174         } else {
175             ASSERT_SUCCESS(
176                 cmdList->Reset(mCommandAllocatorManager->ReserveCommandAllocator().Get(), nullptr));
177         }
178     }
179 
GetPendingCommandList()180     ComPtr<ID3D12GraphicsCommandList> Device::GetPendingCommandList() {
181         // Callers of GetPendingCommandList do so to record commands. Only reserve a command
182         // allocator when it is needed so we don't submit empty command lists
183         if (!mPendingCommands.open) {
184             OpenCommandList(&mPendingCommands.commandList);
185             mPendingCommands.open = true;
186         }
187         return mPendingCommands.commandList;
188     }
189 
GetCompletedCommandSerial() const190     Serial Device::GetCompletedCommandSerial() const {
191         return mCompletedSerial;
192     }
193 
GetLastSubmittedCommandSerial() const194     Serial Device::GetLastSubmittedCommandSerial() const {
195         return mLastSubmittedSerial;
196     }
197 
GetPendingCommandSerial() const198     Serial Device::GetPendingCommandSerial() const {
199         return mLastSubmittedSerial + 1;
200     }
201 
TickImpl()202     void Device::TickImpl() {
203         // Perform cleanup operations to free unused objects
204         mCompletedSerial = mFence->GetCompletedValue();
205 
206         // Uploader should tick before the resource allocator
207         // as it enqueues resources to be released.
208         mDynamicUploader->Tick(mCompletedSerial);
209 
210         mResourceAllocator->Tick(mCompletedSerial);
211         mCommandAllocatorManager->Tick(mCompletedSerial);
212         mDescriptorHeapAllocator->Tick(mCompletedSerial);
213         mMapRequestTracker->Tick(mCompletedSerial);
214         mUsedComObjectRefs.ClearUpTo(mCompletedSerial);
215         ExecuteCommandLists({});
216         NextSerial();
217     }
218 
NextSerial()219     void Device::NextSerial() {
220         mLastSubmittedSerial++;
221         ASSERT_SUCCESS(mCommandQueue->Signal(mFence.Get(), mLastSubmittedSerial));
222     }
223 
WaitForSerial(uint64_t serial)224     void Device::WaitForSerial(uint64_t serial) {
225         mCompletedSerial = mFence->GetCompletedValue();
226         if (mCompletedSerial < serial) {
227             ASSERT_SUCCESS(mFence->SetEventOnCompletion(serial, mFenceEvent));
228             WaitForSingleObject(mFenceEvent, INFINITE);
229         }
230     }
231 
ReferenceUntilUnused(ComPtr<IUnknown> object)232     void Device::ReferenceUntilUnused(ComPtr<IUnknown> object) {
233         mUsedComObjectRefs.Enqueue(object, GetPendingCommandSerial());
234     }
235 
ExecuteCommandLists(std::initializer_list<ID3D12CommandList * > commandLists)236     void Device::ExecuteCommandLists(std::initializer_list<ID3D12CommandList*> commandLists) {
237         // If there are pending commands, prepend them to ExecuteCommandLists
238         if (mPendingCommands.open) {
239             std::vector<ID3D12CommandList*> lists(commandLists.size() + 1);
240             mPendingCommands.commandList->Close();
241             mPendingCommands.open = false;
242             lists[0] = mPendingCommands.commandList.Get();
243             std::copy(commandLists.begin(), commandLists.end(), lists.begin() + 1);
244             mCommandQueue->ExecuteCommandLists(static_cast<UINT>(commandLists.size() + 1),
245                                                lists.data());
246             mPendingCommands.commandList = nullptr;
247         } else {
248             std::vector<ID3D12CommandList*> lists(commandLists);
249             mCommandQueue->ExecuteCommandLists(static_cast<UINT>(commandLists.size()),
250                                                lists.data());
251         }
252     }
253 
CreateBindGroupImpl(const BindGroupDescriptor * descriptor)254     ResultOrError<BindGroupBase*> Device::CreateBindGroupImpl(
255         const BindGroupDescriptor* descriptor) {
256         return new BindGroup(this, descriptor);
257     }
CreateBindGroupLayoutImpl(const BindGroupLayoutDescriptor * descriptor)258     ResultOrError<BindGroupLayoutBase*> Device::CreateBindGroupLayoutImpl(
259         const BindGroupLayoutDescriptor* descriptor) {
260         return new BindGroupLayout(this, descriptor);
261     }
CreateBufferImpl(const BufferDescriptor * descriptor)262     ResultOrError<BufferBase*> Device::CreateBufferImpl(const BufferDescriptor* descriptor) {
263         return new Buffer(this, descriptor);
264     }
CreateCommandBuffer(CommandEncoderBase * encoder,const CommandBufferDescriptor * descriptor)265     CommandBufferBase* Device::CreateCommandBuffer(CommandEncoderBase* encoder,
266                                                    const CommandBufferDescriptor* descriptor) {
267         return new CommandBuffer(encoder, descriptor);
268     }
CreateComputePipelineImpl(const ComputePipelineDescriptor * descriptor)269     ResultOrError<ComputePipelineBase*> Device::CreateComputePipelineImpl(
270         const ComputePipelineDescriptor* descriptor) {
271         return new ComputePipeline(this, descriptor);
272     }
CreatePipelineLayoutImpl(const PipelineLayoutDescriptor * descriptor)273     ResultOrError<PipelineLayoutBase*> Device::CreatePipelineLayoutImpl(
274         const PipelineLayoutDescriptor* descriptor) {
275         return new PipelineLayout(this, descriptor);
276     }
CreateQueueImpl()277     ResultOrError<QueueBase*> Device::CreateQueueImpl() {
278         return new Queue(this);
279     }
CreateRenderPipelineImpl(const RenderPipelineDescriptor * descriptor)280     ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
281         const RenderPipelineDescriptor* descriptor) {
282         return new RenderPipeline(this, descriptor);
283     }
CreateSamplerImpl(const SamplerDescriptor * descriptor)284     ResultOrError<SamplerBase*> Device::CreateSamplerImpl(const SamplerDescriptor* descriptor) {
285         return new Sampler(this, descriptor);
286     }
CreateShaderModuleImpl(const ShaderModuleDescriptor * descriptor)287     ResultOrError<ShaderModuleBase*> Device::CreateShaderModuleImpl(
288         const ShaderModuleDescriptor* descriptor) {
289         return new ShaderModule(this, descriptor);
290     }
CreateSwapChainImpl(const SwapChainDescriptor * descriptor)291     ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl(
292         const SwapChainDescriptor* descriptor) {
293         return new SwapChain(this, descriptor);
294     }
CreateTextureImpl(const TextureDescriptor * descriptor)295     ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
296         return new Texture(this, descriptor);
297     }
CreateTextureViewImpl(TextureBase * texture,const TextureViewDescriptor * descriptor)298     ResultOrError<TextureViewBase*> Device::CreateTextureViewImpl(
299         TextureBase* texture,
300         const TextureViewDescriptor* descriptor) {
301         return new TextureView(texture, descriptor);
302     }
303 
CreateStagingBuffer(size_t size)304     ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(size_t size) {
305         std::unique_ptr<StagingBufferBase> stagingBuffer =
306             std::make_unique<StagingBuffer>(size, this);
307         return std::move(stagingBuffer);
308     }
309 
CopyFromStagingToBuffer(StagingBufferBase * source,uint64_t sourceOffset,BufferBase * destination,uint64_t destinationOffset,uint64_t size)310     MaybeError Device::CopyFromStagingToBuffer(StagingBufferBase* source,
311                                                uint64_t sourceOffset,
312                                                BufferBase* destination,
313                                                uint64_t destinationOffset,
314                                                uint64_t size) {
315         ToBackend(destination)
316             ->TransitionUsageNow(GetPendingCommandList(), dawn::BufferUsageBit::CopyDst);
317 
318         GetPendingCommandList()->CopyBufferRegion(
319             ToBackend(destination)->GetD3D12Resource().Get(), destinationOffset,
320             ToBackend(source)->GetResource(), sourceOffset, size);
321 
322         return {};
323     }
324 
325 }}  // namespace dawn_native::d3d12
326