Refactoring

- Make the memory allocator a unique child of the render device.
  Fixes object lifetime issues with swapchain management due to cyclic dependencies
This commit is contained in:
kd-11 2018-06-06 20:34:55 +03:00 committed by kd-11
parent c9e367befd
commit 63f803b68a
4 changed files with 218 additions and 221 deletions

View file

@ -547,18 +547,6 @@ VKGSRender::VKGSRender() : GSRender()
vk::set_current_thread_ctx(m_thread_context); vk::set_current_thread_ctx(m_thread_context);
vk::set_current_renderer(m_swapchain->get_device()); vk::set_current_renderer(m_swapchain->get_device());
// Choose memory allocator (device memory)
if (g_cfg.video.disable_vulkan_mem_allocator)
{
m_mem_allocator = std::make_shared<vk::mem_allocator_vk>(*m_device, m_device->gpu());
}
else
{
m_mem_allocator = std::make_shared<vk::mem_allocator_vma>(*m_device, m_device->gpu());
}
vk::set_current_mem_allocator(m_mem_allocator);
m_client_width = m_frame->client_width(); m_client_width = m_frame->client_width();
m_client_height = m_frame->client_height(); m_client_height = m_frame->client_height();
if (!m_swapchain->init(m_client_width, m_client_height)) if (!m_swapchain->init(m_client_width, m_client_height))
@ -782,7 +770,6 @@ VKGSRender::~VKGSRender()
//Device handles/contexts //Device handles/contexts
m_swapchain->destroy(); m_swapchain->destroy();
m_mem_allocator->destroy();
m_thread_context.close(); m_thread_context.close();
#if !defined(_WIN32) && defined(HAVE_VULKAN) #if !defined(_WIN32) && defined(HAVE_VULKAN)

View file

@ -287,8 +287,6 @@ public:
std::unique_ptr<vk::vertex_cache> m_vertex_cache; std::unique_ptr<vk::vertex_cache> m_vertex_cache;
std::unique_ptr<vk::shader_cache> m_shaders_cache; std::unique_ptr<vk::shader_cache> m_shaders_cache;
std::shared_ptr<vk::mem_allocator_base> m_mem_allocator;
private: private:
std::unique_ptr<VKProgramBuffer> m_prog_buffer; std::unique_ptr<VKProgramBuffer> m_prog_buffer;

View file

@ -4,20 +4,19 @@
namespace vk namespace vk
{ {
context* g_current_vulkan_ctx = nullptr; const context* g_current_vulkan_ctx = nullptr;
render_device g_current_renderer; const render_device* g_current_renderer;
driver_vendor g_driver_vendor = driver_vendor::unknown;
std::shared_ptr<vk::mem_allocator_base> g_mem_allocator = nullptr;
std::unique_ptr<image> g_null_texture; std::unique_ptr<image> g_null_texture;
std::unique_ptr<image_view> g_null_image_view; std::unique_ptr<image_view> g_null_image_view;
std::unordered_map<VkFormat, std::unique_ptr<image>> g_typeless_textures; std::unordered_map<u32, std::unique_ptr<image>> g_typeless_textures;
VkSampler g_null_sampler = nullptr; VkSampler g_null_sampler = nullptr;
atomic_t<bool> g_cb_no_interrupt_flag { false }; atomic_t<bool> g_cb_no_interrupt_flag { false };
//Driver compatibility workarounds //Driver compatibility workarounds
driver_vendor g_driver_vendor = driver_vendor::unknown;
bool g_drv_no_primitive_restart_flag = false; bool g_drv_no_primitive_restart_flag = false;
bool g_drv_sanitize_fp_values = false; bool g_drv_sanitize_fp_values = false;
bool g_drv_disable_fence_reset = false; bool g_drv_disable_fence_reset = false;
@ -141,7 +140,7 @@ namespace vk
sampler_info.compareOp = VK_COMPARE_OP_NEVER; sampler_info.compareOp = VK_COMPARE_OP_NEVER;
sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
vkCreateSampler(g_current_renderer, &sampler_info, nullptr, &g_null_sampler); vkCreateSampler(*g_current_renderer, &sampler_info, nullptr, &g_null_sampler);
return g_null_sampler; return g_null_sampler;
} }
@ -150,11 +149,11 @@ namespace vk
if (g_null_image_view) if (g_null_image_view)
return g_null_image_view->value; return g_null_image_view->value;
g_null_texture.reset(new image(g_current_renderer, g_current_renderer.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, g_null_texture.reset(new image(*g_current_renderer, g_current_renderer->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, VK_FORMAT_B8G8R8A8_UNORM, 4, 4, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TYPE_2D, VK_FORMAT_B8G8R8A8_UNORM, 4, 4, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0)); VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0));
g_null_image_view.reset(new image_view(g_current_renderer, g_null_texture->value, VK_IMAGE_VIEW_TYPE_2D, g_null_image_view.reset(new image_view(*g_current_renderer, g_null_texture->value, VK_IMAGE_VIEW_TYPE_2D,
VK_FORMAT_B8G8R8A8_UNORM, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}, VK_FORMAT_B8G8R8A8_UNORM, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A},
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1})); {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}));
@ -173,12 +172,12 @@ namespace vk
{ {
auto create_texture = [&]() auto create_texture = [&]()
{ {
return new vk::image(g_current_renderer, g_current_renderer.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, return new vk::image(*g_current_renderer, g_current_renderer->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, format, 4096, 4096, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_TYPE_2D, format, 4096, 4096, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0); VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 0);
}; };
auto &ptr = g_typeless_textures[format]; auto &ptr = g_typeless_textures[(u32)format];
if (!ptr) if (!ptr)
{ {
auto _img = create_texture(); auto _img = create_texture();
@ -206,39 +205,35 @@ namespace vk
g_typeless_textures.clear(); g_typeless_textures.clear();
if (g_null_sampler) if (g_null_sampler)
vkDestroySampler(g_current_renderer, g_null_sampler, nullptr); vkDestroySampler(*g_current_renderer, g_null_sampler, nullptr);
g_null_sampler = nullptr; g_null_sampler = nullptr;
} }
void set_current_mem_allocator(std::shared_ptr<vk::mem_allocator_base> mem_allocator) vk::mem_allocator_base* get_current_mem_allocator()
{ {
g_mem_allocator = mem_allocator; verify (HERE, g_current_renderer);
} return g_current_renderer->get_allocator();
std::shared_ptr<vk::mem_allocator_base> get_current_mem_allocator()
{
return g_mem_allocator;
} }
void set_current_thread_ctx(const vk::context &ctx) void set_current_thread_ctx(const vk::context &ctx)
{ {
g_current_vulkan_ctx = (vk::context *)&ctx; g_current_vulkan_ctx = &ctx;
} }
context *get_current_thread_ctx() const context *get_current_thread_ctx()
{ {
return g_current_vulkan_ctx; return g_current_vulkan_ctx;
} }
vk::render_device *get_current_renderer() const vk::render_device *get_current_renderer()
{ {
return &g_current_renderer; return g_current_renderer;
} }
void set_current_renderer(const vk::render_device &device) void set_current_renderer(const vk::render_device &device)
{ {
g_current_renderer = device; g_current_renderer = &device;
g_cb_no_interrupt_flag.store(false); g_cb_no_interrupt_flag.store(false);
g_drv_no_primitive_restart_flag = false; g_drv_no_primitive_restart_flag = false;
g_drv_sanitize_fp_values = false; g_drv_sanitize_fp_values = false;
@ -247,7 +242,7 @@ namespace vk
g_num_total_frames = 0; g_num_total_frames = 0;
g_driver_vendor = driver_vendor::unknown; g_driver_vendor = driver_vendor::unknown;
const auto gpu_name = g_current_renderer.gpu().name(); const auto gpu_name = g_current_renderer->gpu().name();
//Radeon fails to properly handle degenerate primitives if primitive restart is enabled //Radeon fails to properly handle degenerate primitives if primitive restart is enabled
//One has to choose between using degenerate primitives or primitive restart to break up lists but not both //One has to choose between using degenerate primitives or primitive restart to break up lists but not both
@ -488,15 +483,15 @@ namespace vk
{ {
if (g_drv_disable_fence_reset) if (g_drv_disable_fence_reset)
{ {
vkDestroyFence(g_current_renderer, *pFence, nullptr); vkDestroyFence(*g_current_renderer, *pFence, nullptr);
VkFenceCreateInfo info = {}; VkFenceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
CHECK_RESULT(vkCreateFence(g_current_renderer, &info, nullptr, pFence)); CHECK_RESULT(vkCreateFence(*g_current_renderer, &info, nullptr, pFence));
} }
else else
{ {
CHECK_RESULT(vkResetFences(g_current_renderer, 1, pFence)); CHECK_RESULT(vkResetFences(*g_current_renderer, 1, pFence));
} }
} }

View file

@ -77,14 +77,13 @@ namespace vk
struct memory_type_mapping; struct memory_type_mapping;
struct gpu_formats_support; struct gpu_formats_support;
vk::context *get_current_thread_ctx(); const vk::context *get_current_thread_ctx();
void set_current_thread_ctx(const vk::context &ctx); void set_current_thread_ctx(const vk::context &ctx);
vk::render_device *get_current_renderer(); const vk::render_device *get_current_renderer();
void set_current_renderer(const vk::render_device &device); void set_current_renderer(const vk::render_device &device);
void set_current_mem_allocator(std::shared_ptr<vk::mem_allocator_base> mem_allocator); mem_allocator_base *get_current_mem_allocator();
std::shared_ptr<vk::mem_allocator_base> get_current_mem_allocator();
//Compatibility workarounds //Compatibility workarounds
bool emulate_primitive_restart(rsx::primitive_type type); bool emulate_primitive_restart(rsx::primitive_type type);
@ -167,178 +166,6 @@ namespace vk
bool d32_sfloat_s8; bool d32_sfloat_s8;
}; };
class physical_device
{
VkPhysicalDevice dev = nullptr;
VkPhysicalDeviceProperties props;
VkPhysicalDeviceMemoryProperties memory_properties;
std::vector<VkQueueFamilyProperties> queue_props;
public:
physical_device() {}
~physical_device() {}
void set_device(VkPhysicalDevice pdev)
{
dev = pdev;
vkGetPhysicalDeviceProperties(pdev, &props);
vkGetPhysicalDeviceMemoryProperties(pdev, &memory_properties);
}
std::string name() const
{
return props.deviceName;
}
uint32_t get_queue_count() const
{
if (queue_props.size())
return (u32)queue_props.size();
uint32_t count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, nullptr);
return count;
}
VkQueueFamilyProperties get_queue_properties(uint32_t queue)
{
if (!queue_props.size())
{
uint32_t count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, nullptr);
queue_props.resize(count);
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, queue_props.data());
}
if (queue >= queue_props.size()) fmt::throw_exception("Bad queue index passed to get_queue_properties (%u)" HERE, queue);
return queue_props[queue];
}
VkPhysicalDeviceMemoryProperties get_memory_properties() const
{
return memory_properties;
}
operator VkPhysicalDevice() const
{
return dev;
}
};
class render_device
{
physical_device *pgpu = nullptr;
memory_type_mapping memory_map{};
gpu_formats_support m_formats_support{};
VkDevice dev = VK_NULL_HANDLE;
public:
render_device()
{}
render_device(vk::physical_device &pdev, uint32_t graphics_queue_idx)
{
float queue_priorities[1] = { 0.f };
pgpu = &pdev;
VkDeviceQueueCreateInfo queue = {};
queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue.pNext = NULL;
queue.queueFamilyIndex = graphics_queue_idx;
queue.queueCount = 1;
queue.pQueuePriorities = queue_priorities;
//Set up instance information
const char *requested_extensions[] =
{
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
//Enable hardware features manually
//Currently we require:
//1. Anisotropic sampling
//2. DXT support
VkPhysicalDeviceFeatures available_features;
vkGetPhysicalDeviceFeatures(*pgpu, &available_features);
available_features.samplerAnisotropy = VK_TRUE;
available_features.textureCompressionBC = VK_TRUE;
VkDeviceCreateInfo device = {};
device.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device.pNext = NULL;
device.queueCreateInfoCount = 1;
device.pQueueCreateInfos = &queue;
device.enabledLayerCount = 0;
device.ppEnabledLayerNames = nullptr; // Deprecated
device.enabledExtensionCount = 1;
device.ppEnabledExtensionNames = requested_extensions;
device.pEnabledFeatures = &available_features;
CHECK_RESULT(vkCreateDevice(*pgpu, &device, nullptr, &dev));
memory_map = vk::get_memory_mapping(pdev);
m_formats_support = vk::get_optimal_tiling_supported_formats(pdev);
}
~render_device()
{
}
void destroy()
{
if (dev && pgpu)
{
vkDestroyDevice(dev, nullptr);
dev = nullptr;
}
}
bool get_compatible_memory_type(u32 typeBits, u32 desired_mask, u32 *type_index)
{
VkPhysicalDeviceMemoryProperties mem_infos = pgpu->get_memory_properties();
for (uint32_t i = 0; i < 32; i++)
{
if ((typeBits & 1) == 1)
{
if ((mem_infos.memoryTypes[i].propertyFlags & desired_mask) == desired_mask)
{
*type_index = i;
return true;
}
}
typeBits >>= 1;
}
return false;
}
const physical_device& gpu() const
{
return *pgpu;
}
const memory_type_mapping& get_memory_mapping() const
{
return memory_map;
}
const gpu_formats_support& get_formats_support() const
{
return m_formats_support;
}
operator VkDevice&()
{
return dev;
}
};
// Memory Allocator - base class // Memory Allocator - base class
class mem_allocator_base class mem_allocator_base
@ -530,10 +357,200 @@ namespace vk
private: private:
VkDevice m_device; VkDevice m_device;
std::shared_ptr<vk::mem_allocator_base> m_mem_allocator; vk::mem_allocator_base* m_mem_allocator;
mem_allocator_base::mem_handle_t m_mem_handle; mem_allocator_base::mem_handle_t m_mem_handle;
}; };
class physical_device
{
VkPhysicalDevice dev = nullptr;
VkPhysicalDeviceProperties props;
VkPhysicalDeviceMemoryProperties memory_properties;
std::vector<VkQueueFamilyProperties> queue_props;
public:
physical_device() {}
~physical_device() {}
void set_device(VkPhysicalDevice pdev)
{
dev = pdev;
vkGetPhysicalDeviceProperties(pdev, &props);
vkGetPhysicalDeviceMemoryProperties(pdev, &memory_properties);
}
std::string name() const
{
return props.deviceName;
}
uint32_t get_queue_count() const
{
if (queue_props.size())
return (u32)queue_props.size();
uint32_t count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, nullptr);
return count;
}
VkQueueFamilyProperties get_queue_properties(uint32_t queue)
{
if (!queue_props.size())
{
uint32_t count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, nullptr);
queue_props.resize(count);
vkGetPhysicalDeviceQueueFamilyProperties(dev, &count, queue_props.data());
}
if (queue >= queue_props.size()) fmt::throw_exception("Bad queue index passed to get_queue_properties (%u)" HERE, queue);
return queue_props[queue];
}
VkPhysicalDeviceMemoryProperties get_memory_properties() const
{
return memory_properties;
}
operator VkPhysicalDevice() const
{
return dev;
}
};
class render_device
{
physical_device *pgpu = nullptr;
memory_type_mapping memory_map{};
gpu_formats_support m_formats_support{};
std::unique_ptr<mem_allocator_base> m_allocator;
VkDevice dev = VK_NULL_HANDLE;
public:
render_device()
{}
~render_device()
{}
void create(vk::physical_device &pdev, uint32_t graphics_queue_idx)
{
float queue_priorities[1] = { 0.f };
pgpu = &pdev;
VkDeviceQueueCreateInfo queue = {};
queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue.pNext = NULL;
queue.queueFamilyIndex = graphics_queue_idx;
queue.queueCount = 1;
queue.pQueuePriorities = queue_priorities;
//Set up instance information
const char *requested_extensions[] =
{
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
//Enable hardware features manually
//Currently we require:
//1. Anisotropic sampling
//2. DXT support
VkPhysicalDeviceFeatures available_features;
vkGetPhysicalDeviceFeatures(*pgpu, &available_features);
available_features.samplerAnisotropy = VK_TRUE;
available_features.textureCompressionBC = VK_TRUE;
VkDeviceCreateInfo device = {};
device.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device.pNext = NULL;
device.queueCreateInfoCount = 1;
device.pQueueCreateInfos = &queue;
device.enabledLayerCount = 0;
device.ppEnabledLayerNames = nullptr; // Deprecated
device.enabledExtensionCount = 1;
device.ppEnabledExtensionNames = requested_extensions;
device.pEnabledFeatures = &available_features;
CHECK_RESULT(vkCreateDevice(*pgpu, &device, nullptr, &dev));
memory_map = vk::get_memory_mapping(pdev);
m_formats_support = vk::get_optimal_tiling_supported_formats(pdev);
if (g_cfg.video.disable_vulkan_mem_allocator)
m_allocator = std::make_unique<vk::mem_allocator_vk>(dev, pdev);
else
m_allocator = std::make_unique<vk::mem_allocator_vma>(dev, pdev);
}
void destroy()
{
if (dev && pgpu)
{
if (m_allocator)
{
m_allocator->destroy();
m_allocator.reset();
}
vkDestroyDevice(dev, nullptr);
dev = nullptr;
memory_map = {};
m_formats_support = {};
}
}
bool get_compatible_memory_type(u32 typeBits, u32 desired_mask, u32 *type_index) const
{
VkPhysicalDeviceMemoryProperties mem_infos = pgpu->get_memory_properties();
for (uint32_t i = 0; i < 32; i++)
{
if ((typeBits & 1) == 1)
{
if ((mem_infos.memoryTypes[i].propertyFlags & desired_mask) == desired_mask)
{
*type_index = i;
return true;
}
}
typeBits >>= 1;
}
return false;
}
const physical_device& gpu() const
{
return *pgpu;
}
const memory_type_mapping& get_memory_mapping() const
{
return memory_map;
}
const gpu_formats_support& get_formats_support() const
{
return m_formats_support;
}
mem_allocator_base* get_allocator() const
{
return m_allocator.get();
}
operator VkDevice() const
{
return dev;
}
};
struct image struct image
{ {
VkImage value = VK_NULL_HANDLE; VkImage value = VK_NULL_HANDLE;
@ -542,7 +559,7 @@ namespace vk
VkImageCreateInfo info = {}; VkImageCreateInfo info = {};
std::shared_ptr<vk::memory_block> memory; std::shared_ptr<vk::memory_block> memory;
image(vk::render_device &dev, image(const vk::render_device &dev,
uint32_t memory_type_index, uint32_t memory_type_index,
uint32_t access_flags, uint32_t access_flags,
VkImageType image_type, VkImageType image_type,
@ -1179,7 +1196,7 @@ public:
public: public:
swapchain_base(physical_device &gpu, uint32_t _present_queue, uint32_t _graphics_queue, VkFormat format = VK_FORMAT_B8G8R8A8_UNORM) swapchain_base(physical_device &gpu, uint32_t _present_queue, uint32_t _graphics_queue, VkFormat format = VK_FORMAT_B8G8R8A8_UNORM)
{ {
dev = render_device(gpu, _graphics_queue); dev.create(gpu, _graphics_queue);
if (_graphics_queue < UINT32_MAX) vkGetDeviceQueue(dev, _graphics_queue, 0, &vk_graphics_queue); if (_graphics_queue < UINT32_MAX) vkGetDeviceQueue(dev, _graphics_queue, 0, &vk_graphics_queue);
if (_present_queue < UINT32_MAX) vkGetDeviceQueue(dev, _present_queue, 0, &vk_present_queue); if (_present_queue < UINT32_MAX) vkGetDeviceQueue(dev, _present_queue, 0, &vk_present_queue);