[Vulkan] EDRAM range ownership transfers, resolve clears, 2x-as-4x MSAA
Transfers are functional on a D3D12-like level, but need additional work so fallbacks are used when multisampled integer sampled images are not supported, and to eliminate transfers between render targets within Vulkan format compatibility classes by using different views directly.
This commit is contained in:
@@ -15,6 +15,7 @@ XE_UI_VULKAN_FUNCTION(vkCmdClearColorImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyBufferToImage)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdCopyImageToBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDispatch)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDraw)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdDrawIndexed)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdEndRenderPass)
|
||||
@@ -29,6 +30,7 @@ XE_UI_VULKAN_FUNCTION(vkCmdSetStencilWriteMask)
|
||||
XE_UI_VULKAN_FUNCTION(vkCmdSetViewport)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateBuffer)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateCommandPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateComputePipelines)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateDescriptorPool)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateDescriptorSetLayout)
|
||||
XE_UI_VULKAN_FUNCTION(vkCreateFence)
|
||||
|
||||
120
src/xenia/ui/vulkan/single_layout_descriptor_set_pool.cc
Normal file
120
src/xenia/ui/vulkan/single_layout_descriptor_set_pool.cc
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_layout_descriptor_set_pool.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
SingleLayoutDescriptorSetPool::SingleLayoutDescriptorSetPool(
|
||||
const VulkanProvider& provider, uint32_t pool_set_count,
|
||||
uint32_t set_layout_descriptor_counts_count,
|
||||
const VkDescriptorPoolSize* set_layout_descriptor_counts,
|
||||
VkDescriptorSetLayout set_layout)
|
||||
: provider_(provider),
|
||||
pool_set_count_(pool_set_count),
|
||||
set_layout_(set_layout) {
|
||||
assert_not_zero(pool_set_count);
|
||||
pool_descriptor_counts_.resize(set_layout_descriptor_counts_count);
|
||||
for (uint32_t i = 0; i < set_layout_descriptor_counts_count; ++i) {
|
||||
VkDescriptorPoolSize& pool_descriptor_type_count =
|
||||
pool_descriptor_counts_[i];
|
||||
const VkDescriptorPoolSize& set_layout_descriptor_type_count =
|
||||
set_layout_descriptor_counts[i];
|
||||
pool_descriptor_type_count.type = set_layout_descriptor_type_count.type;
|
||||
pool_descriptor_type_count.descriptorCount =
|
||||
set_layout_descriptor_type_count.descriptorCount * pool_set_count;
|
||||
}
|
||||
}
|
||||
|
||||
SingleLayoutDescriptorSetPool::~SingleLayoutDescriptorSetPool() {
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
|
||||
VkDevice device = provider_.device();
|
||||
if (current_pool_ != VK_NULL_HANDLE) {
|
||||
dfn.vkDestroyDescriptorPool(device, current_pool_, nullptr);
|
||||
}
|
||||
for (VkDescriptorPool pool : full_pools_) {
|
||||
dfn.vkDestroyDescriptorPool(device, pool, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
size_t SingleLayoutDescriptorSetPool::Allocate() {
|
||||
if (!descriptor_sets_free_.empty()) {
|
||||
size_t free_index = descriptor_sets_free_.back();
|
||||
descriptor_sets_free_.pop_back();
|
||||
return free_index;
|
||||
}
|
||||
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
|
||||
VkDevice device = provider_.device();
|
||||
|
||||
// Two iterations so if vkAllocateDescriptorSets fails even with a non-zero
|
||||
// current_pool_sets_remaining_, another attempt will be made in a new pool.
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
if (current_pool_ != VK_NULL_HANDLE && !current_pool_sets_remaining_) {
|
||||
full_pools_.push_back(current_pool_);
|
||||
current_pool_ = VK_NULL_HANDLE;
|
||||
}
|
||||
if (current_pool_ == VK_NULL_HANDLE) {
|
||||
VkDescriptorPoolCreateInfo pool_create_info;
|
||||
pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
pool_create_info.pNext = nullptr;
|
||||
pool_create_info.flags = 0;
|
||||
pool_create_info.maxSets = pool_set_count_;
|
||||
pool_create_info.poolSizeCount = uint32_t(pool_descriptor_counts_.size());
|
||||
pool_create_info.pPoolSizes = pool_descriptor_counts_.data();
|
||||
if (dfn.vkCreateDescriptorPool(device, &pool_create_info, nullptr,
|
||||
¤t_pool_) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"SingleLayoutDescriptorSetPool: Failed to create a descriptor "
|
||||
"pool");
|
||||
return SIZE_MAX;
|
||||
}
|
||||
current_pool_sets_remaining_ = pool_set_count_;
|
||||
}
|
||||
|
||||
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.descriptorPool = current_pool_;
|
||||
descriptor_set_allocate_info.descriptorSetCount = 1;
|
||||
descriptor_set_allocate_info.pSetLayouts = &set_layout_;
|
||||
VkDescriptorSet descriptor_set;
|
||||
if (dfn.vkAllocateDescriptorSets(device, &descriptor_set_allocate_info,
|
||||
&descriptor_set) != VK_SUCCESS) {
|
||||
XELOGE(
|
||||
"SingleLayoutDescriptorSetPool: Failed to allocate a descriptor "
|
||||
"layout");
|
||||
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.
|
||||
dfn.vkDestroyDescriptorPool(device, current_pool_, nullptr);
|
||||
current_pool_ = VK_NULL_HANDLE;
|
||||
return SIZE_MAX;
|
||||
}
|
||||
full_pools_.push_back(current_pool_);
|
||||
current_pool_ = VK_NULL_HANDLE;
|
||||
}
|
||||
--current_pool_sets_remaining_;
|
||||
descriptor_sets_.push_back(descriptor_set);
|
||||
return descriptor_sets_.size() - 1;
|
||||
}
|
||||
|
||||
// Both attempts have failed.
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
63
src/xenia/ui/vulkan/single_layout_descriptor_set_pool.h
Normal file
63
src/xenia/ui/vulkan/single_layout_descriptor_set_pool.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_DESCRIPTOR_SET_POOL_H_
|
||||
#define XENIA_UI_VULKAN_SINGLE_DESCRIPTOR_SET_POOL_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
|
||||
class SingleLayoutDescriptorSetPool {
|
||||
public:
|
||||
// set_layout_descriptor_counts must contain the numbers of descriptors of
|
||||
// each type in a single set with the layout (the multiplication by the pool
|
||||
// set count will be done internally). The descriptor set layout must not be
|
||||
// destroyed until this object is also destroyed.
|
||||
SingleLayoutDescriptorSetPool(
|
||||
const VulkanProvider& provider, uint32_t pool_set_count,
|
||||
uint32_t set_layout_descriptor_counts_count,
|
||||
const VkDescriptorPoolSize* set_layout_descriptor_counts,
|
||||
VkDescriptorSetLayout set_layout);
|
||||
~SingleLayoutDescriptorSetPool();
|
||||
|
||||
// Returns SIZE_MAX in case of a failure.
|
||||
size_t Allocate();
|
||||
void Free(size_t index) {
|
||||
assert_true(index < descriptor_sets_.size());
|
||||
descriptor_sets_free_.push_back(index);
|
||||
}
|
||||
VkDescriptorSet Get(size_t index) const { return descriptor_sets_[index]; }
|
||||
|
||||
private:
|
||||
const VulkanProvider& provider_;
|
||||
uint32_t pool_set_count_;
|
||||
std::vector<VkDescriptorPoolSize> pool_descriptor_counts_;
|
||||
VkDescriptorSetLayout set_layout_;
|
||||
|
||||
std::vector<VkDescriptorPool> full_pools_;
|
||||
VkDescriptorPool current_pool_ = VK_NULL_HANDLE;
|
||||
uint32_t current_pool_sets_remaining_ = 0;
|
||||
|
||||
std::vector<VkDescriptorSet> descriptor_sets_;
|
||||
std::vector<size_t> descriptor_sets_free_;
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_VULKAN_SINGLE_DESCRIPTOR_SET_POOL_H_
|
||||
@@ -715,6 +715,8 @@ bool VulkanProvider::Initialize() {
|
||||
static const std::pair<const char*, size_t> kUsedDeviceExtensions[] = {
|
||||
{"VK_EXT_fragment_shader_interlock",
|
||||
offsetof(DeviceExtensions, ext_fragment_shader_interlock)},
|
||||
{"VK_EXT_shader_stencil_export",
|
||||
offsetof(DeviceExtensions, ext_shader_stencil_export)},
|
||||
{"VK_KHR_dedicated_allocation",
|
||||
offsetof(DeviceExtensions, khr_dedicated_allocation)},
|
||||
{"VK_KHR_image_format_list",
|
||||
@@ -946,6 +948,8 @@ bool VulkanProvider::Initialize() {
|
||||
XELOGVK("Vulkan device extensions:");
|
||||
XELOGVK("* VK_EXT_fragment_shader_interlock: {}",
|
||||
device_extensions_.ext_fragment_shader_interlock ? "yes" : "no");
|
||||
XELOGVK("* VK_EXT_shader_stencil_export: {}",
|
||||
device_extensions_.ext_shader_stencil_export ? "yes" : "no");
|
||||
XELOGVK("* VK_KHR_dedicated_allocation: {}",
|
||||
device_extensions_.khr_dedicated_allocation ? "yes" : "no");
|
||||
XELOGVK("* VK_KHR_image_format_list: {}",
|
||||
|
||||
@@ -132,6 +132,7 @@ class VulkanProvider : public GraphicsProvider {
|
||||
}
|
||||
struct DeviceExtensions {
|
||||
bool ext_fragment_shader_interlock;
|
||||
bool ext_shader_stencil_export;
|
||||
// Core since 1.1.0.
|
||||
bool khr_dedicated_allocation;
|
||||
// Core since 1.2.0.
|
||||
|
||||
@@ -189,6 +189,53 @@ bool CreateDedicatedAllocationImage(const VulkanProvider& provider,
|
||||
return true;
|
||||
}
|
||||
|
||||
VkPipeline CreateComputePipeline(
|
||||
const VulkanProvider& provider, VkPipelineLayout layout,
|
||||
VkShaderModule shader, const VkSpecializationInfo* specialization_info,
|
||||
const char* entry_point) {
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
|
||||
VkDevice device = provider.device();
|
||||
VkComputePipelineCreateInfo pipeline_create_info;
|
||||
pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
|
||||
pipeline_create_info.pNext = nullptr;
|
||||
pipeline_create_info.flags = 0;
|
||||
pipeline_create_info.stage.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
pipeline_create_info.stage.pNext = nullptr;
|
||||
pipeline_create_info.stage.flags = 0;
|
||||
pipeline_create_info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
pipeline_create_info.stage.module = shader;
|
||||
pipeline_create_info.stage.pName = entry_point;
|
||||
pipeline_create_info.stage.pSpecializationInfo = specialization_info;
|
||||
pipeline_create_info.layout = layout;
|
||||
pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
|
||||
pipeline_create_info.basePipelineIndex = -1;
|
||||
VkPipeline pipeline;
|
||||
if (dfn.vkCreateComputePipelines(device, VK_NULL_HANDLE, 1,
|
||||
&pipeline_create_info, nullptr,
|
||||
&pipeline) != VK_SUCCESS) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
VkPipeline CreateComputePipeline(
|
||||
const VulkanProvider& provider, VkPipelineLayout layout,
|
||||
const uint32_t* shader_code, size_t shader_code_size_bytes,
|
||||
const VkSpecializationInfo* specialization_info, const char* entry_point) {
|
||||
VkShaderModule shader =
|
||||
CreateShaderModule(provider, shader_code, shader_code_size_bytes);
|
||||
if (shader == VK_NULL_HANDLE) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
|
||||
VkDevice device = provider.device();
|
||||
VkPipeline pipeline = CreateComputePipeline(provider, layout, shader,
|
||||
specialization_info, entry_point);
|
||||
dfn.vkDestroyShaderModule(device, shader, nullptr);
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
|
||||
@@ -164,6 +164,17 @@ inline VkShaderModule CreateShaderModule(const VulkanProvider& provider,
|
||||
: VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VkPipeline CreateComputePipeline(
|
||||
const VulkanProvider& provider, VkPipelineLayout layout,
|
||||
VkShaderModule shader,
|
||||
const VkSpecializationInfo* specialization_info = nullptr,
|
||||
const char* entry_point = "main");
|
||||
VkPipeline CreateComputePipeline(
|
||||
const VulkanProvider& provider, VkPipelineLayout layout,
|
||||
const uint32_t* shader_code, size_t shader_code_size_bytes,
|
||||
const VkSpecializationInfo* specialization_info = nullptr,
|
||||
const char* entry_point = "main");
|
||||
|
||||
} // namespace util
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
|
||||
Reference in New Issue
Block a user