blob: 28719de8b70eba1e76a0edb22945e75439e18231 [file] [log] [blame] [edit]
// Copyright 2017 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
#include "common/BitSetIterator.h"
#include "dawn_native/d3d12/BindGroupD3D12.h"
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/SamplerHeapCacheD3D12.h"
#include "dawn_native/d3d12/StagingDescriptorAllocatorD3D12.h"
namespace dawn_native { namespace d3d12 {
namespace {
BindGroupLayout::DescriptorType WGPUBindingInfoToDescriptorType(
const BindingInfo& bindingInfo) {
switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer:
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
return BindGroupLayout::DescriptorType::CBV;
case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
return BindGroupLayout::DescriptorType::UAV;
case wgpu::BufferBindingType::ReadOnlyStorage:
return BindGroupLayout::DescriptorType::SRV;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
case BindingInfoType::Sampler:
return BindGroupLayout::DescriptorType::Sampler;
case BindingInfoType::Texture:
case BindingInfoType::ExternalTexture:
return BindGroupLayout::DescriptorType::SRV;
case BindingInfoType::StorageTexture:
switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly:
return BindGroupLayout::DescriptorType::SRV;
case wgpu::StorageTextureAccess::WriteOnly:
return BindGroupLayout::DescriptorType::UAV;
case wgpu::StorageTextureAccess::Undefined:
UNREACHABLE();
}
}
}
} // anonymous namespace
// static
Ref<BindGroupLayout> BindGroupLayout::Create(Device* device,
const BindGroupLayoutDescriptor* descriptor) {
return AcquireRef(new BindGroupLayout(device, descriptor));
}
BindGroupLayout::BindGroupLayout(Device* device, const BindGroupLayoutDescriptor* descriptor)
: BindGroupLayoutBase(device, descriptor),
mBindingOffsets(GetBindingCount()),
mDescriptorCounts{},
mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) {
for (BindingIndex bindingIndex = GetDynamicBufferCount(); bindingIndex < GetBindingCount();
++bindingIndex) {
const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex);
// For dynamic resources, Dawn uses root descriptor in D3D12 backend.
// So there is no need to allocate the descriptor from descriptor heap.
// This loop starts after the dynamic buffer indices to skip counting
// dynamic resources in calculating the size of the descriptor heap.
ASSERT(!bindingInfo.buffer.hasDynamicOffset);
// TODO(dawn:728) In the future, special handling will be needed for external textures
// here because they encompass multiple views.
DescriptorType descriptorType = WGPUBindingInfoToDescriptorType(bindingInfo);
mBindingOffsets[bindingIndex] = mDescriptorCounts[descriptorType]++;
}
auto SetDescriptorRange = [&](uint32_t index, uint32_t count, uint32_t* baseRegister,
D3D12_DESCRIPTOR_RANGE_TYPE type) -> bool {
if (count == 0) {
return false;
}
auto& range = mRanges[index];
range.RangeType = type;
range.NumDescriptors = count;
range.RegisterSpace = 0;
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
range.BaseShaderRegister = *baseRegister;
*baseRegister += count;
// These ranges will be copied and range.BaseShaderRegister will be set in
// d3d12::PipelineLayout to account for bind group register offsets
return true;
};
uint32_t rangeIndex = 0;
uint32_t baseRegister = 0;
std::array<uint32_t, DescriptorType::Count> descriptorOffsets;
// Ranges 0-2 contain the CBV, UAV, and SRV ranges, if they exist, tightly packed
// Range 3 contains the Sampler range, if there is one
if (SetDescriptorRange(rangeIndex, mDescriptorCounts[CBV], &baseRegister,
D3D12_DESCRIPTOR_RANGE_TYPE_CBV)) {
descriptorOffsets[CBV] = mRanges[rangeIndex++].BaseShaderRegister;
}
if (SetDescriptorRange(rangeIndex, mDescriptorCounts[UAV], &baseRegister,
D3D12_DESCRIPTOR_RANGE_TYPE_UAV)) {
descriptorOffsets[UAV] = mRanges[rangeIndex++].BaseShaderRegister;
}
if (SetDescriptorRange(rangeIndex, mDescriptorCounts[SRV], &baseRegister,
D3D12_DESCRIPTOR_RANGE_TYPE_SRV)) {
descriptorOffsets[SRV] = mRanges[rangeIndex++].BaseShaderRegister;
}
uint32_t zero = 0;
SetDescriptorRange(Sampler, mDescriptorCounts[Sampler], &zero,
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER);
descriptorOffsets[Sampler] = 0;
for (BindingIndex bindingIndex{0}; bindingIndex < GetBindingCount(); ++bindingIndex) {
const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex);
if (bindingInfo.bindingType == BindingInfoType::Buffer &&
bindingInfo.buffer.hasDynamicOffset) {
// Dawn is using values in mBindingOffsets to decide register number in HLSL.
// Root descriptor needs to set this value to set correct register number in
// generated HLSL shader.
mBindingOffsets[bindingIndex] = baseRegister++;
continue;
}
// TODO(dawn:728) In the future, special handling will be needed here for external
// textures because they encompass multiple views.
DescriptorType descriptorType = WGPUBindingInfoToDescriptorType(bindingInfo);
mBindingOffsets[bindingIndex] += descriptorOffsets[descriptorType];
}
mViewAllocator = device->GetViewStagingDescriptorAllocator(GetCbvUavSrvDescriptorCount());
mSamplerAllocator =
device->GetSamplerStagingDescriptorAllocator(GetSamplerDescriptorCount());
}
ResultOrError<Ref<BindGroup>> BindGroupLayout::AllocateBindGroup(
Device* device,
const BindGroupDescriptor* descriptor) {
uint32_t viewSizeIncrement = 0;
CPUDescriptorHeapAllocation viewAllocation;
if (GetCbvUavSrvDescriptorCount() > 0) {
DAWN_TRY_ASSIGN(viewAllocation, mViewAllocator->AllocateCPUDescriptors());
viewSizeIncrement = mViewAllocator->GetSizeIncrement();
}
Ref<BindGroup> bindGroup = AcquireRef<BindGroup>(
mBindGroupAllocator.Allocate(device, descriptor, viewSizeIncrement, viewAllocation));
if (GetSamplerDescriptorCount() > 0) {
Ref<SamplerHeapCacheEntry> samplerHeapCacheEntry;
DAWN_TRY_ASSIGN(samplerHeapCacheEntry, device->GetSamplerHeapCache()->GetOrCreate(
bindGroup.Get(), mSamplerAllocator));
bindGroup->SetSamplerAllocationEntry(std::move(samplerHeapCacheEntry));
}
return bindGroup;
}
void BindGroupLayout::DeallocateBindGroup(BindGroup* bindGroup,
CPUDescriptorHeapAllocation* viewAllocation) {
if (viewAllocation->IsValid()) {
mViewAllocator->Deallocate(viewAllocation);
}
mBindGroupAllocator.Deallocate(bindGroup);
}
ityp::span<BindingIndex, const uint32_t> BindGroupLayout::GetBindingOffsets() const {
return {mBindingOffsets.data(), mBindingOffsets.size()};
}
uint32_t BindGroupLayout::GetCbvUavSrvDescriptorTableSize() const {
return (static_cast<uint32_t>(mDescriptorCounts[CBV] > 0) +
static_cast<uint32_t>(mDescriptorCounts[UAV] > 0) +
static_cast<uint32_t>(mDescriptorCounts[SRV] > 0));
}
uint32_t BindGroupLayout::GetSamplerDescriptorTableSize() const {
return mDescriptorCounts[Sampler] > 0;
}
uint32_t BindGroupLayout::GetCbvUavSrvDescriptorCount() const {
return mDescriptorCounts[CBV] + mDescriptorCounts[UAV] + mDescriptorCounts[SRV];
}
uint32_t BindGroupLayout::GetSamplerDescriptorCount() const {
return mDescriptorCounts[Sampler];
}
const D3D12_DESCRIPTOR_RANGE* BindGroupLayout::GetCbvUavSrvDescriptorRanges() const {
return mRanges;
}
const D3D12_DESCRIPTOR_RANGE* BindGroupLayout::GetSamplerDescriptorRanges() const {
return &mRanges[Sampler];
}
}} // namespace dawn_native::d3d12