Vulkan: Reuse descriptor pools
This changes puts descriptor pools in the BindGroupLayout so that they can be reused between descriptors with the same layout. This makes the DrawCallPerf.Run/Vulkan_NoReuseBindGroups benchmark go from 1400ns to 800ns per run. BUG=dawn::256 Change-Id: Ia9baf7f998d9ff4d552e255c80069b67c6a9ac40 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/12920 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
dbf9f7c39c
commit
0558f99119
2
BUILD.gn
2
BUILD.gn
|
@ -426,6 +426,8 @@ source_set("libdawn_native_sources") {
|
||||||
"src/dawn_native/vulkan/CommandRecordingContext.h",
|
"src/dawn_native/vulkan/CommandRecordingContext.h",
|
||||||
"src/dawn_native/vulkan/ComputePipelineVk.cpp",
|
"src/dawn_native/vulkan/ComputePipelineVk.cpp",
|
||||||
"src/dawn_native/vulkan/ComputePipelineVk.h",
|
"src/dawn_native/vulkan/ComputePipelineVk.h",
|
||||||
|
"src/dawn_native/vulkan/DescriptorSetService.cpp",
|
||||||
|
"src/dawn_native/vulkan/DescriptorSetService.h",
|
||||||
"src/dawn_native/vulkan/DeviceVk.cpp",
|
"src/dawn_native/vulkan/DeviceVk.cpp",
|
||||||
"src/dawn_native/vulkan/DeviceVk.h",
|
"src/dawn_native/vulkan/DeviceVk.h",
|
||||||
"src/dawn_native/vulkan/ExternalHandle.h",
|
"src/dawn_native/vulkan/ExternalHandle.h",
|
||||||
|
|
|
@ -221,7 +221,7 @@ namespace dawn_native {
|
||||||
return new BindGroupBase(device, ObjectBase::kError);
|
return new BindGroupBase(device, ObjectBase::kError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const BindGroupLayoutBase* BindGroupBase::GetLayout() const {
|
BindGroupLayoutBase* BindGroupBase::GetLayout() {
|
||||||
ASSERT(!IsError());
|
ASSERT(!IsError());
|
||||||
return mLayout.Get();
|
return mLayout.Get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace dawn_native {
|
||||||
|
|
||||||
static BindGroupBase* MakeError(DeviceBase* device);
|
static BindGroupBase* MakeError(DeviceBase* device);
|
||||||
|
|
||||||
const BindGroupLayoutBase* GetLayout() const;
|
BindGroupLayoutBase* GetLayout();
|
||||||
BufferBinding GetBindingAsBufferBinding(size_t binding);
|
BufferBinding GetBindingAsBufferBinding(size_t binding);
|
||||||
SamplerBase* GetBindingAsSampler(size_t binding);
|
SamplerBase* GetBindingAsSampler(size_t binding);
|
||||||
TextureViewBase* GetBindingAsTextureView(size_t binding);
|
TextureViewBase* GetBindingAsTextureView(size_t binding);
|
||||||
|
|
|
@ -15,9 +15,13 @@
|
||||||
#include "dawn_native/vulkan/BindGroupLayoutVk.h"
|
#include "dawn_native/vulkan/BindGroupLayoutVk.h"
|
||||||
|
|
||||||
#include "common/BitSetIterator.h"
|
#include "common/BitSetIterator.h"
|
||||||
|
#include "dawn_native/vulkan/DescriptorSetService.h"
|
||||||
#include "dawn_native/vulkan/DeviceVk.h"
|
#include "dawn_native/vulkan/DeviceVk.h"
|
||||||
|
#include "dawn_native/vulkan/FencedDeleter.h"
|
||||||
#include "dawn_native/vulkan/VulkanError.h"
|
#include "dawn_native/vulkan/VulkanError.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace dawn_native { namespace vulkan {
|
namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -72,7 +76,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError BindGroupLayout::Initialize() {
|
MaybeError BindGroupLayout::Initialize() {
|
||||||
const auto& info = GetBindingInfo();
|
const LayoutBindingInfo& info = GetBindingInfo();
|
||||||
|
|
||||||
// Compute the bindings that will be chained in the DescriptorSetLayout create info. We add
|
// Compute the bindings that will be chained in the DescriptorSetLayout create info. We add
|
||||||
// one entry per binding set. This might be optimized by computing continuous ranges of
|
// one entry per binding set. This might be optimized by computing continuous ranges of
|
||||||
|
@ -80,13 +84,13 @@ namespace dawn_native { namespace vulkan {
|
||||||
uint32_t numBindings = 0;
|
uint32_t numBindings = 0;
|
||||||
std::array<VkDescriptorSetLayoutBinding, kMaxBindingsPerGroup> bindings;
|
std::array<VkDescriptorSetLayoutBinding, kMaxBindingsPerGroup> bindings;
|
||||||
for (uint32_t bindingIndex : IterateBitSet(info.mask)) {
|
for (uint32_t bindingIndex : IterateBitSet(info.mask)) {
|
||||||
auto& binding = bindings[numBindings];
|
VkDescriptorSetLayoutBinding* binding = &bindings[numBindings];
|
||||||
binding.binding = bindingIndex;
|
binding->binding = bindingIndex;
|
||||||
binding.descriptorType =
|
binding->descriptorType =
|
||||||
VulkanDescriptorType(info.types[bindingIndex], info.hasDynamicOffset[bindingIndex]);
|
VulkanDescriptorType(info.types[bindingIndex], info.hasDynamicOffset[bindingIndex]);
|
||||||
binding.descriptorCount = 1;
|
binding->descriptorCount = 1;
|
||||||
binding.stageFlags = VulkanShaderStageFlags(info.visibilities[bindingIndex]);
|
binding->stageFlags = VulkanShaderStageFlags(info.visibilities[bindingIndex]);
|
||||||
binding.pImmutableSamplers = nullptr;
|
binding->pImmutableSamplers = nullptr;
|
||||||
|
|
||||||
numBindings++;
|
numBindings++;
|
||||||
}
|
}
|
||||||
|
@ -99,73 +103,113 @@ namespace dawn_native { namespace vulkan {
|
||||||
createInfo.pBindings = bindings.data();
|
createInfo.pBindings = bindings.data();
|
||||||
|
|
||||||
Device* device = ToBackend(GetDevice());
|
Device* device = ToBackend(GetDevice());
|
||||||
return CheckVkSuccess(device->fn.CreateDescriptorSetLayout(device->GetVkDevice(),
|
DAWN_TRY(CheckVkSuccess(device->fn.CreateDescriptorSetLayout(
|
||||||
&createInfo, nullptr, &mHandle),
|
device->GetVkDevice(), &createInfo, nullptr, &mHandle),
|
||||||
"CreateDescriptorSetLayout");
|
"CreateDescriptorSetLayout"));
|
||||||
|
|
||||||
|
// Compute the size of descriptor pools used for this layout.
|
||||||
|
std::map<VkDescriptorType, uint32_t> descriptorCountPerType;
|
||||||
|
|
||||||
|
for (uint32_t bindingIndex : IterateBitSet(info.mask)) {
|
||||||
|
VkDescriptorType vulkanType =
|
||||||
|
VulkanDescriptorType(info.types[bindingIndex], info.hasDynamicOffset[bindingIndex]);
|
||||||
|
|
||||||
|
// map::operator[] will return 0 if the key doesn't exist.
|
||||||
|
descriptorCountPerType[vulkanType]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPoolSizes.reserve(descriptorCountPerType.size());
|
||||||
|
for (const auto& it : descriptorCountPerType) {
|
||||||
|
mPoolSizes.push_back(VkDescriptorPoolSize{it.first, it.second});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroupLayout::~BindGroupLayout() {
|
BindGroupLayout::~BindGroupLayout() {
|
||||||
|
Device* device = ToBackend(GetDevice());
|
||||||
|
|
||||||
// DescriptorSetLayout aren't used by execution on the GPU and can be deleted at any time,
|
// DescriptorSetLayout aren't used by execution on the GPU and can be deleted at any time,
|
||||||
// so we destroy mHandle immediately instead of using the FencedDeleter
|
// so we destroy mHandle immediately instead of using the FencedDeleter
|
||||||
if (mHandle != VK_NULL_HANDLE) {
|
if (mHandle != VK_NULL_HANDLE) {
|
||||||
Device* device = ToBackend(GetDevice());
|
|
||||||
device->fn.DestroyDescriptorSetLayout(device->GetVkDevice(), mHandle, nullptr);
|
device->fn.DestroyDescriptorSetLayout(device->GetVkDevice(), mHandle, nullptr);
|
||||||
mHandle = VK_NULL_HANDLE;
|
mHandle = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FencedDeleter* deleter = device->GetFencedDeleter();
|
||||||
|
for (const SingleDescriptorSetAllocation& allocation : mAllocations) {
|
||||||
|
deleter->DeleteWhenUnused(allocation.pool);
|
||||||
|
}
|
||||||
|
mAllocations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSetLayout BindGroupLayout::GetHandle() const {
|
VkDescriptorSetLayout BindGroupLayout::GetHandle() const {
|
||||||
return mHandle;
|
return mHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroupLayout::PoolSizeSpec BindGroupLayout::ComputePoolSizes(uint32_t* numPoolSizes) const {
|
ResultOrError<DescriptorSetAllocation> BindGroupLayout::AllocateOneSet() {
|
||||||
uint32_t numSizes = 0;
|
Device* device = ToBackend(GetDevice());
|
||||||
PoolSizeSpec result{};
|
|
||||||
|
|
||||||
// Defines an array and indices into it that will contain for each sampler type at which
|
// Reuse a previous allocation if available.
|
||||||
// position it is in the PoolSizeSpec, or -1 if it isn't present yet.
|
if (!mAvailableAllocations.empty()) {
|
||||||
enum DescriptorType {
|
size_t index = mAvailableAllocations.back();
|
||||||
UNIFORM_BUFFER,
|
mAvailableAllocations.pop_back();
|
||||||
SAMPLER,
|
return {{index, mAllocations[index].set}};
|
||||||
SAMPLED_IMAGE,
|
|
||||||
STORAGE_BUFFER,
|
|
||||||
MAX_TYPE,
|
|
||||||
};
|
|
||||||
static_assert(MAX_TYPE == kMaxPoolSizesNeeded, "");
|
|
||||||
auto ToDescriptorType = [](wgpu::BindingType type) -> DescriptorType {
|
|
||||||
switch (type) {
|
|
||||||
case wgpu::BindingType::UniformBuffer:
|
|
||||||
return UNIFORM_BUFFER;
|
|
||||||
case wgpu::BindingType::Sampler:
|
|
||||||
return SAMPLER;
|
|
||||||
case wgpu::BindingType::SampledTexture:
|
|
||||||
return SAMPLED_IMAGE;
|
|
||||||
case wgpu::BindingType::StorageBuffer:
|
|
||||||
return STORAGE_BUFFER;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::array<int, MAX_TYPE> descriptorTypeIndex;
|
|
||||||
descriptorTypeIndex.fill(-1);
|
|
||||||
|
|
||||||
const auto& info = GetBindingInfo();
|
|
||||||
for (uint32_t bindingIndex : IterateBitSet(info.mask)) {
|
|
||||||
DescriptorType type = ToDescriptorType(info.types[bindingIndex]);
|
|
||||||
|
|
||||||
if (descriptorTypeIndex[type] == -1) {
|
|
||||||
descriptorTypeIndex[type] = numSizes;
|
|
||||||
result[numSizes].type = VulkanDescriptorType(info.types[bindingIndex],
|
|
||||||
info.hasDynamicOffset[bindingIndex]);
|
|
||||||
result[numSizes].descriptorCount = 1;
|
|
||||||
numSizes++;
|
|
||||||
} else {
|
|
||||||
result[descriptorTypeIndex[type]].descriptorCount++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*numPoolSizes = numSizes;
|
// Create a pool to hold our descriptor set.
|
||||||
return result;
|
// TODO(cwallez@chromium.org): This horribly inefficient, have more than one descriptor
|
||||||
|
// set per pool.
|
||||||
|
VkDescriptorPoolCreateInfo createInfo;
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
createInfo.pNext = nullptr;
|
||||||
|
createInfo.flags = 0;
|
||||||
|
createInfo.maxSets = 1;
|
||||||
|
createInfo.poolSizeCount = static_cast<uint32_t>(mPoolSizes.size());
|
||||||
|
createInfo.pPoolSizes = mPoolSizes.data();
|
||||||
|
|
||||||
|
VkDescriptorPool descriptorPool;
|
||||||
|
DAWN_TRY(CheckVkSuccess(device->fn.CreateDescriptorPool(device->GetVkDevice(), &createInfo,
|
||||||
|
nullptr, &descriptorPool),
|
||||||
|
"CreateDescriptorPool"));
|
||||||
|
|
||||||
|
// Allocate our single set.
|
||||||
|
VkDescriptorSetAllocateInfo allocateInfo;
|
||||||
|
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
allocateInfo.pNext = nullptr;
|
||||||
|
allocateInfo.descriptorPool = descriptorPool;
|
||||||
|
allocateInfo.descriptorSetCount = 1;
|
||||||
|
allocateInfo.pSetLayouts = &mHandle;
|
||||||
|
|
||||||
|
VkDescriptorSet descriptorSet;
|
||||||
|
MaybeError result = CheckVkSuccess(
|
||||||
|
device->fn.AllocateDescriptorSets(device->GetVkDevice(), &allocateInfo, &descriptorSet),
|
||||||
|
"AllocateDescriptorSets");
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
// On an error we can destroy the pool immediately because no command references it.
|
||||||
|
device->fn.DestroyDescriptorPool(device->GetVkDevice(), descriptorPool, nullptr);
|
||||||
|
return result.AcquireError();
|
||||||
|
}
|
||||||
|
|
||||||
|
mAllocations.push_back({descriptorPool, descriptorSet});
|
||||||
|
return {{mAllocations.size() - 1, descriptorSet}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BindGroupLayout::Deallocate(DescriptorSetAllocation* allocation) {
|
||||||
|
// We can't reuse the descriptor set right away because the Vulkan spec says in the
|
||||||
|
// documentation for vkCmdBindDescriptorSets that the set may be consumed any time between
|
||||||
|
// host execution of the command and the end of the draw/dispatch.
|
||||||
|
ToBackend(GetDevice())
|
||||||
|
->GetDescriptorSetService()
|
||||||
|
->AddDeferredDeallocation(this, allocation->index);
|
||||||
|
|
||||||
|
// Clear the content of allocation so that use after frees are more visible.
|
||||||
|
*allocation = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindGroupLayout::FinishDeallocation(size_t index) {
|
||||||
|
mAvailableAllocations.push_back(index);
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace dawn_native::vulkan
|
}} // namespace dawn_native::vulkan
|
||||||
|
|
|
@ -19,12 +19,32 @@
|
||||||
|
|
||||||
#include "common/vulkan_platform.h"
|
#include "common/vulkan_platform.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace dawn_native { namespace vulkan {
|
namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
|
|
||||||
VkDescriptorType VulkanDescriptorType(wgpu::BindingType type, bool isDynamic);
|
VkDescriptorType VulkanDescriptorType(wgpu::BindingType type, bool isDynamic);
|
||||||
|
|
||||||
|
// Contains a descriptor set along with data necessary to track its allocation.
|
||||||
|
struct DescriptorSetAllocation {
|
||||||
|
size_t index = 0;
|
||||||
|
VkDescriptorSet set = VK_NULL_HANDLE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// In Vulkan descriptor pools have to be sized to an exact number of descriptors. This means
|
||||||
|
// it's hard to have something where we can mix different types of descriptor sets because
|
||||||
|
// we don't know if their vector of number of descriptors will be similar.
|
||||||
|
//
|
||||||
|
// That's why that in addition to containing the VkDescriptorSetLayout to create
|
||||||
|
// VkDescriptorSets for its bindgroups, the layout also acts as an allocator for the descriptor
|
||||||
|
// sets.
|
||||||
|
//
|
||||||
|
// The allocations is done with one pool per descriptor set, which is inefficient, but at least
|
||||||
|
// the pools are reused when no longer used. Minimizing the number of descriptor pool allocation
|
||||||
|
// is important because creating them can incur GPU memory allocation which is usually an
|
||||||
|
// expensive syscall.
|
||||||
class BindGroupLayout : public BindGroupLayoutBase {
|
class BindGroupLayout : public BindGroupLayoutBase {
|
||||||
public:
|
public:
|
||||||
static ResultOrError<BindGroupLayout*> Create(Device* device,
|
static ResultOrError<BindGroupLayout*> Create(Device* device,
|
||||||
|
@ -33,14 +53,26 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
VkDescriptorSetLayout GetHandle() const;
|
VkDescriptorSetLayout GetHandle() const;
|
||||||
|
|
||||||
static constexpr size_t kMaxPoolSizesNeeded = 4;
|
ResultOrError<DescriptorSetAllocation> AllocateOneSet();
|
||||||
using PoolSizeSpec = std::array<VkDescriptorPoolSize, kMaxPoolSizesNeeded>;
|
void Deallocate(DescriptorSetAllocation* allocation);
|
||||||
PoolSizeSpec ComputePoolSizes(uint32_t* numPoolSizes) const;
|
|
||||||
|
// Interaction with the DescriptorSetService.
|
||||||
|
void FinishDeallocation(size_t index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using BindGroupLayoutBase::BindGroupLayoutBase;
|
using BindGroupLayoutBase::BindGroupLayoutBase;
|
||||||
MaybeError Initialize();
|
MaybeError Initialize();
|
||||||
|
|
||||||
|
std::vector<VkDescriptorPoolSize> mPoolSizes;
|
||||||
|
|
||||||
|
struct SingleDescriptorSetAllocation {
|
||||||
|
VkDescriptorPool pool = VK_NULL_HANDLE;
|
||||||
|
// Descriptor sets are freed when the pool is destroyed.
|
||||||
|
VkDescriptorSet set = VK_NULL_HANDLE;
|
||||||
|
};
|
||||||
|
std::vector<SingleDescriptorSetAllocation> mAllocations;
|
||||||
|
std::vector<size_t> mAvailableAllocations;
|
||||||
|
|
||||||
VkDescriptorSetLayout mHandle = VK_NULL_HANDLE;
|
VkDescriptorSetLayout mHandle = VK_NULL_HANDLE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,37 +36,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
MaybeError BindGroup::Initialize() {
|
MaybeError BindGroup::Initialize() {
|
||||||
Device* device = ToBackend(GetDevice());
|
Device* device = ToBackend(GetDevice());
|
||||||
|
|
||||||
// Create a pool to hold our descriptor set.
|
DAWN_TRY_ASSIGN(mAllocation, ToBackend(GetLayout())->AllocateOneSet());
|
||||||
// TODO(cwallez@chromium.org): This horribly inefficient, find a way to be better, for
|
|
||||||
// example by having one pool per bind group layout instead.
|
|
||||||
uint32_t numPoolSizes = 0;
|
|
||||||
auto poolSizes = ToBackend(GetLayout())->ComputePoolSizes(&numPoolSizes);
|
|
||||||
|
|
||||||
VkDescriptorPoolCreateInfo createInfo;
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
|
||||||
createInfo.pNext = nullptr;
|
|
||||||
createInfo.flags = 0;
|
|
||||||
createInfo.maxSets = 1;
|
|
||||||
createInfo.poolSizeCount = numPoolSizes;
|
|
||||||
createInfo.pPoolSizes = poolSizes.data();
|
|
||||||
|
|
||||||
DAWN_TRY(CheckVkSuccess(
|
|
||||||
device->fn.CreateDescriptorPool(device->GetVkDevice(), &createInfo, nullptr, &mPool),
|
|
||||||
"CreateDescriptorPool"));
|
|
||||||
|
|
||||||
// Now do the allocation of one descriptor set, this is very suboptimal too.
|
|
||||||
VkDescriptorSetLayout vkLayout = ToBackend(GetLayout())->GetHandle();
|
|
||||||
|
|
||||||
VkDescriptorSetAllocateInfo allocateInfo;
|
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
||||||
allocateInfo.pNext = nullptr;
|
|
||||||
allocateInfo.descriptorPool = mPool;
|
|
||||||
allocateInfo.descriptorSetCount = 1;
|
|
||||||
allocateInfo.pSetLayouts = &vkLayout;
|
|
||||||
|
|
||||||
DAWN_TRY(CheckVkSuccess(
|
|
||||||
device->fn.AllocateDescriptorSets(device->GetVkDevice(), &allocateInfo, &mHandle),
|
|
||||||
"AllocateDescriptorSets"));
|
|
||||||
|
|
||||||
// Now do a write of a single descriptor set with all possible chained data allocated on the
|
// Now do a write of a single descriptor set with all possible chained data allocated on the
|
||||||
// stack.
|
// stack.
|
||||||
|
@ -80,7 +50,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
auto& write = writes[numWrites];
|
auto& write = writes[numWrites];
|
||||||
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
write.pNext = nullptr;
|
write.pNext = nullptr;
|
||||||
write.dstSet = mHandle;
|
write.dstSet = mAllocation.set;
|
||||||
write.dstBinding = bindingIndex;
|
write.dstBinding = bindingIndex;
|
||||||
write.dstArrayElement = 0;
|
write.dstArrayElement = 0;
|
||||||
write.descriptorCount = 1;
|
write.descriptorCount = 1;
|
||||||
|
@ -108,7 +78,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex));
|
TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex));
|
||||||
|
|
||||||
writeImageInfo[numWrites].imageView = view->GetHandle();
|
writeImageInfo[numWrites].imageView = view->GetHandle();
|
||||||
// TODO(cwallez@chromium.org): This isn't true in general: if the image can has
|
// TODO(cwallez@chromium.org): This isn't true in general: if the image has
|
||||||
// two read-only usages one of which is Sampled. Works for now though :)
|
// two read-only usages one of which is Sampled. Works for now though :)
|
||||||
writeImageInfo[numWrites].imageLayout =
|
writeImageInfo[numWrites].imageLayout =
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
@ -123,6 +93,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
numWrites++;
|
numWrites++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(cwallez@chromium.org): Batch these updates
|
||||||
device->fn.UpdateDescriptorSets(device->GetVkDevice(), numWrites, writes.data(), 0,
|
device->fn.UpdateDescriptorSets(device->GetVkDevice(), numWrites, writes.data(), 0,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
|
@ -130,18 +101,11 @@ namespace dawn_native { namespace vulkan {
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroup::~BindGroup() {
|
BindGroup::~BindGroup() {
|
||||||
// The descriptor set doesn't need to be delete because it's done implicitly when the
|
ToBackend(GetLayout())->Deallocate(&mAllocation);
|
||||||
// descriptor pool is destroyed.
|
|
||||||
mHandle = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
if (mPool != VK_NULL_HANDLE) {
|
|
||||||
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(mPool);
|
|
||||||
mPool = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSet BindGroup::GetHandle() const {
|
VkDescriptorSet BindGroup::GetHandle() const {
|
||||||
return mHandle;
|
return mAllocation.set;
|
||||||
}
|
}
|
||||||
|
|
||||||
}} // namespace dawn_native::vulkan
|
}} // namespace dawn_native::vulkan
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "dawn_native/BindGroup.h"
|
#include "dawn_native/BindGroup.h"
|
||||||
|
|
||||||
#include "common/vulkan_platform.h"
|
#include "dawn_native/vulkan/BindGroupLayoutVk.h"
|
||||||
|
|
||||||
namespace dawn_native { namespace vulkan {
|
namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
|
@ -35,8 +35,9 @@ namespace dawn_native { namespace vulkan {
|
||||||
using BindGroupBase::BindGroupBase;
|
using BindGroupBase::BindGroupBase;
|
||||||
MaybeError Initialize();
|
MaybeError Initialize();
|
||||||
|
|
||||||
VkDescriptorPool mPool = VK_NULL_HANDLE;
|
// The descriptor set in this allocation outlives the BindGroup because it is owned by
|
||||||
VkDescriptorSet mHandle = VK_NULL_HANDLE;
|
// the BindGroupLayout which is referenced by the BindGroup.
|
||||||
|
DescriptorSetAllocation mAllocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace dawn_native::vulkan
|
}} // namespace dawn_native::vulkan
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2019 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/vulkan/DescriptorSetService.h"
|
||||||
|
|
||||||
|
#include "dawn_native/vulkan/BindGroupLayoutVk.h"
|
||||||
|
#include "dawn_native/vulkan/DeviceVk.h"
|
||||||
|
|
||||||
|
namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
|
DescriptorSetService::DescriptorSetService(Device* device) : mDevice(device) {
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorSetService::~DescriptorSetService() {
|
||||||
|
ASSERT(mDeallocations.Empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescriptorSetService::AddDeferredDeallocation(BindGroupLayout* layout, size_t index) {
|
||||||
|
mDeallocations.Enqueue({layout, index}, mDevice->GetPendingCommandSerial());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescriptorSetService::Tick(Serial completedSerial) {
|
||||||
|
for (Deallocation& dealloc : mDeallocations.IterateUpTo(completedSerial)) {
|
||||||
|
dealloc.layout->FinishDeallocation(dealloc.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
mDeallocations.ClearUpTo(completedSerial);
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace dawn_native::vulkan
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2019 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.
|
||||||
|
|
||||||
|
#ifndef DAWNNATIVE_VULKAN_DESCRIPTORSETSERVICE_H_
|
||||||
|
#define DAWNNATIVE_VULKAN_DESCRIPTORSETSERVICE_H_
|
||||||
|
|
||||||
|
#include "common/SerialQueue.h"
|
||||||
|
|
||||||
|
#include "dawn_native/vulkan/BindGroupLayoutVk.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
|
class BindGroupLayout;
|
||||||
|
class Device;
|
||||||
|
|
||||||
|
// Handles everything related to descriptor sets that isn't tied to a particular
|
||||||
|
// BindGroupLayout.
|
||||||
|
class DescriptorSetService {
|
||||||
|
public:
|
||||||
|
DescriptorSetService(Device* device);
|
||||||
|
~DescriptorSetService();
|
||||||
|
|
||||||
|
// Will call layout->FinishDeallocation when the serial is passed.
|
||||||
|
void AddDeferredDeallocation(BindGroupLayout* layout, size_t index);
|
||||||
|
|
||||||
|
void Tick(Serial completedSerial);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Device* mDevice;
|
||||||
|
|
||||||
|
struct Deallocation {
|
||||||
|
Ref<BindGroupLayout> layout;
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
SerialQueue<Deallocation> mDeallocations;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace dawn_native::vulkan
|
||||||
|
|
||||||
|
#endif // DAWNNATIVE_VULKAN_DESCRIPTORSETSERVICE_H_
|
|
@ -28,6 +28,7 @@
|
||||||
#include "dawn_native/vulkan/BufferVk.h"
|
#include "dawn_native/vulkan/BufferVk.h"
|
||||||
#include "dawn_native/vulkan/CommandBufferVk.h"
|
#include "dawn_native/vulkan/CommandBufferVk.h"
|
||||||
#include "dawn_native/vulkan/ComputePipelineVk.h"
|
#include "dawn_native/vulkan/ComputePipelineVk.h"
|
||||||
|
#include "dawn_native/vulkan/DescriptorSetService.h"
|
||||||
#include "dawn_native/vulkan/FencedDeleter.h"
|
#include "dawn_native/vulkan/FencedDeleter.h"
|
||||||
#include "dawn_native/vulkan/PipelineLayoutVk.h"
|
#include "dawn_native/vulkan/PipelineLayoutVk.h"
|
||||||
#include "dawn_native/vulkan/QueueVk.h"
|
#include "dawn_native/vulkan/QueueVk.h"
|
||||||
|
@ -67,6 +68,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
DAWN_TRY(functions->LoadDeviceProcs(mVkDevice, mDeviceInfo));
|
DAWN_TRY(functions->LoadDeviceProcs(mVkDevice, mDeviceInfo));
|
||||||
|
|
||||||
GatherQueueFromDevice();
|
GatherQueueFromDevice();
|
||||||
|
mDescriptorSetService = std::make_unique<DescriptorSetService>(this);
|
||||||
mDeleter = std::make_unique<FencedDeleter>(this);
|
mDeleter = std::make_unique<FencedDeleter>(this);
|
||||||
mMapRequestTracker = std::make_unique<MapRequestTracker>(this);
|
mMapRequestTracker = std::make_unique<MapRequestTracker>(this);
|
||||||
mRenderPassCache = std::make_unique<RenderPassCache>(this);
|
mRenderPassCache = std::make_unique<RenderPassCache>(this);
|
||||||
|
@ -131,6 +133,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
// Free services explicitly so that they can free Vulkan objects before vkDestroyDevice
|
// Free services explicitly so that they can free Vulkan objects before vkDestroyDevice
|
||||||
mDynamicUploader = nullptr;
|
mDynamicUploader = nullptr;
|
||||||
|
mDescriptorSetService = nullptr;
|
||||||
|
|
||||||
// Releasing the uploader enqueues buffers to be released.
|
// Releasing the uploader enqueues buffers to be released.
|
||||||
// Call Tick() again to clear them before releasing the deleter.
|
// Call Tick() again to clear them before releasing the deleter.
|
||||||
|
@ -216,6 +219,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
CheckPassedFences();
|
CheckPassedFences();
|
||||||
RecycleCompletedCommands();
|
RecycleCompletedCommands();
|
||||||
|
|
||||||
|
mDescriptorSetService->Tick(mCompletedSerial);
|
||||||
mMapRequestTracker->Tick(mCompletedSerial);
|
mMapRequestTracker->Tick(mCompletedSerial);
|
||||||
|
|
||||||
// Uploader should tick before the resource allocator
|
// Uploader should tick before the resource allocator
|
||||||
|
@ -261,6 +265,10 @@ namespace dawn_native { namespace vulkan {
|
||||||
return mMapRequestTracker.get();
|
return mMapRequestTracker.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DescriptorSetService* Device::GetDescriptorSetService() const {
|
||||||
|
return mDescriptorSetService.get();
|
||||||
|
}
|
||||||
|
|
||||||
FencedDeleter* Device::GetFencedDeleter() const {
|
FencedDeleter* Device::GetFencedDeleter() const {
|
||||||
return mDeleter.get();
|
return mDeleter.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
class Adapter;
|
class Adapter;
|
||||||
class BufferUploader;
|
class BufferUploader;
|
||||||
|
class DescriptorSetService;
|
||||||
struct ExternalImageDescriptor;
|
struct ExternalImageDescriptor;
|
||||||
class FencedDeleter;
|
class FencedDeleter;
|
||||||
class MapRequestTracker;
|
class MapRequestTracker;
|
||||||
|
@ -58,6 +59,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
VkQueue GetQueue() const;
|
VkQueue GetQueue() const;
|
||||||
|
|
||||||
BufferUploader* GetBufferUploader() const;
|
BufferUploader* GetBufferUploader() const;
|
||||||
|
DescriptorSetService* GetDescriptorSetService() const;
|
||||||
FencedDeleter* GetFencedDeleter() const;
|
FencedDeleter* GetFencedDeleter() const;
|
||||||
MapRequestTracker* GetMapRequestTracker() const;
|
MapRequestTracker* GetMapRequestTracker() const;
|
||||||
RenderPassCache* GetRenderPassCache() const;
|
RenderPassCache* GetRenderPassCache() const;
|
||||||
|
@ -132,6 +134,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
uint32_t mQueueFamily = 0;
|
uint32_t mQueueFamily = 0;
|
||||||
VkQueue mQueue = VK_NULL_HANDLE;
|
VkQueue mQueue = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
std::unique_ptr<DescriptorSetService> mDescriptorSetService;
|
||||||
std::unique_ptr<FencedDeleter> mDeleter;
|
std::unique_ptr<FencedDeleter> mDeleter;
|
||||||
std::unique_ptr<MapRequestTracker> mMapRequestTracker;
|
std::unique_ptr<MapRequestTracker> mMapRequestTracker;
|
||||||
std::unique_ptr<ResourceMemoryAllocator> mResourceMemoryAllocator;
|
std::unique_ptr<ResourceMemoryAllocator> mResourceMemoryAllocator;
|
||||||
|
|
Loading…
Reference in New Issue