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/BindGroupLayoutD3D12.h" 16 17 #include "common/BitSetIterator.h" 18 #include "dawn_native/d3d12/BindGroupD3D12.h" 19 #include "dawn_native/d3d12/DeviceD3D12.h" 20 #include "dawn_native/d3d12/SamplerHeapCacheD3D12.h" 21 #include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h" 22 23 namespace dawn_native { namespace d3d12 { 24 namespace { WGPUBindingInfoToDescriptorRangeType(const BindingInfo & bindingInfo)25 D3D12_DESCRIPTOR_RANGE_TYPE WGPUBindingInfoToDescriptorRangeType( 26 const BindingInfo& bindingInfo) { 27 switch (bindingInfo.bindingType) { 28 case BindingInfoType::Buffer: 29 switch (bindingInfo.buffer.type) { 30 case wgpu::BufferBindingType::Uniform: 31 return D3D12_DESCRIPTOR_RANGE_TYPE_CBV; 32 case wgpu::BufferBindingType::Storage: 33 case kInternalStorageBufferBinding: 34 return D3D12_DESCRIPTOR_RANGE_TYPE_UAV; 35 case wgpu::BufferBindingType::ReadOnlyStorage: 36 return D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 37 case wgpu::BufferBindingType::Undefined: 38 UNREACHABLE(); 39 } 40 41 case BindingInfoType::Sampler: 42 return D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; 43 44 case BindingInfoType::Texture: 45 case BindingInfoType::ExternalTexture: 46 return D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 47 48 case BindingInfoType::StorageTexture: 49 switch (bindingInfo.storageTexture.access) { 50 case wgpu::StorageTextureAccess::WriteOnly: 51 return D3D12_DESCRIPTOR_RANGE_TYPE_UAV; 52 case wgpu::StorageTextureAccess::Undefined: 53 UNREACHABLE(); 54 } 55 } 56 } 57 } // anonymous namespace 58 59 // static Create(Device * device,const BindGroupLayoutDescriptor * descriptor,PipelineCompatibilityToken pipelineCompatibilityToken)60 Ref<BindGroupLayout> BindGroupLayout::Create( 61 Device* device, 62 const BindGroupLayoutDescriptor* descriptor, 63 PipelineCompatibilityToken pipelineCompatibilityToken) { 64 return AcquireRef(new BindGroupLayout(device, descriptor, pipelineCompatibilityToken)); 65 } 66 BindGroupLayout(Device * device,const BindGroupLayoutDescriptor * descriptor,PipelineCompatibilityToken pipelineCompatibilityToken)67 BindGroupLayout::BindGroupLayout(Device* device, 68 const BindGroupLayoutDescriptor* descriptor, 69 PipelineCompatibilityToken pipelineCompatibilityToken) 70 : BindGroupLayoutBase(device, descriptor, pipelineCompatibilityToken), 71 mDescriptorHeapOffsets(GetBindingCount()), 72 mShaderRegisters(GetBindingCount()), 73 mCbvUavSrvDescriptorCount(0), 74 mSamplerDescriptorCount(0), 75 mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) { 76 for (BindingIndex bindingIndex{0}; bindingIndex < GetBindingCount(); ++bindingIndex) { 77 const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex); 78 79 D3D12_DESCRIPTOR_RANGE_TYPE descriptorRangeType = 80 WGPUBindingInfoToDescriptorRangeType(bindingInfo); 81 82 // TODO(dawn:728) In the future, special handling will be needed for external textures 83 // here because they encompass multiple views. 84 mShaderRegisters[bindingIndex] = uint32_t(bindingInfo.binding); 85 86 if (bindingIndex < GetDynamicBufferCount()) { 87 continue; 88 } 89 90 // For dynamic resources, Dawn uses root descriptor in D3D12 backend. So there is no 91 // need to allocate the descriptor from descriptor heap or create descriptor ranges. 92 ASSERT(!bindingInfo.buffer.hasDynamicOffset); 93 94 // TODO(dawn:728) In the future, special handling will be needed for external textures 95 // here because they encompass multiple views. 96 mDescriptorHeapOffsets[bindingIndex] = 97 descriptorRangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER 98 ? mSamplerDescriptorCount++ 99 : mCbvUavSrvDescriptorCount++; 100 101 D3D12_DESCRIPTOR_RANGE range; 102 range.RangeType = descriptorRangeType; 103 range.NumDescriptors = 1; 104 range.BaseShaderRegister = GetShaderRegister(bindingIndex); 105 range.RegisterSpace = kRegisterSpacePlaceholder; 106 range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 107 108 std::vector<D3D12_DESCRIPTOR_RANGE>& descriptorRanges = 109 descriptorRangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER 110 ? mSamplerDescriptorRanges 111 : mCbvUavSrvDescriptorRanges; 112 113 // Try to join this range with the previous one, if the current range is a continuation 114 // of the previous. This is possible because the binding infos in the base type are 115 // sorted. 116 if (descriptorRanges.size() >= 2) { 117 D3D12_DESCRIPTOR_RANGE& previous = descriptorRanges.back(); 118 if (previous.RangeType == range.RangeType && 119 previous.BaseShaderRegister + previous.NumDescriptors == 120 range.BaseShaderRegister) { 121 previous.NumDescriptors += range.NumDescriptors; 122 continue; 123 } 124 } 125 126 descriptorRanges.push_back(range); 127 } 128 129 mViewAllocator = device->GetViewStagingDescriptorAllocator(GetCbvUavSrvDescriptorCount()); 130 mSamplerAllocator = 131 device->GetSamplerStagingDescriptorAllocator(GetSamplerDescriptorCount()); 132 } 133 AllocateBindGroup(Device * device,const BindGroupDescriptor * descriptor)134 ResultOrError<Ref<BindGroup>> BindGroupLayout::AllocateBindGroup( 135 Device* device, 136 const BindGroupDescriptor* descriptor) { 137 uint32_t viewSizeIncrement = 0; 138 CPUDescriptorHeapAllocation viewAllocation; 139 if (GetCbvUavSrvDescriptorCount() > 0) { 140 DAWN_TRY_ASSIGN(viewAllocation, mViewAllocator->AllocateCPUDescriptors()); 141 viewSizeIncrement = mViewAllocator->GetSizeIncrement(); 142 } 143 144 Ref<BindGroup> bindGroup = AcquireRef<BindGroup>( 145 mBindGroupAllocator.Allocate(device, descriptor, viewSizeIncrement, viewAllocation)); 146 147 if (GetSamplerDescriptorCount() > 0) { 148 Ref<SamplerHeapCacheEntry> samplerHeapCacheEntry; 149 DAWN_TRY_ASSIGN(samplerHeapCacheEntry, device->GetSamplerHeapCache()->GetOrCreate( 150 bindGroup.Get(), mSamplerAllocator)); 151 bindGroup->SetSamplerAllocationEntry(std::move(samplerHeapCacheEntry)); 152 } 153 154 return bindGroup; 155 } 156 DeallocateBindGroup(BindGroup * bindGroup,CPUDescriptorHeapAllocation * viewAllocation)157 void BindGroupLayout::DeallocateBindGroup(BindGroup* bindGroup, 158 CPUDescriptorHeapAllocation* viewAllocation) { 159 if (viewAllocation->IsValid()) { 160 mViewAllocator->Deallocate(viewAllocation); 161 } 162 163 mBindGroupAllocator.Deallocate(bindGroup); 164 } 165 GetDescriptorHeapOffsets() const166 ityp::span<BindingIndex, const uint32_t> BindGroupLayout::GetDescriptorHeapOffsets() const { 167 return {mDescriptorHeapOffsets.data(), mDescriptorHeapOffsets.size()}; 168 } 169 GetShaderRegister(BindingIndex bindingIndex) const170 uint32_t BindGroupLayout::GetShaderRegister(BindingIndex bindingIndex) const { 171 return mShaderRegisters[bindingIndex]; 172 } 173 GetCbvUavSrvDescriptorCount() const174 uint32_t BindGroupLayout::GetCbvUavSrvDescriptorCount() const { 175 return mCbvUavSrvDescriptorCount; 176 } 177 GetSamplerDescriptorCount() const178 uint32_t BindGroupLayout::GetSamplerDescriptorCount() const { 179 return mSamplerDescriptorCount; 180 } 181 GetCbvUavSrvDescriptorRanges() const182 const std::vector<D3D12_DESCRIPTOR_RANGE>& BindGroupLayout::GetCbvUavSrvDescriptorRanges() 183 const { 184 return mCbvUavSrvDescriptorRanges; 185 } 186 GetSamplerDescriptorRanges() const187 const std::vector<D3D12_DESCRIPTOR_RANGE>& BindGroupLayout::GetSamplerDescriptorRanges() const { 188 return mSamplerDescriptorRanges; 189 } 190 191 }} // namespace dawn_native::d3d12 192