49a15148fa
Move VkDeviceMemory functions to the new files. Signed-off-by: Chia-I Wu <olvaffe@gmail.com> Reviewed-by: Yiwei Zhang <zzyiwei@chromium.org> Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com> Reviewed-by: Ryan Neph <ryanneph@google.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10117>
421 lines
13 KiB
C
421 lines
13 KiB
C
/*
|
|
* Copyright 2019 Google LLC
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* based in part on anv and radv which are:
|
|
* Copyright © 2015 Intel Corporation
|
|
* Copyright © 2016 Red Hat.
|
|
* Copyright © 2016 Bas Nieuwenhuizen
|
|
*/
|
|
|
|
#include "vn_device_memory.h"
|
|
|
|
#include "venus-protocol/vn_protocol_driver_device_memory.h"
|
|
|
|
#include "vn_device.h"
|
|
|
|
/* device memory commands */
|
|
|
|
static VkResult
|
|
vn_device_memory_simple_alloc(struct vn_device *dev,
|
|
uint32_t mem_type_index,
|
|
VkDeviceSize size,
|
|
struct vn_device_memory **out_mem)
|
|
{
|
|
const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
|
|
|
|
struct vn_device_memory *mem =
|
|
vk_zalloc(alloc, sizeof(*mem), VN_DEFAULT_ALIGN,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
|
|
if (!mem)
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
|
|
vn_object_base_init(&mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY, &dev->base);
|
|
mem->size = size;
|
|
|
|
VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem);
|
|
VkResult result = vn_call_vkAllocateMemory(
|
|
dev->instance, vn_device_to_handle(dev),
|
|
&(const VkMemoryAllocateInfo){
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
.allocationSize = size,
|
|
.memoryTypeIndex = mem_type_index,
|
|
},
|
|
NULL, &mem_handle);
|
|
if (result != VK_SUCCESS) {
|
|
vk_free(alloc, mem);
|
|
return result;
|
|
}
|
|
|
|
const VkPhysicalDeviceMemoryProperties *mem_props =
|
|
&dev->physical_device->memory_properties.memoryProperties;
|
|
const VkMemoryType *mem_type = &mem_props->memoryTypes[mem_type_index];
|
|
result = vn_renderer_bo_create_gpu(dev->instance->renderer, mem->size,
|
|
mem->base.id, mem_type->propertyFlags,
|
|
0, &mem->base_bo);
|
|
if (result != VK_SUCCESS) {
|
|
vn_async_vkFreeMemory(dev->instance, vn_device_to_handle(dev),
|
|
mem_handle, NULL);
|
|
vk_free(alloc, mem);
|
|
return result;
|
|
}
|
|
vn_instance_roundtrip(dev->instance);
|
|
|
|
*out_mem = mem;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
vn_device_memory_simple_free(struct vn_device *dev,
|
|
struct vn_device_memory *mem)
|
|
{
|
|
const VkAllocationCallbacks *alloc = &dev->base.base.alloc;
|
|
|
|
if (mem->base_bo)
|
|
vn_renderer_bo_unref(mem->base_bo);
|
|
|
|
vn_async_vkFreeMemory(dev->instance, vn_device_to_handle(dev),
|
|
vn_device_memory_to_handle(mem), NULL);
|
|
vn_object_base_fini(&mem->base);
|
|
vk_free(alloc, mem);
|
|
}
|
|
|
|
void
|
|
vn_device_memory_pool_fini(struct vn_device *dev, uint32_t mem_type_index)
|
|
{
|
|
struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];
|
|
if (pool->memory)
|
|
vn_device_memory_simple_free(dev, pool->memory);
|
|
mtx_destroy(&pool->mutex);
|
|
}
|
|
|
|
static VkResult
|
|
vn_device_memory_pool_grow_locked(struct vn_device *dev,
|
|
uint32_t mem_type_index,
|
|
VkDeviceSize size)
|
|
{
|
|
struct vn_device_memory *mem;
|
|
VkResult result =
|
|
vn_device_memory_simple_alloc(dev, mem_type_index, size, &mem);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];
|
|
if (pool->memory) {
|
|
const bool bo_destroyed = vn_renderer_bo_unref(pool->memory->base_bo);
|
|
pool->memory->base_bo = NULL;
|
|
|
|
/* we use pool->memory's base_bo to keep it alive */
|
|
if (bo_destroyed)
|
|
vn_device_memory_simple_free(dev, pool->memory);
|
|
}
|
|
|
|
pool->memory = mem;
|
|
pool->used = 0;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static VkResult
|
|
vn_device_memory_pool_alloc(struct vn_device *dev,
|
|
uint32_t mem_type_index,
|
|
VkDeviceSize size,
|
|
struct vn_device_memory **base_mem,
|
|
struct vn_renderer_bo **base_bo,
|
|
VkDeviceSize *base_offset)
|
|
{
|
|
/* We should not support suballocations because apps can do better and we
|
|
* also don't know the alignment requirements. But each BO takes up a
|
|
* precious KVM memslot currently and some CTS tests exhausts them...
|
|
*/
|
|
const VkDeviceSize pool_size = 16 * 1024 * 1024;
|
|
const VkDeviceSize pool_align = 4096; /* XXX */
|
|
struct vn_device_memory_pool *pool = &dev->memory_pools[mem_type_index];
|
|
|
|
assert(size <= pool_size);
|
|
|
|
mtx_lock(&pool->mutex);
|
|
|
|
if (!pool->memory || pool->used + size > pool_size) {
|
|
VkResult result =
|
|
vn_device_memory_pool_grow_locked(dev, mem_type_index, pool_size);
|
|
if (result != VK_SUCCESS) {
|
|
mtx_unlock(&pool->mutex);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/* we use base_bo to keep base_mem alive */
|
|
*base_mem = pool->memory;
|
|
*base_bo = vn_renderer_bo_ref(pool->memory->base_bo);
|
|
|
|
*base_offset = pool->used;
|
|
pool->used += align64(size, pool_align);
|
|
|
|
mtx_unlock(&pool->mutex);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
vn_device_memory_pool_free(struct vn_device *dev,
|
|
struct vn_device_memory *base_mem,
|
|
struct vn_renderer_bo *base_bo)
|
|
{
|
|
/* we use base_bo to keep base_mem alive */
|
|
if (vn_renderer_bo_unref(base_bo))
|
|
vn_device_memory_simple_free(dev, base_mem);
|
|
}
|
|
|
|
VkResult
|
|
vn_AllocateMemory(VkDevice device,
|
|
const VkMemoryAllocateInfo *pAllocateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkDeviceMemory *pMemory)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
const VkPhysicalDeviceMemoryProperties *mem_props =
|
|
&dev->physical_device->memory_properties.memoryProperties;
|
|
const VkMemoryType *mem_type =
|
|
&mem_props->memoryTypes[pAllocateInfo->memoryTypeIndex];
|
|
const VkImportMemoryFdInfoKHR *import_info =
|
|
vk_find_struct_const(pAllocateInfo->pNext, IMPORT_MEMORY_FD_INFO_KHR);
|
|
const VkExportMemoryAllocateInfo *export_info =
|
|
vk_find_struct_const(pAllocateInfo->pNext, EXPORT_MEMORY_ALLOCATE_INFO);
|
|
if (export_info && !export_info->handleTypes)
|
|
export_info = NULL;
|
|
|
|
const bool need_bo =
|
|
(mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ||
|
|
import_info || export_info;
|
|
const bool suballocate =
|
|
need_bo && !pAllocateInfo->pNext &&
|
|
!(mem_type->propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) &&
|
|
pAllocateInfo->allocationSize <= 64 * 1024;
|
|
|
|
struct vn_device_memory *mem =
|
|
vk_zalloc(alloc, sizeof(*mem), VN_DEFAULT_ALIGN,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (!mem)
|
|
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
vn_object_base_init(&mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY, &dev->base);
|
|
mem->size = pAllocateInfo->allocationSize;
|
|
|
|
VkDeviceMemory mem_handle = vn_device_memory_to_handle(mem);
|
|
VkResult result;
|
|
if (import_info) {
|
|
struct vn_renderer_bo *bo;
|
|
result = vn_renderer_bo_create_dmabuf(
|
|
dev->instance->renderer, pAllocateInfo->allocationSize,
|
|
import_info->fd, mem_type->propertyFlags,
|
|
export_info ? export_info->handleTypes : 0, &bo);
|
|
if (result != VK_SUCCESS) {
|
|
vk_free(alloc, mem);
|
|
return vn_error(dev->instance, result);
|
|
}
|
|
|
|
/* TODO create host-side memory from bo->res_id */
|
|
result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
|
|
if (result != VK_SUCCESS) {
|
|
vn_renderer_bo_unref(bo);
|
|
vk_free(alloc, mem);
|
|
return vn_error(dev->instance, result);
|
|
}
|
|
|
|
mem->base_bo = bo;
|
|
} else if (suballocate) {
|
|
result = vn_device_memory_pool_alloc(
|
|
dev, pAllocateInfo->memoryTypeIndex, mem->size, &mem->base_memory,
|
|
&mem->base_bo, &mem->base_offset);
|
|
if (result != VK_SUCCESS) {
|
|
vk_free(alloc, mem);
|
|
return vn_error(dev->instance, result);
|
|
}
|
|
} else {
|
|
result = vn_call_vkAllocateMemory(dev->instance, device, pAllocateInfo,
|
|
NULL, &mem_handle);
|
|
if (result != VK_SUCCESS) {
|
|
vk_free(alloc, mem);
|
|
return vn_error(dev->instance, result);
|
|
}
|
|
}
|
|
|
|
if (need_bo && !mem->base_bo) {
|
|
result = vn_renderer_bo_create_gpu(
|
|
dev->instance->renderer, mem->size, mem->base.id,
|
|
mem_type->propertyFlags, export_info ? export_info->handleTypes : 0,
|
|
&mem->base_bo);
|
|
if (result != VK_SUCCESS) {
|
|
vn_async_vkFreeMemory(dev->instance, device, mem_handle, NULL);
|
|
vk_free(alloc, mem);
|
|
return vn_error(dev->instance, result);
|
|
}
|
|
vn_instance_roundtrip(dev->instance);
|
|
}
|
|
|
|
*pMemory = mem_handle;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
vn_FreeMemory(VkDevice device,
|
|
VkDeviceMemory memory,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_device_memory *mem = vn_device_memory_from_handle(memory);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
if (!mem)
|
|
return;
|
|
|
|
if (mem->base_memory) {
|
|
vn_device_memory_pool_free(dev, mem->base_memory, mem->base_bo);
|
|
} else {
|
|
if (mem->base_bo)
|
|
vn_renderer_bo_unref(mem->base_bo);
|
|
vn_async_vkFreeMemory(dev->instance, device, memory, NULL);
|
|
}
|
|
|
|
vn_object_base_fini(&mem->base);
|
|
vk_free(alloc, mem);
|
|
}
|
|
|
|
uint64_t
|
|
vn_GetDeviceMemoryOpaqueCaptureAddress(
|
|
VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_device_memory *mem = vn_device_memory_from_handle(pInfo->memory);
|
|
|
|
assert(!mem->base_memory);
|
|
return vn_call_vkGetDeviceMemoryOpaqueCaptureAddress(dev->instance, device,
|
|
pInfo);
|
|
}
|
|
|
|
VkResult
|
|
vn_MapMemory(VkDevice device,
|
|
VkDeviceMemory memory,
|
|
VkDeviceSize offset,
|
|
VkDeviceSize size,
|
|
VkMemoryMapFlags flags,
|
|
void **ppData)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_device_memory *mem = vn_device_memory_from_handle(memory);
|
|
|
|
void *ptr = vn_renderer_bo_map(mem->base_bo);
|
|
if (!ptr)
|
|
return vn_error(dev->instance, VK_ERROR_MEMORY_MAP_FAILED);
|
|
|
|
mem->map_end = size == VK_WHOLE_SIZE ? mem->size : offset + size;
|
|
|
|
*ppData = ptr + mem->base_offset + offset;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
vn_UnmapMemory(VkDevice device, VkDeviceMemory memory)
|
|
{
|
|
}
|
|
|
|
VkResult
|
|
vn_FlushMappedMemoryRanges(VkDevice device,
|
|
uint32_t memoryRangeCount,
|
|
const VkMappedMemoryRange *pMemoryRanges)
|
|
{
|
|
for (uint32_t i = 0; i < memoryRangeCount; i++) {
|
|
const VkMappedMemoryRange *range = &pMemoryRanges[i];
|
|
struct vn_device_memory *mem =
|
|
vn_device_memory_from_handle(range->memory);
|
|
|
|
const VkDeviceSize size = range->size == VK_WHOLE_SIZE
|
|
? mem->map_end - range->offset
|
|
: range->size;
|
|
vn_renderer_bo_flush(mem->base_bo, mem->base_offset + range->offset,
|
|
size);
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult
|
|
vn_InvalidateMappedMemoryRanges(VkDevice device,
|
|
uint32_t memoryRangeCount,
|
|
const VkMappedMemoryRange *pMemoryRanges)
|
|
{
|
|
for (uint32_t i = 0; i < memoryRangeCount; i++) {
|
|
const VkMappedMemoryRange *range = &pMemoryRanges[i];
|
|
struct vn_device_memory *mem =
|
|
vn_device_memory_from_handle(range->memory);
|
|
|
|
const VkDeviceSize size = range->size == VK_WHOLE_SIZE
|
|
? mem->map_end - range->offset
|
|
: range->size;
|
|
vn_renderer_bo_invalidate(mem->base_bo,
|
|
mem->base_offset + range->offset, size);
|
|
}
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
vn_GetDeviceMemoryCommitment(VkDevice device,
|
|
VkDeviceMemory memory,
|
|
VkDeviceSize *pCommittedMemoryInBytes)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_device_memory *mem = vn_device_memory_from_handle(memory);
|
|
|
|
assert(!mem->base_memory);
|
|
vn_call_vkGetDeviceMemoryCommitment(dev->instance, device, memory,
|
|
pCommittedMemoryInBytes);
|
|
}
|
|
|
|
VkResult
|
|
vn_GetMemoryFdKHR(VkDevice device,
|
|
const VkMemoryGetFdInfoKHR *pGetFdInfo,
|
|
int *pFd)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_device_memory *mem =
|
|
vn_device_memory_from_handle(pGetFdInfo->memory);
|
|
|
|
assert(!mem->base_memory && mem->base_bo);
|
|
*pFd = vn_renderer_bo_export_dmabuf(mem->base_bo);
|
|
if (*pFd < 0)
|
|
return vn_error(dev->instance, VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VkResult
|
|
vn_GetMemoryFdPropertiesKHR(VkDevice device,
|
|
VkExternalMemoryHandleTypeFlagBits handleType,
|
|
int fd,
|
|
VkMemoryFdPropertiesKHR *pMemoryFdProperties)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
|
|
struct vn_renderer_bo *bo;
|
|
VkResult result = vn_renderer_bo_create_dmabuf(dev->instance->renderer, 0,
|
|
fd, 0, handleType, &bo);
|
|
if (result != VK_SUCCESS)
|
|
return vn_error(dev->instance, result);
|
|
|
|
/* TODO call into the host with bo->res_id */
|
|
result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
|
|
|
|
vn_renderer_bo_unref(bo);
|
|
|
|
return result;
|
|
}
|