1 // Copyright 2019 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/PassResourceUsageTracker.h" 16 17 #include "dawn_native/BindGroup.h" 18 #include "dawn_native/Buffer.h" 19 #include "dawn_native/EnumMaskIterator.h" 20 #include "dawn_native/ExternalTexture.h" 21 #include "dawn_native/Format.h" 22 #include "dawn_native/QuerySet.h" 23 #include "dawn_native/Texture.h" 24 25 #include <utility> 26 27 namespace dawn_native { 28 BufferUsedAs(BufferBase * buffer,wgpu::BufferUsage usage)29 void SyncScopeUsageTracker::BufferUsedAs(BufferBase* buffer, wgpu::BufferUsage usage) { 30 // std::map's operator[] will create the key and return 0 if the key didn't exist 31 // before. 32 mBufferUsages[buffer] |= usage; 33 } 34 TextureViewUsedAs(TextureViewBase * view,wgpu::TextureUsage usage)35 void SyncScopeUsageTracker::TextureViewUsedAs(TextureViewBase* view, wgpu::TextureUsage usage) { 36 TextureBase* texture = view->GetTexture(); 37 const SubresourceRange& range = view->GetSubresourceRange(); 38 39 // Get or create a new TextureSubresourceUsage for that texture (initially filled with 40 // wgpu::TextureUsage::None) 41 auto it = mTextureUsages.emplace( 42 std::piecewise_construct, std::forward_as_tuple(texture), 43 std::forward_as_tuple(texture->GetFormat().aspects, texture->GetArrayLayers(), 44 texture->GetNumMipLevels(), wgpu::TextureUsage::None)); 45 TextureSubresourceUsage& textureUsage = it.first->second; 46 47 textureUsage.Update(range, 48 [usage](const SubresourceRange&, wgpu::TextureUsage* storedUsage) { 49 // TODO(crbug.com/dawn/1001): Consider optimizing to have fewer 50 // branches. 51 if ((*storedUsage & wgpu::TextureUsage::RenderAttachment) != 0 && 52 (usage & wgpu::TextureUsage::RenderAttachment) != 0) { 53 // Using the same subresource as an attachment for two different 54 // render attachments is a write-write hazard. Add this internal 55 // usage so we will fail the check that a subresource with 56 // writable usage is the single usage. 57 *storedUsage |= kAgainAsRenderAttachment; 58 } 59 *storedUsage |= usage; 60 }); 61 } 62 AddRenderBundleTextureUsage(TextureBase * texture,const TextureSubresourceUsage & textureUsage)63 void SyncScopeUsageTracker::AddRenderBundleTextureUsage( 64 TextureBase* texture, 65 const TextureSubresourceUsage& textureUsage) { 66 // Get or create a new TextureSubresourceUsage for that texture (initially filled with 67 // wgpu::TextureUsage::None) 68 auto it = mTextureUsages.emplace( 69 std::piecewise_construct, std::forward_as_tuple(texture), 70 std::forward_as_tuple(texture->GetFormat().aspects, texture->GetArrayLayers(), 71 texture->GetNumMipLevels(), wgpu::TextureUsage::None)); 72 TextureSubresourceUsage* passTextureUsage = &it.first->second; 73 74 passTextureUsage->Merge( 75 textureUsage, [](const SubresourceRange&, wgpu::TextureUsage* storedUsage, 76 const wgpu::TextureUsage& addedUsage) { 77 ASSERT((addedUsage & wgpu::TextureUsage::RenderAttachment) == 0); 78 *storedUsage |= addedUsage; 79 }); 80 } 81 AddBindGroup(BindGroupBase * group)82 void SyncScopeUsageTracker::AddBindGroup(BindGroupBase* group) { 83 for (BindingIndex bindingIndex{0}; bindingIndex < group->GetLayout()->GetBindingCount(); 84 ++bindingIndex) { 85 const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex); 86 87 switch (bindingInfo.bindingType) { 88 case BindingInfoType::Buffer: { 89 BufferBase* buffer = group->GetBindingAsBufferBinding(bindingIndex).buffer; 90 switch (bindingInfo.buffer.type) { 91 case wgpu::BufferBindingType::Uniform: 92 BufferUsedAs(buffer, wgpu::BufferUsage::Uniform); 93 break; 94 case wgpu::BufferBindingType::Storage: 95 BufferUsedAs(buffer, wgpu::BufferUsage::Storage); 96 break; 97 case kInternalStorageBufferBinding: 98 BufferUsedAs(buffer, kInternalStorageBuffer); 99 break; 100 case wgpu::BufferBindingType::ReadOnlyStorage: 101 BufferUsedAs(buffer, kReadOnlyStorageBuffer); 102 break; 103 case wgpu::BufferBindingType::Undefined: 104 UNREACHABLE(); 105 } 106 break; 107 } 108 109 case BindingInfoType::Texture: { 110 TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex); 111 TextureViewUsedAs(view, wgpu::TextureUsage::TextureBinding); 112 break; 113 } 114 115 case BindingInfoType::StorageTexture: { 116 TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex); 117 switch (bindingInfo.storageTexture.access) { 118 case wgpu::StorageTextureAccess::WriteOnly: 119 TextureViewUsedAs(view, wgpu::TextureUsage::StorageBinding); 120 break; 121 case wgpu::StorageTextureAccess::Undefined: 122 UNREACHABLE(); 123 } 124 break; 125 } 126 127 case BindingInfoType::ExternalTexture: { 128 ExternalTextureBase* externalTexture = 129 group->GetBindingAsExternalTexture(bindingIndex); 130 131 const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& textureViews = 132 externalTexture->GetTextureViews(); 133 134 // Only single-plane formats are supported right now, so assert only one 135 // view exists. 136 ASSERT(textureViews[1].Get() == nullptr); 137 ASSERT(textureViews[2].Get() == nullptr); 138 139 mExternalTextureUsages.insert(externalTexture); 140 TextureViewUsedAs(textureViews[0].Get(), wgpu::TextureUsage::TextureBinding); 141 break; 142 } 143 144 case BindingInfoType::Sampler: 145 break; 146 } 147 } 148 } 149 AcquireSyncScopeUsage()150 SyncScopeResourceUsage SyncScopeUsageTracker::AcquireSyncScopeUsage() { 151 SyncScopeResourceUsage result; 152 result.buffers.reserve(mBufferUsages.size()); 153 result.bufferUsages.reserve(mBufferUsages.size()); 154 result.textures.reserve(mTextureUsages.size()); 155 result.textureUsages.reserve(mTextureUsages.size()); 156 157 for (auto& it : mBufferUsages) { 158 result.buffers.push_back(it.first); 159 result.bufferUsages.push_back(it.second); 160 } 161 162 for (auto& it : mTextureUsages) { 163 result.textures.push_back(it.first); 164 result.textureUsages.push_back(std::move(it.second)); 165 } 166 167 for (auto& it : mExternalTextureUsages) { 168 result.externalTextures.push_back(it); 169 } 170 171 mBufferUsages.clear(); 172 mTextureUsages.clear(); 173 mExternalTextureUsages.clear(); 174 175 return result; 176 } 177 AddDispatch(SyncScopeResourceUsage scope)178 void ComputePassResourceUsageTracker::AddDispatch(SyncScopeResourceUsage scope) { 179 mUsage.dispatchUsages.push_back(std::move(scope)); 180 } 181 AddReferencedBuffer(BufferBase * buffer)182 void ComputePassResourceUsageTracker::AddReferencedBuffer(BufferBase* buffer) { 183 mUsage.referencedBuffers.insert(buffer); 184 } 185 AddResourcesReferencedByBindGroup(BindGroupBase * group)186 void ComputePassResourceUsageTracker::AddResourcesReferencedByBindGroup(BindGroupBase* group) { 187 for (BindingIndex index{0}; index < group->GetLayout()->GetBindingCount(); ++index) { 188 const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(index); 189 190 switch (bindingInfo.bindingType) { 191 case BindingInfoType::Buffer: { 192 mUsage.referencedBuffers.insert(group->GetBindingAsBufferBinding(index).buffer); 193 break; 194 } 195 196 case BindingInfoType::Texture: { 197 mUsage.referencedTextures.insert( 198 group->GetBindingAsTextureView(index)->GetTexture()); 199 break; 200 } 201 202 case BindingInfoType::ExternalTexture: { 203 ExternalTextureBase* externalTexture = 204 group->GetBindingAsExternalTexture(index); 205 const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& textureViews = 206 externalTexture->GetTextureViews(); 207 208 // Only single-plane formats are supported right now, so assert only one 209 // view exists. 210 ASSERT(textureViews[1].Get() == nullptr); 211 ASSERT(textureViews[2].Get() == nullptr); 212 213 mUsage.referencedExternalTextures.insert(externalTexture); 214 mUsage.referencedTextures.insert(textureViews[0].Get()->GetTexture()); 215 break; 216 } 217 218 case BindingInfoType::StorageTexture: 219 case BindingInfoType::Sampler: 220 break; 221 } 222 } 223 } 224 AcquireResourceUsage()225 ComputePassResourceUsage ComputePassResourceUsageTracker::AcquireResourceUsage() { 226 return std::move(mUsage); 227 } 228 AcquireResourceUsage()229 RenderPassResourceUsage RenderPassResourceUsageTracker::AcquireResourceUsage() { 230 RenderPassResourceUsage result; 231 *static_cast<SyncScopeResourceUsage*>(&result) = AcquireSyncScopeUsage(); 232 233 result.querySets.reserve(mQueryAvailabilities.size()); 234 result.queryAvailabilities.reserve(mQueryAvailabilities.size()); 235 236 for (auto& it : mQueryAvailabilities) { 237 result.querySets.push_back(it.first); 238 result.queryAvailabilities.push_back(std::move(it.second)); 239 } 240 241 mQueryAvailabilities.clear(); 242 243 return result; 244 } 245 TrackQueryAvailability(QuerySetBase * querySet,uint32_t queryIndex)246 void RenderPassResourceUsageTracker::TrackQueryAvailability(QuerySetBase* querySet, 247 uint32_t queryIndex) { 248 // The query availability only needs to be tracked again on render passes for checking 249 // query overwrite on render pass and resetting query sets on the Vulkan backend. 250 DAWN_ASSERT(querySet != nullptr); 251 252 // Gets the iterator for that querySet or create a new vector of bool set to false 253 // if the querySet wasn't registered. 254 auto it = mQueryAvailabilities.emplace(querySet, querySet->GetQueryCount()).first; 255 it->second[queryIndex] = true; 256 } 257 GetQueryAvailabilityMap() const258 const QueryAvailabilityMap& RenderPassResourceUsageTracker::GetQueryAvailabilityMap() const { 259 return mQueryAvailabilities; 260 } 261 262 } // namespace dawn_native 263