VkResult result = anv_device_import_bo_from_host_ptr(pool->device,
map, size,
bo_alloc_flags,
+ 0 /* client_address */,
&new_bo);
if (result != VK_SUCCESS) {
munmap(map, size);
.size = size,
.flags = bo_flags,
.is_external = (alloc_flags & ANV_BO_ALLOC_EXTERNAL),
+ .has_client_visible_address =
+ (alloc_flags & ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS) != 0,
};
if (alloc_flags & ANV_BO_ALLOC_MAPPED) {
new_bo.has_fixed_address = true;
new_bo.offset = explicit_address;
} else {
- assert(explicit_address == 0);
- if (!anv_vma_alloc(device, &new_bo)) {
+ if (!anv_vma_alloc(device, &new_bo, explicit_address)) {
if (new_bo.map)
anv_gem_munmap(new_bo.map, size);
anv_gem_close(device, new_bo.gem_handle);
anv_device_import_bo_from_host_ptr(struct anv_device *device,
void *host_ptr, uint32_t size,
enum anv_bo_alloc_flags alloc_flags,
+ uint64_t client_address,
struct anv_bo **bo_out)
{
assert(!(alloc_flags & (ANV_BO_ALLOC_MAPPED |
VK_ERROR_INVALID_EXTERNAL_HANDLE,
"same host pointer imported two different ways");
}
+
+ if (bo->has_client_visible_address !=
+ ((alloc_flags & ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS) != 0)) {
+ pthread_mutex_unlock(&cache->mutex);
+ return vk_errorf(device->instance, NULL,
+ VK_ERROR_INVALID_EXTERNAL_HANDLE,
+ "The same BO was imported with and without buffer "
+ "device address");
+ }
+
+ if (client_address && client_address != gen_48b_address(bo->offset)) {
+ pthread_mutex_unlock(&cache->mutex);
+ return vk_errorf(device->instance, NULL,
+ VK_ERROR_INVALID_EXTERNAL_HANDLE,
+ "The same BO was imported at two different "
+ "addresses");
+ }
+
__sync_fetch_and_add(&bo->refcount, 1);
} else {
struct anv_bo new_bo = {
.flags = bo_flags,
.is_external = true,
.from_host_ptr = true,
+ .has_client_visible_address =
+ (alloc_flags & ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS) != 0,
};
- if (!anv_vma_alloc(device, &new_bo)) {
+ assert(client_address == gen_48b_address(client_address));
+ if (!anv_vma_alloc(device, &new_bo, client_address)) {
anv_gem_close(device, new_bo.gem_handle);
pthread_mutex_unlock(&cache->mutex);
return vk_errorf(device->instance, NULL,
anv_device_import_bo(struct anv_device *device,
int fd,
enum anv_bo_alloc_flags alloc_flags,
+ uint64_t client_address,
struct anv_bo **bo_out)
{
assert(!(alloc_flags & (ANV_BO_ALLOC_MAPPED |
"The same BO was imported on two different heaps");
}
+ if (bo->has_client_visible_address !=
+ ((alloc_flags & ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS) != 0)) {
+ pthread_mutex_unlock(&cache->mutex);
+ return vk_errorf(device->instance, NULL,
+ VK_ERROR_INVALID_EXTERNAL_HANDLE,
+ "The same BO was imported with and without buffer "
+ "device address");
+ }
+
+ if (client_address && client_address != gen_48b_address(bo->offset)) {
+ pthread_mutex_unlock(&cache->mutex);
+ return vk_errorf(device->instance, NULL,
+ VK_ERROR_INVALID_EXTERNAL_HANDLE,
+ "The same BO was imported at two different "
+ "addresses");
+ }
+
bo->flags = new_flags;
__sync_fetch_and_add(&bo->refcount, 1);
.size = size,
.flags = bo_flags,
.is_external = true,
+ .has_client_visible_address =
+ (alloc_flags & ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS) != 0,
};
- if (!anv_vma_alloc(device, &new_bo)) {
+ assert(client_address == gen_48b_address(client_address));
+ if (!anv_vma_alloc(device, &new_bo, client_address)) {
anv_gem_close(device, new_bo.gem_handle);
pthread_mutex_unlock(&cache->mutex);
return vk_errorf(device->instance, NULL,
if (dma_buf < 0)
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
- VkResult result = anv_device_import_bo(device, dma_buf, 0, &mem->bo);
+ VkResult result = anv_device_import_bo(device, dma_buf, 0,
+ 0 /* client_address */,
+ &mem->bo);
assert(VK_SUCCESS);
/* "If the vkAllocateMemory command succeeds, the implementation must
result = anv_device_import_bo(device, dma_buf,
ANV_BO_ALLOC_IMPLICIT_SYNC |
ANV_BO_ALLOC_IMPLICIT_WRITE,
+ 0 /* client_address */,
&bo);
if (result != VK_SUCCESS) {
return vk_errorf(device->instance, device, result,
util_vma_heap_init(&device->vma_lo,
LOW_HEAP_MIN_ADDRESS, LOW_HEAP_SIZE);
+ util_vma_heap_init(&device->vma_cva, CLIENT_VISIBLE_HEAP_MIN_ADDRESS,
+ CLIENT_VISIBLE_HEAP_SIZE);
+
/* Leave the last 4GiB out of the high vma range, so that no state
* base address + size can overflow 48 bits. For more information see
* the comment about Wa32bitGeneralStateOffset in anv_allocator.c
fail_vmas:
if (physical_device->use_softpin) {
util_vma_heap_finish(&device->vma_hi);
+ util_vma_heap_finish(&device->vma_cva);
util_vma_heap_finish(&device->vma_lo);
}
fail_queue:
if (physical_device->use_softpin) {
util_vma_heap_finish(&device->vma_hi);
+ util_vma_heap_finish(&device->vma_cva);
util_vma_heap_finish(&device->vma_lo);
}
}
bool
-anv_vma_alloc(struct anv_device *device, struct anv_bo *bo)
+anv_vma_alloc(struct anv_device *device, struct anv_bo *bo,
+ uint64_t client_address)
{
- if (!(bo->flags & EXEC_OBJECT_PINNED))
+ if (!(bo->flags & EXEC_OBJECT_PINNED)) {
+ assert(!(bo->has_client_visible_address));
return true;
+ }
pthread_mutex_lock(&device->vma_mutex);
bo->offset = 0;
+ if (bo->has_client_visible_address) {
+ assert(bo->flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS);
+ if (client_address) {
+ if (util_vma_heap_alloc_addr(&device->vma_cva,
+ client_address, bo->size)) {
+ bo->offset = gen_canonical_address(client_address);
+ }
+ } else {
+ uint64_t addr = util_vma_heap_alloc(&device->vma_cva, bo->size, 4096);
+ if (addr) {
+ bo->offset = gen_canonical_address(addr);
+ assert(addr == gen_48b_address(bo->offset));
+ }
+ }
+ /* We don't want to fall back to other heaps */
+ goto done;
+ }
+
+ assert(client_address == 0);
+
if (bo->flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS) {
uint64_t addr = util_vma_heap_alloc(&device->vma_hi, bo->size, 4096);
if (addr) {
}
}
+done:
pthread_mutex_unlock(&device->vma_mutex);
return bo->offset != 0;
if (addr_48b >= LOW_HEAP_MIN_ADDRESS &&
addr_48b <= LOW_HEAP_MAX_ADDRESS) {
util_vma_heap_free(&device->vma_lo, addr_48b, bo->size);
+ } else if (addr_48b >= CLIENT_VISIBLE_HEAP_MIN_ADDRESS &&
+ addr_48b <= CLIENT_VISIBLE_HEAP_MAX_ADDRESS) {
+ util_vma_heap_free(&device->vma_cva, addr_48b, bo->size);
} else {
assert(addr_48b >= HIGH_HEAP_MIN_ADDRESS);
util_vma_heap_free(&device->vma_hi, addr_48b, bo->size);
VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT);
result = anv_device_import_bo(device, fd_info->fd, alloc_flags,
- &mem->bo);
+ 0 /* client_address */, &mem->bo);
if (result != VK_SUCCESS)
goto fail;
host_ptr_info->pHostPointer,
pAllocateInfo->allocationSize,
alloc_flags,
+ 0 /* client_address */,
&mem->bo);
if (result != VK_SUCCESS)
result = anv_device_import_bo(device, pCreateInfo->fd,
ANV_BO_ALLOC_IMPLICIT_SYNC,
+ 0 /* address */,
&mem->bo);
if (result != VK_SUCCESS)
goto fail_import;
#define SURFACE_STATE_POOL_MAX_ADDRESS 0x00017fffffffULL
#define INSTRUCTION_STATE_POOL_MIN_ADDRESS 0x000180000000ULL /* 6 GiB */
#define INSTRUCTION_STATE_POOL_MAX_ADDRESS 0x0001bfffffffULL
-#define HIGH_HEAP_MIN_ADDRESS 0x0001c0000000ULL /* 7 GiB */
+#define CLIENT_VISIBLE_HEAP_MIN_ADDRESS 0x0001c0000000ULL /* 7 GiB */
+#define CLIENT_VISIBLE_HEAP_MAX_ADDRESS 0x0002bfffffffULL
+#define HIGH_HEAP_MIN_ADDRESS 0x0002c0000000ULL /* 11 GiB */
#define LOW_HEAP_SIZE \
(LOW_HEAP_MAX_ADDRESS - LOW_HEAP_MIN_ADDRESS + 1)
(SURFACE_STATE_POOL_MAX_ADDRESS - SURFACE_STATE_POOL_MIN_ADDRESS + 1)
#define INSTRUCTION_STATE_POOL_SIZE \
(INSTRUCTION_STATE_POOL_MAX_ADDRESS - INSTRUCTION_STATE_POOL_MIN_ADDRESS + 1)
+#define CLIENT_VISIBLE_HEAP_SIZE \
+ (CLIENT_VISIBLE_HEAP_MAX_ADDRESS - CLIENT_VISIBLE_HEAP_MIN_ADDRESS + 1)
/* Allowing different clear colors requires us to perform a depth resolve at
* the end of certain render passes. This is because while slow clears store
/** True if this BO wraps a host pointer */
bool from_host_ptr:1;
+
+ /** See also ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS */
+ bool has_client_visible_address:1;
};
static inline struct anv_bo *
pthread_mutex_t vma_mutex;
struct util_vma_heap vma_lo;
+ struct util_vma_heap vma_cva;
struct util_vma_heap vma_hi;
/** List of all anv_device_memory objects */
* This is equivalent to EXEC_OBJECT_WRITE.
*/
ANV_BO_ALLOC_IMPLICIT_WRITE = (1 << 7),
+
+ /** Has an address which is visible to the client */
+ ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS = (1 << 8),
};
VkResult anv_device_alloc_bo(struct anv_device *device, uint64_t size,
VkResult anv_device_import_bo_from_host_ptr(struct anv_device *device,
void *host_ptr, uint32_t size,
enum anv_bo_alloc_flags alloc_flags,
+ uint64_t client_address,
struct anv_bo **bo_out);
VkResult anv_device_import_bo(struct anv_device *device, int fd,
enum anv_bo_alloc_flags alloc_flags,
+ uint64_t client_address,
struct anv_bo **bo);
VkResult anv_device_export_bo(struct anv_device *device,
struct anv_bo *bo, int *fd_out);
uint32_t *handles, uint32_t num_handles,
int64_t abs_timeout_ns, bool wait_all);
-bool anv_vma_alloc(struct anv_device *device, struct anv_bo *bo);
+bool anv_vma_alloc(struct anv_device *device, struct anv_bo *bo,
+ uint64_t client_address);
void anv_vma_free(struct anv_device *device, struct anv_bo *bo);
struct anv_reloc_list {
VkResult result = anv_device_import_bo(device, fd,
ANV_BO_ALLOC_EXTERNAL |
ANV_BO_ALLOC_IMPLICIT_SYNC,
+ 0 /* client_address */,
&new_impl.bo);
if (result != VK_SUCCESS)
return result;