• 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/BindGroupD3D12.h"
16 
17 #include "common/BitSetIterator.h"
18 #include "dawn_native/ExternalTexture.h"
19 #include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
20 #include "dawn_native/d3d12/BufferD3D12.h"
21 #include "dawn_native/d3d12/DeviceD3D12.h"
22 #include "dawn_native/d3d12/SamplerHeapCacheD3D12.h"
23 #include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h"
24 #include "dawn_native/d3d12/TextureD3D12.h"
25 
26 namespace dawn_native { namespace d3d12 {
27 
28     // static
Create(Device * device,const BindGroupDescriptor * descriptor)29     ResultOrError<Ref<BindGroup>> BindGroup::Create(Device* device,
30                                                     const BindGroupDescriptor* descriptor) {
31         return ToBackend(descriptor->layout)->AllocateBindGroup(device, descriptor);
32     }
33 
BindGroup(Device * device,const BindGroupDescriptor * descriptor,uint32_t viewSizeIncrement,const CPUDescriptorHeapAllocation & viewAllocation)34     BindGroup::BindGroup(Device* device,
35                          const BindGroupDescriptor* descriptor,
36                          uint32_t viewSizeIncrement,
37                          const CPUDescriptorHeapAllocation& viewAllocation)
38         : BindGroupBase(this, device, descriptor) {
39         BindGroupLayout* bgl = ToBackend(GetLayout());
40 
41         mCPUViewAllocation = viewAllocation;
42 
43         const auto& descriptorHeapOffsets = bgl->GetDescriptorHeapOffsets();
44 
45         ID3D12Device* d3d12Device = device->GetD3D12Device();
46 
47         // It's not necessary to create descriptors in the descriptor heap for dynamic resources.
48         // This is because they are created as root descriptors which are never heap allocated.
49         // Since dynamic buffers are packed in the front, we can skip over these bindings by
50         // starting from the dynamic buffer count.
51         for (BindingIndex bindingIndex = bgl->GetDynamicBufferCount();
52              bindingIndex < bgl->GetBindingCount(); ++bindingIndex) {
53             const BindingInfo& bindingInfo = bgl->GetBindingInfo(bindingIndex);
54 
55             // Increment size does not need to be stored and is only used to get a handle
56             // local to the allocation with OffsetFrom().
57             switch (bindingInfo.bindingType) {
58                 case BindingInfoType::Buffer: {
59                     BufferBinding binding = GetBindingAsBufferBinding(bindingIndex);
60 
61                     ID3D12Resource* resource = ToBackend(binding.buffer)->GetD3D12Resource();
62                     if (resource == nullptr) {
63                         // The Buffer was destroyed. Skip creating buffer views since there is no
64                         // resource. This bind group won't be used as it is an error to submit a
65                         // command buffer that references destroyed resources.
66                         continue;
67                     }
68 
69                     switch (bindingInfo.buffer.type) {
70                         case wgpu::BufferBindingType::Uniform: {
71                             D3D12_CONSTANT_BUFFER_VIEW_DESC desc;
72                             desc.SizeInBytes =
73                                 Align(binding.size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
74                             desc.BufferLocation =
75                                 ToBackend(binding.buffer)->GetVA() + binding.offset;
76 
77                             d3d12Device->CreateConstantBufferView(
78                                 &desc, viewAllocation.OffsetFrom(
79                                            viewSizeIncrement, descriptorHeapOffsets[bindingIndex]));
80                             break;
81                         }
82                         case wgpu::BufferBindingType::Storage:
83                         case kInternalStorageBufferBinding: {
84                             // Since SPIRV-Cross outputs HLSL shaders with RWByteAddressBuffer,
85                             // we must use D3D12_BUFFER_UAV_FLAG_RAW when making the
86                             // UNORDERED_ACCESS_VIEW_DESC. Using D3D12_BUFFER_UAV_FLAG_RAW requires
87                             // that we use DXGI_FORMAT_R32_TYPELESS as the format of the view.
88                             // DXGI_FORMAT_R32_TYPELESS requires that the element size be 4
89                             // byte aligned. Since binding.size and binding.offset are in bytes,
90                             // we need to divide by 4 to obtain the element size.
91                             D3D12_UNORDERED_ACCESS_VIEW_DESC desc;
92                             desc.Buffer.NumElements = binding.size / 4;
93                             desc.Format = DXGI_FORMAT_R32_TYPELESS;
94                             desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
95                             desc.Buffer.FirstElement = binding.offset / 4;
96                             desc.Buffer.StructureByteStride = 0;
97                             desc.Buffer.CounterOffsetInBytes = 0;
98                             desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
99 
100                             d3d12Device->CreateUnorderedAccessView(
101                                 resource, nullptr, &desc,
102                                 viewAllocation.OffsetFrom(viewSizeIncrement,
103                                                           descriptorHeapOffsets[bindingIndex]));
104                             break;
105                         }
106                         case wgpu::BufferBindingType::ReadOnlyStorage: {
107                             // Like StorageBuffer, SPIRV-Cross outputs HLSL shaders for readonly
108                             // storage buffer with ByteAddressBuffer. So we must use
109                             // D3D12_BUFFER_SRV_FLAG_RAW when making the SRV descriptor. And it has
110                             // similar requirement for format, element size, etc.
111                             D3D12_SHADER_RESOURCE_VIEW_DESC desc;
112                             desc.Format = DXGI_FORMAT_R32_TYPELESS;
113                             desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
114                             desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
115                             desc.Buffer.FirstElement = binding.offset / 4;
116                             desc.Buffer.NumElements = binding.size / 4;
117                             desc.Buffer.StructureByteStride = 0;
118                             desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
119                             d3d12Device->CreateShaderResourceView(
120                                 resource, &desc,
121                                 viewAllocation.OffsetFrom(viewSizeIncrement,
122                                                           descriptorHeapOffsets[bindingIndex]));
123                             break;
124                         }
125                         case wgpu::BufferBindingType::Undefined:
126                             UNREACHABLE();
127                     }
128 
129                     break;
130                 }
131 
132                 case BindingInfoType::Texture: {
133                     auto* view = ToBackend(GetBindingAsTextureView(bindingIndex));
134                     auto& srv = view->GetSRVDescriptor();
135 
136                     ID3D12Resource* resource = ToBackend(view->GetTexture())->GetD3D12Resource();
137                     if (resource == nullptr) {
138                         // The Texture was destroyed. Skip creating the SRV since there is no
139                         // resource. This bind group won't be used as it is an error to submit a
140                         // command buffer that references destroyed resources.
141                         continue;
142                     }
143 
144                     d3d12Device->CreateShaderResourceView(
145                         resource, &srv,
146                         viewAllocation.OffsetFrom(viewSizeIncrement,
147                                                   descriptorHeapOffsets[bindingIndex]));
148                     break;
149                 }
150 
151                 case BindingInfoType::StorageTexture: {
152                     TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex));
153 
154                     ID3D12Resource* resource = ToBackend(view->GetTexture())->GetD3D12Resource();
155                     if (resource == nullptr) {
156                         // The Texture was destroyed. Skip creating the SRV/UAV since there is no
157                         // resource. This bind group won't be used as it is an error to submit a
158                         // command buffer that references destroyed resources.
159                         continue;
160                     }
161 
162                     switch (bindingInfo.storageTexture.access) {
163                         case wgpu::StorageTextureAccess::WriteOnly: {
164                             D3D12_UNORDERED_ACCESS_VIEW_DESC uav = view->GetUAVDescriptor();
165                             d3d12Device->CreateUnorderedAccessView(
166                                 resource, nullptr, &uav,
167                                 viewAllocation.OffsetFrom(viewSizeIncrement,
168                                                           descriptorHeapOffsets[bindingIndex]));
169                             break;
170                         }
171 
172                         case wgpu::StorageTextureAccess::Undefined:
173                             UNREACHABLE();
174                     }
175 
176                     break;
177                 }
178 
179                 case BindingInfoType::ExternalTexture: {
180                     const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& views =
181                         GetBindingAsExternalTexture(bindingIndex)->GetTextureViews();
182 
183                     // Only single-plane formats are supported right now, so assert only one view
184                     // exists.
185                     ASSERT(views[1].Get() == nullptr);
186                     ASSERT(views[2].Get() == nullptr);
187 
188                     auto& srv = ToBackend(views[0])->GetSRVDescriptor();
189 
190                     ID3D12Resource* resource =
191                         ToBackend(views[0]->GetTexture())->GetD3D12Resource();
192 
193                     d3d12Device->CreateShaderResourceView(
194                         resource, &srv,
195                         viewAllocation.OffsetFrom(viewSizeIncrement,
196                                                   descriptorHeapOffsets[bindingIndex]));
197                     break;
198                 }
199 
200                 case BindingInfoType::Sampler: {
201                     // No-op as samplers will be later initialized by CreateSamplers().
202                     break;
203                 }
204             }
205         }
206 
207         // Loop through the dynamic storage buffers and build a flat map from the index of the
208         // dynamic storage buffer to its binding size. The index |dynamicStorageBufferIndex|
209         // means that it is the i'th buffer that is both dynamic and storage, in increasing order
210         // of BindingNumber.
211         mDynamicStorageBufferLengths.resize(bgl->GetBindingCountInfo().dynamicStorageBufferCount);
212         uint32_t dynamicStorageBufferIndex = 0;
213         for (BindingIndex bindingIndex(0); bindingIndex < bgl->GetDynamicBufferCount();
214              ++bindingIndex) {
215             if (bgl->IsStorageBufferBinding(bindingIndex)) {
216                 mDynamicStorageBufferLengths[dynamicStorageBufferIndex++] =
217                     GetBindingAsBufferBinding(bindingIndex).size;
218             }
219         }
220     }
221 
222     BindGroup::~BindGroup() = default;
223 
DestroyImpl()224     void BindGroup::DestroyImpl() {
225         BindGroupBase::DestroyImpl();
226         ToBackend(GetLayout())->DeallocateBindGroup(this, &mCPUViewAllocation);
227         ASSERT(!mCPUViewAllocation.IsValid());
228     }
229 
PopulateViews(ShaderVisibleDescriptorAllocator * viewAllocator)230     bool BindGroup::PopulateViews(ShaderVisibleDescriptorAllocator* viewAllocator) {
231         const BindGroupLayout* bgl = ToBackend(GetLayout());
232 
233         const uint32_t descriptorCount = bgl->GetCbvUavSrvDescriptorCount();
234         if (descriptorCount == 0 || viewAllocator->IsAllocationStillValid(mGPUViewAllocation)) {
235             return true;
236         }
237 
238         // Attempt to allocate descriptors for the currently bound shader-visible heaps.
239         // If either failed, return early to re-allocate and switch the heaps.
240         Device* device = ToBackend(GetDevice());
241 
242         D3D12_CPU_DESCRIPTOR_HANDLE baseCPUDescriptor;
243         if (!viewAllocator->AllocateGPUDescriptors(descriptorCount,
244                                                    device->GetPendingCommandSerial(),
245                                                    &baseCPUDescriptor, &mGPUViewAllocation)) {
246             return false;
247         }
248 
249         // CPU bindgroups are sparsely allocated across CPU heaps. Instead of doing
250         // simple copies per bindgroup, a single non-simple copy could be issued.
251         // TODO(dawn:155): Consider doing this optimization.
252         device->GetD3D12Device()->CopyDescriptorsSimple(descriptorCount, baseCPUDescriptor,
253                                                         mCPUViewAllocation.GetBaseDescriptor(),
254                                                         D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
255 
256         return true;
257     }
258 
GetBaseViewDescriptor() const259     D3D12_GPU_DESCRIPTOR_HANDLE BindGroup::GetBaseViewDescriptor() const {
260         return mGPUViewAllocation.GetBaseDescriptor();
261     }
262 
GetBaseSamplerDescriptor() const263     D3D12_GPU_DESCRIPTOR_HANDLE BindGroup::GetBaseSamplerDescriptor() const {
264         ASSERT(mSamplerAllocationEntry != nullptr);
265         return mSamplerAllocationEntry->GetBaseDescriptor();
266     }
267 
PopulateSamplers(Device * device,ShaderVisibleDescriptorAllocator * samplerAllocator)268     bool BindGroup::PopulateSamplers(Device* device,
269                                      ShaderVisibleDescriptorAllocator* samplerAllocator) {
270         if (mSamplerAllocationEntry == nullptr) {
271             return true;
272         }
273         return mSamplerAllocationEntry->Populate(device, samplerAllocator);
274     }
275 
SetSamplerAllocationEntry(Ref<SamplerHeapCacheEntry> entry)276     void BindGroup::SetSamplerAllocationEntry(Ref<SamplerHeapCacheEntry> entry) {
277         mSamplerAllocationEntry = std::move(entry);
278     }
279 
GetDynamicStorageBufferLengths() const280     const BindGroup::DynamicStorageBufferLengths& BindGroup::GetDynamicStorageBufferLengths()
281         const {
282         return mDynamicStorageBufferLengths;
283     }
284 
285 }}  // namespace dawn_native::d3d12
286