[Vulkan] Basic texture descriptor set allocation/binding
This commit is contained in:
@@ -94,8 +94,7 @@ size_t SingleLayoutDescriptorSetPool::Allocate() {
|
||||
if (dfn.vkAllocateDescriptorSets(device, &descriptor_set_allocate_info,
|
||||
&descriptor_set) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"SingleLayoutDescriptorSetPool: Failed to allocate a descriptor "
|
||||
"layout");
|
||||
"SingleLayoutDescriptorSetPool: Failed to allocate a descriptor set");
|
||||
if (current_pool_sets_remaining_ >= pool_set_count_) {
|
||||
// Failed to allocate in a new pool - something completely wrong, don't
|
||||
// store empty pools as full.
|
||||
|
||||
216
src/xenia/ui/vulkan/single_type_descriptor_set_allocator.cc
Normal file
216
src/xenia/ui/vulkan/single_type_descriptor_set_allocator.cc
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/vulkan/single_type_descriptor_set_allocator.h"
|
||||
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/ui/vulkan/vulkan_util.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
void SingleTypeDescriptorSetAllocator::Reset() {
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
|
||||
VkDevice device = provider_.device();
|
||||
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyDescriptorPool, device,
|
||||
page_usable_latest_.pool);
|
||||
for (const std::pair<uint32_t, Page>& page_pair : pages_usable_) {
|
||||
dfn.vkDestroyDescriptorPool(device, page_pair.second.pool, nullptr);
|
||||
}
|
||||
pages_usable_.clear();
|
||||
for (VkDescriptorPool pool : pages_full_) {
|
||||
dfn.vkDestroyDescriptorPool(device, pool, nullptr);
|
||||
}
|
||||
pages_full_.clear();
|
||||
}
|
||||
|
||||
VkDescriptorSet SingleTypeDescriptorSetAllocator::Allocate(
|
||||
VkDescriptorSetLayout descriptor_set_layout, uint32_t descriptor_count) {
|
||||
assert_not_zero(descriptor_count);
|
||||
if (descriptor_count == 0) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
|
||||
VkDevice device = provider_.device();
|
||||
|
||||
VkDescriptorSetAllocateInfo descriptor_set_allocate_info;
|
||||
descriptor_set_allocate_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
descriptor_set_allocate_info.pNext = nullptr;
|
||||
descriptor_set_allocate_info.descriptorSetCount = 1;
|
||||
descriptor_set_allocate_info.pSetLayouts = &descriptor_set_layout;
|
||||
VkDescriptorSet descriptor_set;
|
||||
|
||||
if (descriptor_count > descriptor_pool_size_.descriptorCount) {
|
||||
// Can't allocate in the pool, need a dedicated allocation.
|
||||
VkDescriptorPoolSize dedicated_descriptor_pool_size;
|
||||
dedicated_descriptor_pool_size.type = descriptor_pool_size_.type;
|
||||
dedicated_descriptor_pool_size.descriptorCount = descriptor_count;
|
||||
VkDescriptorPoolCreateInfo dedicated_descriptor_pool_create_info;
|
||||
dedicated_descriptor_pool_create_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
dedicated_descriptor_pool_create_info.pNext = nullptr;
|
||||
dedicated_descriptor_pool_create_info.flags = 0;
|
||||
dedicated_descriptor_pool_create_info.maxSets = 1;
|
||||
dedicated_descriptor_pool_create_info.poolSizeCount = 1;
|
||||
dedicated_descriptor_pool_create_info.pPoolSizes =
|
||||
&dedicated_descriptor_pool_size;
|
||||
VkDescriptorPool dedicated_descriptor_pool;
|
||||
if (dfn.vkCreateDescriptorPool(
|
||||
device, &dedicated_descriptor_pool_create_info, nullptr,
|
||||
&dedicated_descriptor_pool) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"SingleTypeDescriptorSetAllocator: Failed to create a dedicated pool "
|
||||
"for {} descriptors",
|
||||
dedicated_descriptor_pool_size.descriptorCount);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
descriptor_set_allocate_info.descriptorPool = dedicated_descriptor_pool;
|
||||
if (dfn.vkAllocateDescriptorSets(device, &descriptor_set_allocate_info,
|
||||
&descriptor_set) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"SingleTypeDescriptorSetAllocator: Failed to allocate {} descriptors "
|
||||
"in a dedicated pool",
|
||||
descriptor_count);
|
||||
dfn.vkDestroyDescriptorPool(device, dedicated_descriptor_pool, nullptr);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
pages_full_.push_back(dedicated_descriptor_pool);
|
||||
return descriptor_set;
|
||||
}
|
||||
|
||||
// Try allocating from the latest page an allocation has happened from, to
|
||||
// avoid detaching from the map and re-attaching for every allocation.
|
||||
if (page_usable_latest_.pool != VK_NULL_HANDLE) {
|
||||
assert_not_zero(page_usable_latest_.descriptors_remaining);
|
||||
assert_not_zero(page_usable_latest_.descriptor_sets_remaining);
|
||||
if (page_usable_latest_.descriptors_remaining >= descriptor_count) {
|
||||
descriptor_set_allocate_info.descriptorPool = page_usable_latest_.pool;
|
||||
if (dfn.vkAllocateDescriptorSets(device, &descriptor_set_allocate_info,
|
||||
&descriptor_set) == VK_SUCCESS) {
|
||||
page_usable_latest_.descriptors_remaining -= descriptor_count;
|
||||
--page_usable_latest_.descriptor_sets_remaining;
|
||||
if (!page_usable_latest_.descriptors_remaining ||
|
||||
!page_usable_latest_.descriptor_sets_remaining) {
|
||||
pages_full_.push_back(page_usable_latest_.pool);
|
||||
page_usable_latest_.pool = VK_NULL_HANDLE;
|
||||
}
|
||||
return descriptor_set;
|
||||
}
|
||||
// Failed to allocate internally even though there should be enough space,
|
||||
// don't try to allocate from this pool again at all.
|
||||
pages_full_.push_back(page_usable_latest_.pool);
|
||||
page_usable_latest_.pool = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
// If allocating from the latest pool wasn't possible, pick any that has free
|
||||
// space. Prefer filling pages that have the most free space as they can more
|
||||
// likely be used for more allocations later.
|
||||
while (!pages_usable_.empty()) {
|
||||
auto page_usable_last_it = std::prev(pages_usable_.cend());
|
||||
if (page_usable_last_it->second.descriptors_remaining < descriptor_count) {
|
||||
// All other pages_usable_ entries have fewer free descriptors too (the
|
||||
// remaining count is the map key).
|
||||
break;
|
||||
}
|
||||
// Remove the page from the map unconditionally - in case of a successful
|
||||
// allocation, it will have a different number of free descriptors, thus a
|
||||
// new map key (but it will also become page_usable_latest_ instead even),
|
||||
// or will become full, and in case of a failure to allocate internally even
|
||||
// though there still should be enough space, it should never be allocated
|
||||
// from again.
|
||||
Page map_page = pages_usable_.crend()->second;
|
||||
pages_usable_.erase(page_usable_last_it);
|
||||
descriptor_set_allocate_info.descriptorPool = map_page.pool;
|
||||
if (dfn.vkAllocateDescriptorSets(device, &descriptor_set_allocate_info,
|
||||
&descriptor_set) != VK_SUCCESS) {
|
||||
pages_full_.push_back(map_page.pool);
|
||||
continue;
|
||||
}
|
||||
map_page.descriptors_remaining -= descriptor_count;
|
||||
--map_page.descriptor_sets_remaining;
|
||||
if (!map_page.descriptors_remaining ||
|
||||
!map_page.descriptor_sets_remaining) {
|
||||
pages_full_.push_back(map_page.pool);
|
||||
} else {
|
||||
if (page_usable_latest_.pool != VK_NULL_HANDLE) {
|
||||
// Make the page with more free descriptors the next to allocate from.
|
||||
if (map_page.descriptors_remaining >
|
||||
page_usable_latest_.descriptors_remaining) {
|
||||
pages_usable_.emplace(page_usable_latest_.descriptors_remaining,
|
||||
page_usable_latest_);
|
||||
page_usable_latest_ = map_page;
|
||||
} else {
|
||||
pages_usable_.emplace(map_page.descriptors_remaining, map_page);
|
||||
}
|
||||
} else {
|
||||
page_usable_latest_ = map_page;
|
||||
}
|
||||
}
|
||||
return descriptor_set;
|
||||
}
|
||||
|
||||
// Try allocating from a new page.
|
||||
VkDescriptorPoolCreateInfo new_descriptor_pool_create_info;
|
||||
new_descriptor_pool_create_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
new_descriptor_pool_create_info.pNext = nullptr;
|
||||
new_descriptor_pool_create_info.flags = 0;
|
||||
new_descriptor_pool_create_info.maxSets = descriptor_sets_per_page_;
|
||||
new_descriptor_pool_create_info.poolSizeCount = 1;
|
||||
new_descriptor_pool_create_info.pPoolSizes = &descriptor_pool_size_;
|
||||
VkDescriptorPool new_descriptor_pool;
|
||||
if (dfn.vkCreateDescriptorPool(device, &new_descriptor_pool_create_info,
|
||||
nullptr, &new_descriptor_pool) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"SingleTypeDescriptorSetAllocator: Failed to create a pool for {} sets "
|
||||
"with {} descriptors",
|
||||
descriptor_sets_per_page_, descriptor_pool_size_.descriptorCount);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
descriptor_set_allocate_info.descriptorPool = new_descriptor_pool;
|
||||
if (dfn.vkAllocateDescriptorSets(device, &descriptor_set_allocate_info,
|
||||
&descriptor_set) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"SingleTypeDescriptorSetAllocator: Failed to allocate {} descriptors",
|
||||
descriptor_count);
|
||||
dfn.vkDestroyDescriptorPool(device, new_descriptor_pool, nullptr);
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
Page new_page;
|
||||
new_page.pool = new_descriptor_pool;
|
||||
new_page.descriptors_remaining =
|
||||
descriptor_pool_size_.descriptorCount - descriptor_count;
|
||||
new_page.descriptor_sets_remaining = descriptor_sets_per_page_ - 1;
|
||||
if (!new_page.descriptors_remaining || !new_page.descriptor_sets_remaining) {
|
||||
pages_full_.push_back(new_page.pool);
|
||||
} else {
|
||||
if (page_usable_latest_.pool != VK_NULL_HANDLE) {
|
||||
// Make the page with more free descriptors the next to allocate from.
|
||||
if (new_page.descriptors_remaining >
|
||||
page_usable_latest_.descriptors_remaining) {
|
||||
pages_usable_.emplace(page_usable_latest_.descriptors_remaining,
|
||||
page_usable_latest_);
|
||||
page_usable_latest_ = new_page;
|
||||
} else {
|
||||
pages_usable_.emplace(new_page.descriptors_remaining, new_page);
|
||||
}
|
||||
} else {
|
||||
page_usable_latest_ = new_page;
|
||||
}
|
||||
}
|
||||
return descriptor_set;
|
||||
}
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
84
src/xenia/ui/vulkan/single_type_descriptor_set_allocator.h
Normal file
84
src/xenia/ui/vulkan/single_type_descriptor_set_allocator.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_VULKAN_SINGLE_TYPE_DESCRIPTOR_SET_ALLOCATOR_H_
|
||||
#define XENIA_UI_VULKAN_SINGLE_TYPE_DESCRIPTOR_SET_ALLOCATOR_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
// Allocates multiple descriptors of a single type in descriptor set layouts
|
||||
// consisting of descriptors of only that type. There's no way to free these
|
||||
// descriptors within the SingleTypeDescriptorSetAllocator, per-layout free
|
||||
// lists should be used externally.
|
||||
class SingleTypeDescriptorSetAllocator {
|
||||
public:
|
||||
explicit SingleTypeDescriptorSetAllocator(
|
||||
const ui::vulkan::VulkanProvider& provider,
|
||||
VkDescriptorType descriptor_type, uint32_t descriptors_per_page,
|
||||
uint32_t descriptor_sets_per_page)
|
||||
: provider_(provider),
|
||||
descriptor_sets_per_page_(descriptor_sets_per_page) {
|
||||
assert_not_zero(descriptor_sets_per_page_);
|
||||
descriptor_pool_size_.type = descriptor_type;
|
||||
// Not allocating sets with 0 descriptors using the allocator - pointless to
|
||||
// have the descriptor count below the set count.
|
||||
descriptor_pool_size_.descriptorCount =
|
||||
std::max(descriptors_per_page, descriptor_sets_per_page);
|
||||
}
|
||||
SingleTypeDescriptorSetAllocator(
|
||||
const SingleTypeDescriptorSetAllocator& allocator) = delete;
|
||||
SingleTypeDescriptorSetAllocator& operator=(
|
||||
const SingleTypeDescriptorSetAllocator& allocator) = delete;
|
||||
~SingleTypeDescriptorSetAllocator() { Reset(); }
|
||||
|
||||
void Reset();
|
||||
|
||||
VkDescriptorSet Allocate(VkDescriptorSetLayout descriptor_set_layout,
|
||||
uint32_t descriptor_count);
|
||||
|
||||
private:
|
||||
struct Page {
|
||||
VkDescriptorPool pool;
|
||||
uint32_t descriptors_remaining;
|
||||
uint32_t descriptor_sets_remaining;
|
||||
};
|
||||
|
||||
const ui::vulkan::VulkanProvider& provider_;
|
||||
|
||||
VkDescriptorPoolSize descriptor_pool_size_;
|
||||
uint32_t descriptor_sets_per_page_;
|
||||
|
||||
std::vector<VkDescriptorPool> pages_full_;
|
||||
// Because allocations must be contiguous, overflow may happen even if a page
|
||||
// still has free descriptors, so multiple pages may have free space.
|
||||
// To avoid removing and re-adding the page to the map that keeps them sorted
|
||||
// (the key is the number of free descriptors remaining, and it changes at
|
||||
// every allocation from a page), instead of always looking for a free space
|
||||
// in the map, maintaining one page outside the map, and allocation attempts
|
||||
// will be made from that page first.
|
||||
std::multimap<uint32_t, Page> pages_usable_;
|
||||
// Doesn't exist if page_usable_latest_.pool == VK_NULL_HANDLE.
|
||||
Page page_usable_latest_ = {};
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_VULKAN_SINGLE_TYPE_DESCRIPTOR_SET_ALLOCATOR_H_
|
||||
@@ -1,162 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/vulkan/transient_descriptor_pool.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
TransientDescriptorPool::TransientDescriptorPool(
|
||||
const VulkanProvider& provider, VkDescriptorType descriptor_type,
|
||||
uint32_t page_descriptor_set_count, uint32_t page_descriptor_count)
|
||||
: provider_(provider),
|
||||
descriptor_type_(descriptor_type),
|
||||
page_descriptor_set_count_(page_descriptor_set_count),
|
||||
page_descriptor_count_(page_descriptor_count) {
|
||||
assert_not_zero(page_descriptor_set_count);
|
||||
assert_true(page_descriptor_set_count <= page_descriptor_count);
|
||||
}
|
||||
|
||||
TransientDescriptorPool::~TransientDescriptorPool() { ClearCache(); }
|
||||
|
||||
void TransientDescriptorPool::Reclaim(uint64_t completed_submission_index) {
|
||||
const VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
|
||||
VkDevice device = provider_.device();
|
||||
while (!pages_submitted_.empty()) {
|
||||
const auto& descriptor_pool_pair = pages_submitted_.front();
|
||||
if (descriptor_pool_pair.second > completed_submission_index) {
|
||||
break;
|
||||
}
|
||||
dfn.vkResetDescriptorPool(device, descriptor_pool_pair.first, 0);
|
||||
pages_writable_.push_back(descriptor_pool_pair.first);
|
||||
pages_submitted_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void TransientDescriptorPool::ClearCache() {
|
||||
const VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
|
||||
VkDevice device = provider_.device();
|
||||
for (const auto& descriptor_pool_pair : pages_submitted_) {
|
||||
dfn.vkDestroyDescriptorPool(device, descriptor_pool_pair.first, nullptr);
|
||||
}
|
||||
pages_submitted_.clear();
|
||||
page_current_descriptors_used_ = 0;
|
||||
page_current_descriptor_sets_used_ = 0;
|
||||
page_current_last_submission_ = 0;
|
||||
for (VkDescriptorPool descriptor_pool : pages_writable_) {
|
||||
dfn.vkDestroyDescriptorPool(device, descriptor_pool, nullptr);
|
||||
}
|
||||
pages_writable_.clear();
|
||||
}
|
||||
|
||||
VkDescriptorSet TransientDescriptorPool::Request(
|
||||
uint64_t submission_index, VkDescriptorSetLayout layout,
|
||||
uint32_t layout_descriptor_count) {
|
||||
assert_true(submission_index >= page_current_last_submission_);
|
||||
assert_not_zero(layout_descriptor_count);
|
||||
assert_true(layout_descriptor_count <= page_descriptor_count_);
|
||||
|
||||
const VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
|
||||
VkDevice device = provider_.device();
|
||||
|
||||
VkDescriptorSetAllocateInfo descriptor_set_allocate_info;
|
||||
descriptor_set_allocate_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
descriptor_set_allocate_info.pNext = nullptr;
|
||||
descriptor_set_allocate_info.descriptorSetCount = 1;
|
||||
descriptor_set_allocate_info.pSetLayouts = &layout;
|
||||
VkDescriptorSet descriptor_set;
|
||||
|
||||
// Try to allocate as normal.
|
||||
// TODO(Triang3l): Investigate the possibility of reuse of descriptor sets, as
|
||||
// vkAllocateDescriptorSets may be implemented suboptimally.
|
||||
if (!pages_writable_.empty()) {
|
||||
if (page_current_descriptor_sets_used_ < page_descriptor_set_count_ &&
|
||||
page_current_descriptors_used_ + layout_descriptor_count <=
|
||||
page_descriptor_count_) {
|
||||
descriptor_set_allocate_info.descriptorPool = pages_writable_.front();
|
||||
switch (dfn.vkAllocateDescriptorSets(
|
||||
device, &descriptor_set_allocate_info, &descriptor_set)) {
|
||||
case VK_SUCCESS:
|
||||
page_current_last_submission_ = submission_index;
|
||||
++page_current_descriptor_sets_used_;
|
||||
page_current_descriptors_used_ += layout_descriptor_count;
|
||||
return descriptor_set;
|
||||
case VK_ERROR_FRAGMENTED_POOL:
|
||||
case VK_ERROR_OUT_OF_POOL_MEMORY:
|
||||
// Need to create a new pool.
|
||||
break;
|
||||
default:
|
||||
XELOGE(
|
||||
"Failed to allocate a transient Vulkan descriptor set with {} "
|
||||
"descriptors of type {}",
|
||||
layout_descriptor_count, uint32_t(descriptor_type_));
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
// Overflow - go to the next pool.
|
||||
pages_submitted_.emplace_back(pages_writable_.front(),
|
||||
page_current_last_submission_);
|
||||
pages_writable_.front() = pages_writable_.back();
|
||||
pages_writable_.pop_back();
|
||||
page_current_descriptor_sets_used_ = 0;
|
||||
page_current_descriptors_used_ = 0;
|
||||
}
|
||||
|
||||
if (pages_writable_.empty()) {
|
||||
VkDescriptorPoolSize descriptor_pool_size;
|
||||
descriptor_pool_size.type = descriptor_type_;
|
||||
descriptor_pool_size.descriptorCount = page_descriptor_count_;
|
||||
VkDescriptorPoolCreateInfo descriptor_pool_create_info;
|
||||
descriptor_pool_create_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
descriptor_pool_create_info.pNext = nullptr;
|
||||
descriptor_pool_create_info.flags = 0;
|
||||
descriptor_pool_create_info.maxSets = page_descriptor_set_count_;
|
||||
descriptor_pool_create_info.poolSizeCount = 1;
|
||||
descriptor_pool_create_info.pPoolSizes = &descriptor_pool_size;
|
||||
VkDescriptorPool descriptor_pool;
|
||||
if (dfn.vkCreateDescriptorPool(device, &descriptor_pool_create_info,
|
||||
nullptr, &descriptor_pool) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"Failed to create a transient Vulkan descriptor pool for {} sets of "
|
||||
"up to {} descriptors of type {}",
|
||||
page_descriptor_set_count_, page_descriptor_count_,
|
||||
uint32_t(descriptor_type_));
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
pages_writable_.push_back(descriptor_pool);
|
||||
}
|
||||
|
||||
// Try to allocate after handling overflow.
|
||||
descriptor_set_allocate_info.descriptorPool = pages_writable_.front();
|
||||
if (dfn.vkAllocateDescriptorSets(device, &descriptor_set_allocate_info,
|
||||
&descriptor_set) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"Failed to allocate a transient Vulkan descriptor set with {} "
|
||||
"descriptors of type {}",
|
||||
layout_descriptor_count, uint32_t(descriptor_type_));
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
page_current_last_submission_ = submission_index;
|
||||
++page_current_descriptor_sets_used_;
|
||||
page_current_descriptors_used_ += layout_descriptor_count;
|
||||
return descriptor_set;
|
||||
}
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2020 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_VULKAN_TRANSIENT_DESCRIPTOR_POOL_H_
|
||||
#define XENIA_UI_VULKAN_TRANSIENT_DESCRIPTOR_POOL_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
// A pool of descriptor pools for single-submission use. For simplicity of
|
||||
// tracking when overflow happens, only allocating descriptors for sets
|
||||
// containing descriptors of a single type.
|
||||
class TransientDescriptorPool {
|
||||
public:
|
||||
TransientDescriptorPool(const VulkanProvider& provider,
|
||||
VkDescriptorType descriptor_type,
|
||||
uint32_t page_descriptor_set_count,
|
||||
uint32_t page_descriptor_count);
|
||||
~TransientDescriptorPool();
|
||||
|
||||
void Reclaim(uint64_t completed_submission_index);
|
||||
void ClearCache();
|
||||
|
||||
// Returns the allocated set, or VK_NULL_HANDLE if failed to allocate.
|
||||
VkDescriptorSet Request(uint64_t submission_index,
|
||||
VkDescriptorSetLayout layout,
|
||||
uint32_t layout_descriptor_count);
|
||||
|
||||
private:
|
||||
const VulkanProvider& provider_;
|
||||
|
||||
VkDescriptorType descriptor_type_;
|
||||
uint32_t page_descriptor_set_count_;
|
||||
uint32_t page_descriptor_count_;
|
||||
|
||||
std::vector<VkDescriptorPool> pages_writable_;
|
||||
uint64_t page_current_last_submission_ = 0;
|
||||
uint32_t page_current_descriptor_sets_used_ = 0;
|
||||
uint32_t page_current_descriptors_used_ = 0;
|
||||
std::deque<std::pair<VkDescriptorPool, uint64_t>> pages_submitted_;
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_VULKAN_TRANSIENT_DESCRIPTOR_POOL_H_
|
||||
Reference in New Issue
Block a user