• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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/SamplerHeapCacheD3D12.h"
16 
17 #include "common/Assert.h"
18 #include "common/HashUtils.h"
19 #include "dawn_native/d3d12/BindGroupD3D12.h"
20 #include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
21 #include "dawn_native/d3d12/DeviceD3D12.h"
22 #include "dawn_native/d3d12/Forward.h"
23 #include "dawn_native/d3d12/SamplerD3D12.h"
24 #include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h"
25 #include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h"
26 
27 namespace dawn_native { namespace d3d12 {
28 
SamplerHeapCacheEntry(std::vector<Sampler * > samplers)29     SamplerHeapCacheEntry::SamplerHeapCacheEntry(std::vector<Sampler*> samplers)
30         : mSamplers(std::move(samplers)) {
31     }
32 
SamplerHeapCacheEntry(SamplerHeapCache * cache,StagingDescriptorAllocator * allocator,std::vector<Sampler * > samplers,CPUDescriptorHeapAllocation allocation)33     SamplerHeapCacheEntry::SamplerHeapCacheEntry(SamplerHeapCache* cache,
34                                                  StagingDescriptorAllocator* allocator,
35                                                  std::vector<Sampler*> samplers,
36                                                  CPUDescriptorHeapAllocation allocation)
37         : mCPUAllocation(std::move(allocation)),
38           mSamplers(std::move(samplers)),
39           mAllocator(allocator),
40           mCache(cache) {
41         ASSERT(mCache != nullptr);
42         ASSERT(mCPUAllocation.IsValid());
43         ASSERT(!mSamplers.empty());
44     }
45 
AcquireSamplers()46     std::vector<Sampler*>&& SamplerHeapCacheEntry::AcquireSamplers() {
47         return std::move(mSamplers);
48     }
49 
~SamplerHeapCacheEntry()50     SamplerHeapCacheEntry::~SamplerHeapCacheEntry() {
51         // If this is a blueprint then the CPU allocation cannot exist and has no entry to remove.
52         if (mCPUAllocation.IsValid()) {
53             mCache->RemoveCacheEntry(this);
54             mAllocator->Deallocate(&mCPUAllocation);
55         }
56 
57         ASSERT(!mCPUAllocation.IsValid());
58     }
59 
Populate(Device * device,ShaderVisibleDescriptorAllocator * allocator)60     bool SamplerHeapCacheEntry::Populate(Device* device,
61                                          ShaderVisibleDescriptorAllocator* allocator) {
62         if (allocator->IsAllocationStillValid(mGPUAllocation)) {
63             return true;
64         }
65 
66         ASSERT(!mSamplers.empty());
67 
68         // Attempt to allocate descriptors for the currently bound shader-visible heaps.
69         // If either failed, return early to re-allocate and switch the heaps.
70         const uint32_t descriptorCount = mSamplers.size();
71         D3D12_CPU_DESCRIPTOR_HANDLE baseCPUDescriptor;
72         if (!allocator->AllocateGPUDescriptors(descriptorCount, device->GetPendingCommandSerial(),
73                                                &baseCPUDescriptor, &mGPUAllocation)) {
74             return false;
75         }
76 
77         // CPU bindgroups are sparsely allocated across CPU heaps. Instead of doing
78         // simple copies per bindgroup, a single non-simple copy could be issued.
79         // TODO(dawn:155): Consider doing this optimization.
80         device->GetD3D12Device()->CopyDescriptorsSimple(descriptorCount, baseCPUDescriptor,
81                                                         mCPUAllocation.GetBaseDescriptor(),
82                                                         D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
83 
84         return true;
85     }
86 
GetBaseDescriptor() const87     D3D12_GPU_DESCRIPTOR_HANDLE SamplerHeapCacheEntry::GetBaseDescriptor() const {
88         return mGPUAllocation.GetBaseDescriptor();
89     }
90 
GetOrCreate(const BindGroup * group,StagingDescriptorAllocator * samplerAllocator)91     ResultOrError<Ref<SamplerHeapCacheEntry>> SamplerHeapCache::GetOrCreate(
92         const BindGroup* group,
93         StagingDescriptorAllocator* samplerAllocator) {
94         const BindGroupLayout* bgl = ToBackend(group->GetLayout());
95 
96         // If a previously created bindgroup used the same samplers, the backing sampler heap
97         // allocation can be reused. The packed list of samplers acts as the key to lookup the
98         // allocation in a cache.
99         // TODO(dawn:155): Avoid re-allocating the vector each lookup.
100         std::vector<Sampler*> samplers;
101         samplers.reserve(bgl->GetSamplerDescriptorCount());
102 
103         for (BindingIndex bindingIndex = bgl->GetDynamicBufferCount();
104              bindingIndex < bgl->GetBindingCount(); ++bindingIndex) {
105             const BindingInfo& bindingInfo = bgl->GetBindingInfo(bindingIndex);
106             if (bindingInfo.bindingType == BindingInfoType::Sampler) {
107                 samplers.push_back(ToBackend(group->GetBindingAsSampler(bindingIndex)));
108             }
109         }
110 
111         // Check the cache if there exists a sampler heap allocation that corresponds to the
112         // samplers.
113         SamplerHeapCacheEntry blueprint(std::move(samplers));
114         auto iter = mCache.find(&blueprint);
115         if (iter != mCache.end()) {
116             return Ref<SamplerHeapCacheEntry>(*iter);
117         }
118 
119         // Steal the sampler vector back from the blueprint to avoid creating a new copy for the
120         // real entry below.
121         samplers = std::move(blueprint.AcquireSamplers());
122 
123         CPUDescriptorHeapAllocation allocation;
124         DAWN_TRY_ASSIGN(allocation, samplerAllocator->AllocateCPUDescriptors());
125 
126         const uint32_t samplerSizeIncrement = samplerAllocator->GetSizeIncrement();
127         ID3D12Device* d3d12Device = mDevice->GetD3D12Device();
128 
129         for (uint32_t i = 0; i < samplers.size(); ++i) {
130             const auto& samplerDesc = samplers[i]->GetSamplerDescriptor();
131             d3d12Device->CreateSampler(&samplerDesc,
132                                        allocation.OffsetFrom(samplerSizeIncrement, i));
133         }
134 
135         Ref<SamplerHeapCacheEntry> entry = AcquireRef(new SamplerHeapCacheEntry(
136             this, samplerAllocator, std::move(samplers), std::move(allocation)));
137         mCache.insert(entry.Get());
138         return std::move(entry);
139     }
140 
SamplerHeapCache(Device * device)141     SamplerHeapCache::SamplerHeapCache(Device* device) : mDevice(device) {
142     }
143 
~SamplerHeapCache()144     SamplerHeapCache::~SamplerHeapCache() {
145         ASSERT(mCache.empty());
146     }
147 
RemoveCacheEntry(SamplerHeapCacheEntry * entry)148     void SamplerHeapCache::RemoveCacheEntry(SamplerHeapCacheEntry* entry) {
149         ASSERT(entry->GetRefCountForTesting() == 0);
150         size_t removedCount = mCache.erase(entry);
151         ASSERT(removedCount == 1);
152     }
153 
operator ()(const SamplerHeapCacheEntry * entry) const154     size_t SamplerHeapCacheEntry::HashFunc::operator()(const SamplerHeapCacheEntry* entry) const {
155         size_t hash = 0;
156         for (const Sampler* sampler : entry->mSamplers) {
157             HashCombine(&hash, sampler);
158         }
159         return hash;
160     }
161 
operator ()(const SamplerHeapCacheEntry * a,const SamplerHeapCacheEntry * b) const162     bool SamplerHeapCacheEntry::EqualityFunc::operator()(const SamplerHeapCacheEntry* a,
163                                                          const SamplerHeapCacheEntry* b) const {
164         return a->mSamplers == b->mSamplers;
165     }
166 }}  // namespace dawn_native::d3d12
167