Vulkan: Add Memory Pool for External Pixel Buffers

Adds a separate memory pool for creating external pixel buffers.
Previous the memory type of images was used, but could not be
compatible.

Pull Request: https://projects.blender.org/blender/blender/pulls/146078
This commit is contained in:
Jeroen Bakker
2025-09-11 16:19:23 +02:00
parent 929110db04
commit 0c75361516
7 changed files with 163 additions and 63 deletions

View File

@@ -234,6 +234,7 @@ set(VULKAN_SRC
vulkan/vk_image_view.cc
vulkan/vk_immediate.cc
vulkan/vk_index_buffer.cc
vulkan/vk_memory_pool.cc
vulkan/vk_memory_layout.cc
vulkan/vk_pipeline_pool.cc
vulkan/vk_pixel_buffer.cc
@@ -283,6 +284,7 @@ set(VULKAN_SRC
vulkan/vk_immediate.hh
vulkan/vk_index_buffer.hh
vulkan/vk_memory.hh
vulkan/vk_memory_pool.hh
vulkan/vk_memory_layout.hh
vulkan/vk_pipeline_pool.hh
vulkan/vk_pixel_buffer.hh

View File

@@ -85,14 +85,11 @@ bool VKBuffer::create(size_t size_in_bytes,
if (export_memory) {
create_info.pNext = &external_memory_create_info;
#ifdef _WIN32
external_memory_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
#else
external_memory_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif
external_memory_create_info.handleTypes = vk_external_memory_handle_type();
/* Dedicated allocation for zero offset. */
vma_create_info.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
vma_create_info.pool = device.vma_pools.external_memory;
vma_create_info.pool = device.vma_pools.external_memory_pixel_buffer.pool;
}
const bool use_descriptor_buffer = device.extensions_get().descriptor_buffer;

View File

@@ -89,7 +89,7 @@ void VKDevice::deinit()
pipelines.write_to_disk();
pipelines.free_data();
descriptor_set_layouts_.deinit();
vmaDestroyPool(mem_allocator_, vma_pools.external_memory);
vma_pools.deinit(*this);
vmaDestroyAllocator(mem_allocator_);
mem_allocator_ = VK_NULL_HANDLE;
@@ -285,49 +285,8 @@ void VKDevice::init_memory_allocator()
if (!extensions_.external_memory) {
return;
}
/* External memory pool */
/* Initialize a dummy image create info to find the memory type index that will be used for
* allocating. */
VkExternalMemoryHandleTypeFlags vk_external_memory_handle_type = 0;
#ifdef _WIN32
vk_external_memory_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
#else
vk_external_memory_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif
VkExternalMemoryImageCreateInfo external_image_create_info = {
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
nullptr,
vk_external_memory_handle_type};
VkImageCreateInfo image_create_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
&external_image_create_info,
0,
VK_IMAGE_TYPE_2D,
VK_FORMAT_R8G8B8A8_UNORM,
{1024, 1024, 1},
1,
1,
VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT,
VK_SHARING_MODE_EXCLUSIVE,
0,
nullptr,
VK_IMAGE_LAYOUT_UNDEFINED};
VmaAllocationCreateInfo allocation_create_info = {};
allocation_create_info.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
allocation_create_info.usage = VMA_MEMORY_USAGE_AUTO;
uint32_t memory_type_index;
vmaFindMemoryTypeIndexForImageInfo(
mem_allocator_, &image_create_info, &allocation_create_info, &memory_type_index);
vma_pools.external_memory_info.handleTypes = vk_external_memory_handle_type;
VmaPoolCreateInfo pool_create_info = {};
pool_create_info.memoryTypeIndex = memory_type_index;
pool_create_info.pMemoryAllocateNext = &vma_pools.external_memory_info;
pool_create_info.priority = 1.0f;
vmaCreatePool(mem_allocator_, &pool_create_info, &vma_pools.external_memory);
vma_pools.init(*this);
}
void VKDevice::init_dummy_buffer()

View File

@@ -22,6 +22,7 @@
#include "vk_debug.hh"
#include "vk_descriptor_pools.hh"
#include "vk_descriptor_set_layouts.hh"
#include "vk_memory_pool.hh"
#include "vk_pipeline_pool.hh"
#include "vk_resource_pool.hh"
#include "vk_samplers.hh"
@@ -247,13 +248,7 @@ class VKDevice : public NonCopyable {
} functions;
struct {
/* NOTE: This attribute needs to be kept alive as it will be read by VMA when allocating from
* `external_memory` pool. */
VkExportMemoryAllocateInfoKHR external_memory_info = {
VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR};
VmaPool external_memory = VK_NULL_HANDLE;
} vma_pools;
VKMemoryPools vma_pools;
const char *extension_name_get(int index) const
{
@@ -317,7 +312,7 @@ class VKDevice : public NonCopyable {
return vk_queue_family_;
}
VmaAllocator mem_allocator_get() const
inline VmaAllocator mem_allocator_get() const
{
return mem_allocator_;
}

View File

@@ -0,0 +1,102 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#include "vk_memory_pool.hh"
#include "vk_device.hh"
namespace blender::gpu {
void VKMemoryPools::init(VKDevice &device)
{
init_external_memory_image(device);
init_external_memory_pixel_buffer(device);
}
void VKMemoryPools::init_external_memory_image(VKDevice &device)
{
VkExternalMemoryImageCreateInfo external_image_create_info = {
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
nullptr,
vk_external_memory_handle_type()};
VkImageCreateInfo image_create_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
&external_image_create_info,
0,
VK_IMAGE_TYPE_2D,
VK_FORMAT_R8G8B8A8_UNORM,
{1024, 1024, 1},
1,
1,
VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT,
VK_SHARING_MODE_EXCLUSIVE,
0,
nullptr,
VK_IMAGE_LAYOUT_UNDEFINED};
VmaAllocationCreateInfo allocation_create_info = {};
allocation_create_info.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
allocation_create_info.usage = VMA_MEMORY_USAGE_AUTO;
uint32_t memory_type_index;
vmaFindMemoryTypeIndexForImageInfo(
device.mem_allocator_get(), &image_create_info, &allocation_create_info, &memory_type_index);
external_memory_image.info.handleTypes = vk_external_memory_handle_type();
VmaPoolCreateInfo pool_create_info = {};
pool_create_info.memoryTypeIndex = memory_type_index;
pool_create_info.pMemoryAllocateNext = &external_memory_image.info;
pool_create_info.priority = 1.0f;
vmaCreatePool(device.mem_allocator_get(), &pool_create_info, &external_memory_image.pool);
}
void VKMemoryPools::init_external_memory_pixel_buffer(VKDevice &device)
{
VkExternalMemoryBufferCreateInfo external_buffer_create_info = {
VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
nullptr,
vk_external_memory_handle_type()};
VkBufferCreateInfo buffer_create_info = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
&external_buffer_create_info,
0,
1024,
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_SHARING_MODE_EXCLUSIVE,
0,
nullptr};
VmaAllocationCreateInfo allocation_create_info = {};
allocation_create_info.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
allocation_create_info.usage = VMA_MEMORY_USAGE_AUTO;
uint32_t memory_type_index;
vmaFindMemoryTypeIndexForBufferInfo(device.mem_allocator_get(),
&buffer_create_info,
&allocation_create_info,
&memory_type_index);
external_memory_pixel_buffer.info.handleTypes = vk_external_memory_handle_type();
VmaPoolCreateInfo pool_create_info = {};
pool_create_info.memoryTypeIndex = memory_type_index;
pool_create_info.pMemoryAllocateNext = &external_memory_pixel_buffer.info;
pool_create_info.priority = 1.0f;
vmaCreatePool(device.mem_allocator_get(), &pool_create_info, &external_memory_pixel_buffer.pool);
}
void VKMemoryPools::deinit(VKDevice &device)
{
external_memory_image.deinit(device);
external_memory_pixel_buffer.deinit(device);
}
void VKMemoryPool::deinit(VKDevice &device)
{
vmaDestroyPool(device.mem_allocator_get(), pool);
}
} // namespace blender::gpu

View File

@@ -0,0 +1,49 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#pragma once
#include "vk_common.hh"
namespace blender::gpu {
class VKDevice;
constexpr VkExternalMemoryHandleTypeFlags vk_external_memory_handle_type()
{
#ifdef _WIN32
return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
#else
return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif
}
/**
* VMA related data for a memory pool.
*/
struct VKMemoryPool {
/* NOTE: This attribute needs to be kept alive as it will be read by VMA when allocating inside
* the pool. */
VkExportMemoryAllocateInfoKHR info = {VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR};
VmaPool pool = VK_NULL_HANDLE;
void deinit(VKDevice &device);
};
struct VKMemoryPools {
VKMemoryPool external_memory_image = {};
VKMemoryPool external_memory_pixel_buffer = {};
void init(VKDevice &device);
void deinit(VKDevice &device);
private:
void init_external_memory_image(VKDevice &device);
void init_external_memory_pixel_buffer(VKDevice &device);
};
} // namespace blender::gpu

View File

@@ -711,12 +711,8 @@ bool VKTexture::allocate()
if (bool(texture_usage & GPU_TEXTURE_USAGE_MEMORY_EXPORT)) {
image_info.pNext = &external_memory_create_info;
#ifdef _WIN32
external_memory_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
#else
external_memory_create_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
#endif
allocCreateInfo.pool = device.vma_pools.external_memory;
external_memory_create_info.handleTypes = vk_external_memory_handle_type();
allocCreateInfo.pool = device.vma_pools.external_memory_image.pool;
}
result = vmaCreateImage(device.mem_allocator_get(),
&image_info,