[Vulkan] Transient descriptor pool + other cleanup for future drawing
This commit is contained in:
parent
afe304b328
commit
93f6a00201
|
@ -49,6 +49,12 @@ bool VulkanCommandProcessor::SetupContext() {
|
|||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
|
||||
VkDevice device = provider.device();
|
||||
|
||||
// No specific reason for 32768, just the "too much" amount from Direct3D 12
|
||||
// PIX warnings.
|
||||
transient_descriptor_pool_uniform_buffers_ =
|
||||
std::make_unique<ui::vulkan::TransientDescriptorPool>(
|
||||
provider, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 32768, 32768);
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info;
|
||||
descriptor_set_layout_create_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
|
@ -77,7 +83,7 @@ bool VulkanCommandProcessor::SetupContext() {
|
|||
&descriptor_set_layout_binding_uniform_buffer;
|
||||
if (dfn.vkCreateDescriptorSetLayout(
|
||||
device, &descriptor_set_layout_create_info, nullptr,
|
||||
&descriptor_set_layout_ub_fetch_bool_loop_constants_) != VK_SUCCESS) {
|
||||
&descriptor_set_layout_fetch_bool_loop_constants_) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"Failed to create a Vulkan descriptor set layout for the fetch, bool "
|
||||
"and loop constants uniform buffer");
|
||||
|
@ -87,7 +93,7 @@ bool VulkanCommandProcessor::SetupContext() {
|
|||
shader_stages_guest_vertex;
|
||||
if (dfn.vkCreateDescriptorSetLayout(
|
||||
device, &descriptor_set_layout_create_info, nullptr,
|
||||
&descriptor_set_layout_ub_float_constants_vertex_) != VK_SUCCESS) {
|
||||
&descriptor_set_layout_float_constants_vertex_) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"Failed to create a Vulkan descriptor set layout for the vertex shader "
|
||||
"float constants uniform buffer");
|
||||
|
@ -97,7 +103,7 @@ bool VulkanCommandProcessor::SetupContext() {
|
|||
VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
if (dfn.vkCreateDescriptorSetLayout(
|
||||
device, &descriptor_set_layout_create_info, nullptr,
|
||||
&descriptor_set_layout_ub_float_constants_pixel_) != VK_SUCCESS) {
|
||||
&descriptor_set_layout_float_constants_pixel_) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"Failed to create a Vulkan descriptor set layout for the pixel shader "
|
||||
"float constants uniform buffer");
|
||||
|
@ -111,7 +117,7 @@ bool VulkanCommandProcessor::SetupContext() {
|
|||
}
|
||||
if (dfn.vkCreateDescriptorSetLayout(
|
||||
device, &descriptor_set_layout_create_info, nullptr,
|
||||
&descriptor_set_layout_ub_system_constants_) != VK_SUCCESS) {
|
||||
&descriptor_set_layout_system_constants_) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"Failed to create a Vulkan descriptor set layout for the system "
|
||||
"constants uniform buffer");
|
||||
|
@ -257,19 +263,21 @@ void VulkanCommandProcessor::ShutdownContext() {
|
|||
descriptor_set_layout_shared_memory_and_edram_);
|
||||
ui::vulkan::util::DestroyAndNullHandle(
|
||||
dfn.vkDestroyDescriptorSetLayout, device,
|
||||
descriptor_set_layout_ub_system_constants_);
|
||||
descriptor_set_layout_system_constants_);
|
||||
ui::vulkan::util::DestroyAndNullHandle(
|
||||
dfn.vkDestroyDescriptorSetLayout, device,
|
||||
descriptor_set_layout_ub_float_constants_pixel_);
|
||||
descriptor_set_layout_float_constants_pixel_);
|
||||
ui::vulkan::util::DestroyAndNullHandle(
|
||||
dfn.vkDestroyDescriptorSetLayout, device,
|
||||
descriptor_set_layout_ub_float_constants_vertex_);
|
||||
descriptor_set_layout_float_constants_vertex_);
|
||||
ui::vulkan::util::DestroyAndNullHandle(
|
||||
dfn.vkDestroyDescriptorSetLayout, device,
|
||||
descriptor_set_layout_ub_fetch_bool_loop_constants_);
|
||||
descriptor_set_layout_fetch_bool_loop_constants_);
|
||||
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyDescriptorSetLayout,
|
||||
device, descriptor_set_layout_empty_);
|
||||
|
||||
transient_descriptor_pool_uniform_buffers_.reset();
|
||||
|
||||
sparse_bind_wait_stage_mask_ = 0;
|
||||
sparse_buffer_binds_.clear();
|
||||
sparse_memory_binds_.clear();
|
||||
|
@ -454,15 +462,26 @@ bool VulkanCommandProcessor::GetPipelineLayout(
|
|||
|
||||
VkDescriptorSetLayout
|
||||
descriptor_set_layouts[SpirvShaderTranslator::kDescriptorSetCount];
|
||||
// Fill any unused set layouts with empty layouts.
|
||||
// TODO(Triang3l): Remove this.
|
||||
for (size_t i = 0; i < xe::countof(descriptor_set_layouts); ++i) {
|
||||
descriptor_set_layouts[i] = descriptor_set_layout_empty_;
|
||||
}
|
||||
descriptor_set_layouts[SpirvShaderTranslator::kDescriptorSetFetchConstants] =
|
||||
descriptor_set_layout_fetch_bool_loop_constants_;
|
||||
descriptor_set_layouts
|
||||
[SpirvShaderTranslator::kDescriptorSetFloatConstantsVertex] =
|
||||
descriptor_set_layout_float_constants_vertex_;
|
||||
descriptor_set_layouts
|
||||
[SpirvShaderTranslator::kDescriptorSetFloatConstantsPixel] =
|
||||
descriptor_set_layout_float_constants_pixel_;
|
||||
descriptor_set_layouts[SpirvShaderTranslator::kDescriptorSetTexturesPixel] =
|
||||
descriptor_set_layout_textures_pixel;
|
||||
descriptor_set_layouts[SpirvShaderTranslator::kDescriptorSetTexturesVertex] =
|
||||
descriptor_set_layout_textures_vertex;
|
||||
descriptor_set_layouts[SpirvShaderTranslator::kDescriptorSetSystemConstants] =
|
||||
descriptor_set_layout_system_constants_;
|
||||
descriptor_set_layouts
|
||||
[SpirvShaderTranslator::kDescriptorSetBoolLoopConstants] =
|
||||
descriptor_set_layout_fetch_bool_loop_constants_;
|
||||
descriptor_set_layouts
|
||||
[SpirvShaderTranslator::kDescriptorSetSharedMemoryAndEdram] =
|
||||
descriptor_set_layout_shared_memory_and_edram_;
|
||||
|
||||
VkPipelineLayoutCreateInfo pipeline_layout_create_info;
|
||||
pipeline_layout_create_info.sType =
|
||||
|
@ -640,6 +659,9 @@ void VulkanCommandProcessor::CheckSubmissionFence(uint64_t await_submission) {
|
|||
command_buffers_submitted_.pop_front();
|
||||
}
|
||||
|
||||
// Reclaim descriptor pools.
|
||||
transient_descriptor_pool_uniform_buffers_->Reclaim(submission_completed_);
|
||||
|
||||
shared_memory_->CompletedSubmissionUpdated();
|
||||
}
|
||||
|
||||
|
@ -888,6 +910,9 @@ bool VulkanCommandProcessor::EndSubmission(bool is_swap) {
|
|||
if (cache_clear_requested_ && AwaitAllQueueOperationsCompletion()) {
|
||||
cache_clear_requested_ = false;
|
||||
|
||||
transient_descriptor_pool_uniform_buffers_->ClearCache();
|
||||
|
||||
assert_true(command_buffers_submitted_.empty());
|
||||
for (const CommandBuffer& command_buffer : command_buffers_writable_) {
|
||||
dfn.vkDestroyCommandPool(device, command_buffer.pool, nullptr);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include "xenia/gpu/vulkan/vulkan_shared_memory.h"
|
||||
#include "xenia/gpu/xenos.h"
|
||||
#include "xenia/kernel/kernel_state.h"
|
||||
#include "xenia/ui/vulkan/transient_descriptor_pool.h"
|
||||
#include "xenia/ui/vulkan/vulkan_context.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -162,15 +164,18 @@ class VulkanCommandProcessor : public CommandProcessor {
|
|||
std::vector<VkSparseBufferMemoryBindInfo> sparse_buffer_bind_infos_temp_;
|
||||
VkPipelineStageFlags sparse_bind_wait_stage_mask_ = 0;
|
||||
|
||||
std::unique_ptr<ui::vulkan::TransientDescriptorPool>
|
||||
transient_descriptor_pool_uniform_buffers_;
|
||||
|
||||
// Descriptor set layouts used by different shaders.
|
||||
VkDescriptorSetLayout descriptor_set_layout_empty_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptor_set_layout_ub_fetch_bool_loop_constants_ =
|
||||
VkDescriptorSetLayout descriptor_set_layout_fetch_bool_loop_constants_ =
|
||||
VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptor_set_layout_ub_float_constants_vertex_ =
|
||||
VkDescriptorSetLayout descriptor_set_layout_float_constants_vertex_ =
|
||||
VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptor_set_layout_ub_float_constants_pixel_ =
|
||||
VkDescriptorSetLayout descriptor_set_layout_float_constants_pixel_ =
|
||||
VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptor_set_layout_ub_system_constants_ =
|
||||
VkDescriptorSetLayout descriptor_set_layout_system_constants_ =
|
||||
VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptor_set_layout_shared_memory_and_edram_ =
|
||||
VK_NULL_HANDLE;
|
||||
|
|
|
@ -71,7 +71,7 @@ void GraphicsUploadBufferPool::FlushWrites() {
|
|||
GraphicsUploadBufferPool::Page* GraphicsUploadBufferPool::Request(
|
||||
uint64_t submission_index, size_t size, size_t alignment,
|
||||
size_t& offset_out) {
|
||||
assert_not_zero(alignment);
|
||||
alignment = std::max(alignment, size_t(1));
|
||||
assert_true(xe::is_pow2(alignment));
|
||||
size = xe::align(size, alignment);
|
||||
assert_true(size <= page_size_);
|
||||
|
@ -126,7 +126,7 @@ GraphicsUploadBufferPool::Page* GraphicsUploadBufferPool::Request(
|
|||
GraphicsUploadBufferPool::Page* GraphicsUploadBufferPool::RequestPartial(
|
||||
uint64_t submission_index, size_t size, size_t alignment,
|
||||
size_t& offset_out, size_t& size_out) {
|
||||
assert_not_zero(alignment);
|
||||
alignment = std::max(alignment, size_t(1));
|
||||
assert_true(xe::is_pow2(alignment));
|
||||
size = xe::align(size, alignment);
|
||||
size = std::min(size, page_size_);
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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.
|
||||
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 = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
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
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* 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_
|
|
@ -615,6 +615,7 @@ bool VulkanProvider::Initialize() {
|
|||
XE_VULKAN_LOAD_DFN(vkGetSwapchainImagesKHR);
|
||||
XE_VULKAN_LOAD_DFN(vkMapMemory);
|
||||
XE_VULKAN_LOAD_DFN(vkResetCommandPool);
|
||||
XE_VULKAN_LOAD_DFN(vkResetDescriptorPool);
|
||||
XE_VULKAN_LOAD_DFN(vkResetFences);
|
||||
XE_VULKAN_LOAD_DFN(vkQueueBindSparse);
|
||||
XE_VULKAN_LOAD_DFN(vkQueuePresentKHR);
|
||||
|
|
|
@ -193,6 +193,7 @@ class VulkanProvider : public GraphicsProvider {
|
|||
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
|
||||
PFN_vkMapMemory vkMapMemory;
|
||||
PFN_vkResetCommandPool vkResetCommandPool;
|
||||
PFN_vkResetDescriptorPool vkResetDescriptorPool;
|
||||
PFN_vkResetFences vkResetFences;
|
||||
PFN_vkQueueBindSparse vkQueueBindSparse;
|
||||
PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||
|
|
Loading…
Reference in New Issue