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_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_height = m_frame->client_height();
if (!m_swapchain->init(m_client_width, m_client_height))
@ -782,7 +770,6 @@ VKGSRender::~VKGSRender()
//Device handles/contexts
m_swapchain->destroy();
m_mem_allocator->destroy();
m_thread_context.close();
#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::shader_cache> m_shaders_cache;
std::shared_ptr<vk::mem_allocator_base> m_mem_allocator;
private:
std::unique_ptr<VKProgramBuffer> m_prog_buffer;

View File

@ -4,20 +4,19 @@
namespace vk
{
context* g_current_vulkan_ctx = nullptr;
render_device g_current_renderer;
driver_vendor g_driver_vendor = driver_vendor::unknown;
std::shared_ptr<vk::mem_allocator_base> g_mem_allocator = nullptr;
const context* g_current_vulkan_ctx = nullptr;
const render_device* g_current_renderer;
std::unique_ptr<image> g_null_texture;
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;
atomic_t<bool> g_cb_no_interrupt_flag { false };
//Driver compatibility workarounds
driver_vendor g_driver_vendor = driver_vendor::unknown;
bool g_drv_no_primitive_restart_flag = false;
bool g_drv_sanitize_fp_values = false;
bool g_drv_disable_fence_reset = false;
@ -141,7 +140,7 @@ namespace vk
sampler_info.compareOp = VK_COMPARE_OP_NEVER;
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;
}
@ -150,11 +149,11 @@ namespace vk
if (g_null_image_view)
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_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_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}));
@ -173,12 +172,12 @@ namespace vk
{
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_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)
{
auto _img = create_texture();
@ -206,39 +205,35 @@ namespace vk
g_typeless_textures.clear();
if (g_null_sampler)
vkDestroySampler(g_current_renderer, g_null_sampler, nullptr);
vkDestroySampler(*g_current_renderer, 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;
}
std::shared_ptr<vk::mem_allocator_base> get_current_mem_allocator()
{
return g_mem_allocator;
verify (HERE, g_current_renderer);
return g_current_renderer->get_allocator();
}
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;
}
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)
{
g_current_renderer = device;
g_current_renderer = &device;
g_cb_no_interrupt_flag.store(false);
g_drv_no_primitive_restart_flag = false;
g_drv_sanitize_fp_values = false;
@ -247,7 +242,7 @@ namespace vk
g_num_total_frames = 0;
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
//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)
{
vkDestroyFence(g_current_renderer, *pFence, nullptr);
vkDestroyFence(*g_current_renderer, *pFence, nullptr);
VkFenceCreateInfo 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
{
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 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);
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_mem_allocator(std::shared_ptr<vk::mem_allocator_base> mem_allocator);
std::shared_ptr<vk::mem_allocator_base> get_current_mem_allocator();
mem_allocator_base *get_current_mem_allocator();
//Compatibility workarounds
bool emulate_primitive_restart(rsx::primitive_type type);
@ -167,178 +166,6 @@ namespace vk
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
class mem_allocator_base
@ -530,10 +357,200 @@ namespace vk
private:
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;
};
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
{
VkImage value = VK_NULL_HANDLE;
@ -542,7 +559,7 @@ namespace vk
VkImageCreateInfo info = {};
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 access_flags,
VkImageType image_type,
@ -1179,7 +1196,7 @@ public:
public:
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 (_present_queue < UINT32_MAX) vkGetDeviceQueue(dev, _present_queue, 0, &vk_present_queue);