wined3d: Implement a Vulkan device memory allocator.

Note that the constants like WINED3D_ALLOCATOR_CHUNK_SIZE and
WINED3D_ALLOCATOR_MIN_BLOCK_SIZE are somewhat arbitrary, rather than the
result of careful tuning. That's mostly because we have a couple of
known stalls in e.g. the command stream that would largely invalidate
such tuning.

Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Henri Verbeet 2020-04-17 20:21:10 +04:30 committed by Alexandre Julliard
parent d65abdabe3
commit 9529f08e1a
5 changed files with 537 additions and 19 deletions

View File

@ -176,6 +176,57 @@ static void wined3d_disable_vulkan_features(VkPhysicalDeviceFeatures *features)
features->inheritedQueries = VK_FALSE;
}
static struct wined3d_allocator_chunk *wined3d_allocator_vk_create_chunk(struct wined3d_allocator *allocator,
struct wined3d_context *context, unsigned int memory_type, size_t chunk_size)
{
struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
struct wined3d_allocator_chunk_vk *chunk_vk;
if (!(chunk_vk = heap_alloc(sizeof(*chunk_vk))))
return NULL;
if (!wined3d_allocator_chunk_init(&chunk_vk->c, allocator))
{
heap_free(chunk_vk);
return NULL;
}
if (!(chunk_vk->vk_memory = wined3d_context_vk_allocate_vram_chunk_memory(context_vk, memory_type, chunk_size)))
{
wined3d_allocator_chunk_cleanup(&chunk_vk->c);
heap_free(chunk_vk);
return NULL;
}
list_add_head(&allocator->pools[memory_type].chunks, &chunk_vk->c.entry);
return &chunk_vk->c;
}
static void wined3d_allocator_vk_destroy_chunk(struct wined3d_allocator_chunk *chunk)
{
struct wined3d_allocator_chunk_vk *chunk_vk = wined3d_allocator_chunk_vk(chunk);
const struct wined3d_vk_info *vk_info;
struct wined3d_device_vk *device_vk;
TRACE("chunk %p.\n", chunk);
device_vk = CONTAINING_RECORD(chunk_vk->c.allocator, struct wined3d_device_vk, allocator);
vk_info = &device_vk->vk_info;
if (chunk_vk->c.map_ptr)
VK_CALL(vkUnmapMemory(device_vk->vk_device, chunk_vk->vk_memory));
VK_CALL(vkFreeMemory(device_vk->vk_device, chunk_vk->vk_memory, NULL));
TRACE("Freed memory 0x%s.\n", wine_dbgstr_longlong(chunk_vk->vk_memory));
wined3d_allocator_chunk_cleanup(&chunk_vk->c);
heap_free(chunk_vk);
}
static const struct wined3d_allocator_ops wined3d_allocator_vk_ops =
{
.allocator_create_chunk = wined3d_allocator_vk_create_chunk,
.allocator_destroy_chunk = wined3d_allocator_vk_destroy_chunk,
};
static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wined3d_adapter *adapter,
enum wined3d_device_type device_type, HWND focus_window, unsigned int flags, BYTE surface_alignment,
const enum wined3d_feature_level *levels, unsigned int level_count,
@ -247,10 +298,19 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi
VK_DEVICE_FUNCS()
#undef VK_DEVICE_PFN
if (!wined3d_allocator_init(&device_vk->allocator,
adapter_vk->memory_properties.memoryTypeCount, &wined3d_allocator_vk_ops))
{
WARN("Failed to initialise allocator.\n");
hr = E_FAIL;
goto fail;
}
if (FAILED(hr = wined3d_device_init(&device_vk->d, wined3d, adapter->ordinal, device_type,
focus_window, flags, surface_alignment, levels, level_count, device_parent)))
{
WARN("Failed to initialize device, hr %#x.\n", hr);
wined3d_allocator_cleanup(&device_vk->allocator);
goto fail;
}
@ -270,6 +330,7 @@ static void adapter_vk_destroy_device(struct wined3d_device *device)
const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
wined3d_device_cleanup(&device_vk->d);
wined3d_allocator_cleanup(&device_vk->allocator);
VK_CALL(vkDestroyDevice(device_vk->vk_device, NULL));
heap_free(device_vk);
}
@ -488,6 +549,49 @@ static void adapter_vk_uninit_3d(struct wined3d_device *device)
wined3d_context_vk_cleanup(context_vk);
}
static void *wined3d_bo_vk_map(struct wined3d_bo_vk *bo, struct wined3d_context_vk *context_vk)
{
const struct wined3d_vk_info *vk_info;
struct wined3d_device_vk *device_vk;
void *map_ptr;
VkResult vr;
vk_info = context_vk->vk_info;
device_vk = wined3d_device_vk(context_vk->c.device);
if (bo->memory)
{
struct wined3d_allocator_chunk_vk *chunk_vk = wined3d_allocator_chunk_vk(bo->memory->chunk);
if (!(map_ptr = wined3d_allocator_chunk_vk_map(chunk_vk, context_vk)))
{
ERR("Failed to map chunk.\n");
return NULL;
}
}
else if ((vr = VK_CALL(vkMapMemory(device_vk->vk_device, bo->vk_memory, 0, VK_WHOLE_SIZE, 0, &map_ptr))) < 0)
{
ERR("Failed to map memory, vr %s.\n", wined3d_debug_vkresult(vr));
return NULL;
}
return map_ptr;
}
static void wined3d_bo_vk_unmap(struct wined3d_bo_vk *bo, struct wined3d_context_vk *context_vk)
{
const struct wined3d_vk_info *vk_info;
struct wined3d_device_vk *device_vk;
vk_info = context_vk->vk_info;
device_vk = wined3d_device_vk(context_vk->c.device);
if (bo->memory)
wined3d_allocator_chunk_vk_unmap(wined3d_allocator_chunk_vk(bo->memory->chunk), context_vk);
else
VK_CALL(vkUnmapMemory(device_vk->vk_device, bo->vk_memory));
}
static void *adapter_vk_map_bo_address(struct wined3d_context *context,
const struct wined3d_bo_address *data, size_t size, uint32_t bind_flags, uint32_t map_flags)
{
@ -499,7 +603,6 @@ static void *adapter_vk_map_bo_address(struct wined3d_context *context,
VkMappedMemoryRange range;
struct wined3d_bo_vk *bo;
void *map_ptr;
VkResult vr;
if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
return data->addr;
@ -532,7 +635,7 @@ static void *adapter_vk_map_bo_address(struct wined3d_context *context,
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range.pNext = NULL;
range.memory = bo->vk_memory;
range.offset = (uintptr_t)data->addr;
range.offset = bo->memory_offset + (uintptr_t)data->addr;
range.size = size;
VK_CALL(vkInvalidateMappedMemoryRanges(device_vk->vk_device, 1, &range));
}
@ -544,19 +647,19 @@ static void *adapter_vk_map_bo_address(struct wined3d_context *context,
wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
wined3d_context_vk_wait_command_buffer(context_vk, bo->command_buffer_id);
if ((vr = VK_CALL(vkMapMemory(device_vk->vk_device, bo->vk_memory,
(uintptr_t)data->addr, size, 0, &map_ptr))) < 0)
if (!(map_ptr = wined3d_bo_vk_map(bo, context_vk)))
{
ERR("Failed to map buffer, vr %s.\n", wined3d_debug_vkresult(vr));
ERR("Failed to map bo.\n");
return NULL;
}
return map_ptr;
return (uint8_t *)map_ptr + bo->memory_offset + (uintptr_t)data->addr;
}
static void adapter_vk_unmap_bo_address(struct wined3d_context *context, const struct wined3d_bo_address *data,
uint32_t bind_flags, unsigned int range_count, const struct wined3d_range *ranges)
{
struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
const struct wined3d_vk_info *vk_info;
struct wined3d_device_vk *device_vk;
VkMappedMemoryRange range;
@ -566,7 +669,7 @@ static void adapter_vk_unmap_bo_address(struct wined3d_context *context, const s
if (!(bo = (struct wined3d_bo_vk *)data->buffer_object))
return;
vk_info = wined3d_context_vk(context)->vk_info;
vk_info = context_vk->vk_info;
device_vk = wined3d_device_vk(context->device);
if (!(bo->memory_type & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
@ -577,13 +680,13 @@ static void adapter_vk_unmap_bo_address(struct wined3d_context *context, const s
for (i = 0; i < range_count; ++i)
{
range.offset = ranges[i].offset;
range.offset = bo->memory_offset + ranges[i].offset;
range.size = ranges[i].size;
VK_CALL(vkFlushMappedMemoryRanges(device_vk->vk_device, 1, &range));
}
}
VK_CALL(vkUnmapMemory(device_vk->vk_device, bo->vk_memory));
wined3d_bo_vk_unmap(bo, context_vk);
}
static void adapter_vk_copy_bo_address(struct wined3d_context *context,

View File

@ -1636,7 +1636,7 @@ static void wined3d_buffer_vk_unload_location(struct wined3d_buffer *buffer,
case WINED3D_LOCATION_BUFFER:
wined3d_context_vk_destroy_bo(context_vk, &buffer_vk->bo);
buffer_vk->bo.vk_buffer = VK_NULL_HANDLE;
buffer_vk->bo.vk_memory = VK_NULL_HANDLE;
buffer_vk->bo.memory = NULL;
buffer_vk->b.buffer_object = 0u;
break;

View File

@ -29,6 +29,87 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3d);
void *wined3d_allocator_chunk_vk_map(struct wined3d_allocator_chunk_vk *chunk_vk,
struct wined3d_context_vk *context_vk)
{
struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
VkResult vr;
TRACE("chunk %p, memory 0x%s, map_ptr %p.\n", chunk_vk,
wine_dbgstr_longlong(chunk_vk->vk_memory), chunk_vk->c.map_ptr);
if (!chunk_vk->c.map_ptr && (vr = VK_CALL(vkMapMemory(device_vk->vk_device,
chunk_vk->vk_memory, 0, VK_WHOLE_SIZE, 0, &chunk_vk->c.map_ptr))) < 0)
{
ERR("Failed to map chunk memory, vr %s.\n", wined3d_debug_vkresult(vr));
return NULL;
}
++chunk_vk->c.map_count;
return chunk_vk->c.map_ptr;
}
void wined3d_allocator_chunk_vk_unmap(struct wined3d_allocator_chunk_vk *chunk_vk,
struct wined3d_context_vk *context_vk)
{
struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
TRACE("chunk_vk %p, context_vk %p.\n", chunk_vk, context_vk);
if (!--chunk_vk->c.map_count)
VK_CALL(vkUnmapMemory(device_vk->vk_device, chunk_vk->vk_memory));
chunk_vk->c.map_ptr = NULL;
}
VkDeviceMemory wined3d_context_vk_allocate_vram_chunk_memory(struct wined3d_context_vk *context_vk,
unsigned int pool, size_t size)
{
struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
VkMemoryAllocateInfo allocate_info;
VkDeviceMemory vk_memory;
VkResult vr;
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocate_info.pNext = NULL;
allocate_info.allocationSize = size;
allocate_info.memoryTypeIndex = pool;
if ((vr = VK_CALL(vkAllocateMemory(device_vk->vk_device, &allocate_info, NULL, &vk_memory))) < 0)
{
ERR("Failed to allocate memory, vr %s.\n", wined3d_debug_vkresult(vr));
return VK_NULL_HANDLE;
}
return vk_memory;
}
static struct wined3d_allocator_block *wined3d_context_vk_allocate_memory(struct wined3d_context_vk *context_vk,
unsigned int memory_type, VkDeviceSize size, VkDeviceMemory *vk_memory)
{
struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
struct wined3d_allocator *allocator = &device_vk->allocator;
struct wined3d_allocator_block *block;
if (size > WINED3D_ALLOCATOR_CHUNK_SIZE / 2)
{
*vk_memory = wined3d_context_vk_allocate_vram_chunk_memory(context_vk, memory_type, size);
return NULL;
}
if (!(block = wined3d_allocator_allocate(allocator, &context_vk->c, memory_type, size)))
{
*vk_memory = VK_NULL_HANDLE;
return NULL;
}
*vk_memory = wined3d_allocator_chunk_vk(block->chunk)->vk_memory;
return block;
}
BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDeviceSize size,
VkBufferUsageFlags usage, VkMemoryPropertyFlags memory_type, struct wined3d_bo_vk *bo)
{
@ -36,7 +117,6 @@ BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDevic
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
VkMemoryRequirements memory_requirements;
struct wined3d_adapter_vk *adapter_vk;
VkMemoryAllocateInfo allocate_info;
VkBufferCreateInfo create_info;
unsigned int memory_type_idx;
VkResult vr;
@ -60,9 +140,6 @@ BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDevic
VK_CALL(vkGetBufferMemoryRequirements(device_vk->vk_device, bo->vk_buffer, &memory_requirements));
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocate_info.pNext = NULL;
allocate_info.allocationSize = memory_requirements.size;
memory_type_idx = wined3d_adapter_vk_get_memory_type_index(adapter_vk,
memory_requirements.memoryTypeBits, memory_type);
if (memory_type_idx == ~0u)
@ -71,18 +148,24 @@ BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDevic
VK_CALL(vkDestroyBuffer(device_vk->vk_device, bo->vk_buffer, NULL));
return FALSE;
}
allocate_info.memoryTypeIndex = memory_type_idx;
if ((vr = VK_CALL(vkAllocateMemory(device_vk->vk_device, &allocate_info, NULL, &bo->vk_memory))) < 0)
bo->memory = wined3d_context_vk_allocate_memory(context_vk,
memory_type_idx, memory_requirements.size, &bo->vk_memory);
if (!bo->vk_memory)
{
ERR("Failed to allocate buffer memory, vr %s.\n", wined3d_debug_vkresult(vr));
ERR("Failed to allocate buffer memory.\n");
VK_CALL(vkDestroyBuffer(device_vk->vk_device, bo->vk_buffer, NULL));
return FALSE;
}
bo->memory_offset = bo->memory ? bo->memory->offset : 0;
if ((vr = VK_CALL(vkBindBufferMemory(device_vk->vk_device, bo->vk_buffer, bo->vk_memory, 0))) < 0)
if ((vr = VK_CALL(vkBindBufferMemory(device_vk->vk_device, bo->vk_buffer,
bo->vk_memory, bo->memory_offset))) < 0)
{
ERR("Failed to bind buffer memory, vr %s.\n", wined3d_debug_vkresult(vr));
VK_CALL(vkFreeMemory(device_vk->vk_device, bo->vk_memory, NULL));
if (bo->memory)
wined3d_allocator_block_free(bo->memory);
else
VK_CALL(vkFreeMemory(device_vk->vk_device, bo->vk_memory, NULL));
VK_CALL(vkDestroyBuffer(device_vk->vk_device, bo->vk_buffer, NULL));
return FALSE;
}
@ -140,6 +223,29 @@ static void wined3d_context_vk_destroy_memory(struct wined3d_context_vk *context
o->command_buffer_id = command_buffer_id;
}
static void wined3d_context_vk_destroy_allocator_block(struct wined3d_context_vk *context_vk,
struct wined3d_allocator_block *block, uint64_t command_buffer_id)
{
struct wined3d_retired_object_vk *o;
if (context_vk->completed_command_buffer_id > command_buffer_id)
{
wined3d_allocator_block_free(block);
TRACE("Freed block %p.\n", block);
return;
}
if (!(o = wined3d_context_vk_get_retired_object_vk(context_vk)))
{
ERR("Leaking block %p.\n", block);
return;
}
o->type = WINED3D_RETIRED_ALLOCATOR_BLOCK_VK;
o->u.block = block;
o->command_buffer_id = command_buffer_id;
}
static void wined3d_context_vk_destroy_buffer(struct wined3d_context_vk *context_vk,
VkBuffer vk_buffer, uint64_t command_buffer_id)
{
@ -167,7 +273,15 @@ static void wined3d_context_vk_destroy_buffer(struct wined3d_context_vk *context
void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk, const struct wined3d_bo_vk *bo)
{
TRACE("context_vk %p, bo %p.\n", context_vk, bo);
wined3d_context_vk_destroy_buffer(context_vk, bo->vk_buffer, bo->command_buffer_id);
if (bo->memory)
{
wined3d_context_vk_destroy_allocator_block(context_vk, bo->memory, bo->command_buffer_id);
return;
}
wined3d_context_vk_destroy_memory(context_vk, bo->vk_memory, bo->command_buffer_id);
}
@ -221,6 +335,11 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont
TRACE("Freed memory 0x%s.\n", wine_dbgstr_longlong(o->u.vk_memory));
break;
case WINED3D_RETIRED_ALLOCATOR_BLOCK_VK:
TRACE("Destroying block %p.\n", o->u.block);
wined3d_allocator_block_free(o->u.block);
break;
case WINED3D_RETIRED_BUFFER_VK:
VK_CALL(vkDestroyBuffer(device_vk->vk_device, o->u.vk_buffer, NULL));
TRACE("Destroyed buffer 0x%s.\n", wine_dbgstr_longlong(o->u.vk_buffer));

View File

@ -7060,3 +7060,218 @@ void compute_normal_matrix(float *normal_matrix, BOOL legacy_lighting,
for (j = 0; j < 3; ++j)
normal_matrix[i * 3 + j] = (&mv._11)[j * 4 + i];
}
static void wined3d_allocator_release_block(struct wined3d_allocator *allocator,
struct wined3d_allocator_block *block)
{
block->parent = allocator->free;
allocator->free = block;
}
static struct wined3d_allocator_block *wined3d_allocator_acquire_block(struct wined3d_allocator *allocator)
{
struct wined3d_allocator_block *block;
if (!allocator->free)
return heap_alloc(sizeof(*block));
block = allocator->free;
allocator->free = block->parent;
return block;
}
void wined3d_allocator_block_free(struct wined3d_allocator_block *block)
{
struct wined3d_allocator *allocator = block->chunk->allocator;
struct wined3d_allocator_block *parent;
while ((parent = block->parent) && block->sibling->free)
{
list_remove(&block->sibling->entry);
wined3d_allocator_release_block(allocator, block->sibling);
wined3d_allocator_release_block(allocator, block);
block = parent;
}
block->free = true;
list_add_head(&block->chunk->available[block->order], &block->entry);
}
static void wined3d_allocator_block_init(struct wined3d_allocator_block *block,
struct wined3d_allocator_chunk *chunk, struct wined3d_allocator_block *parent,
struct wined3d_allocator_block *sibling, unsigned int order, size_t offset, bool free)
{
list_init(&block->entry);
block->chunk = chunk;
block->parent = parent;
block->sibling = sibling;
block->order = order;
block->offset = offset;
block->free = free;
}
void wined3d_allocator_chunk_cleanup(struct wined3d_allocator_chunk *chunk)
{
struct wined3d_allocator_block *block;
size_t i;
if (list_empty(&chunk->available[0]))
{
ERR("Chunk %p is not empty.\n", chunk);
return;
}
for (i = 1; i < ARRAY_SIZE(chunk->available); ++i)
{
if (!list_empty(&chunk->available[i]))
{
ERR("Chunk %p is not empty.\n", chunk);
return;
}
}
block = LIST_ENTRY(list_head(&chunk->available[0]), struct wined3d_allocator_block, entry);
wined3d_allocator_release_block(chunk->allocator, block);
}
bool wined3d_allocator_chunk_init(struct wined3d_allocator_chunk *chunk, struct wined3d_allocator *allocator)
{
struct wined3d_allocator_block *block;
unsigned int i;
if (!(block = wined3d_allocator_acquire_block(allocator)))
return false;
wined3d_allocator_block_init(block, chunk, NULL, NULL, 0, 0, true);
list_init(&chunk->entry);
for (i = 0; i < ARRAY_SIZE(chunk->available); ++i)
{
list_init(&chunk->available[i]);
}
list_add_head(&chunk->available[0], &block->entry);
chunk->allocator = allocator;
chunk->map_count = 0;
chunk->map_ptr = NULL;
return true;
}
void wined3d_allocator_cleanup(struct wined3d_allocator *allocator)
{
struct wined3d_allocator_chunk *chunk, *chunk2;
struct wined3d_allocator_block *block, *next;
size_t i;
for (i = 0; i < allocator->pool_count; ++i)
{
LIST_FOR_EACH_ENTRY_SAFE(chunk, chunk2, &allocator->pools[i].chunks, struct wined3d_allocator_chunk, entry)
{
list_remove(&chunk->entry);
allocator->ops->allocator_destroy_chunk(chunk);
}
}
heap_free(allocator->pools);
next = allocator->free;
while ((block = next))
{
next = block->parent;
heap_free(block);
}
}
static struct wined3d_allocator_block *wined3d_allocator_chunk_allocate(struct wined3d_allocator_chunk *chunk,
unsigned int order)
{
struct wined3d_allocator_block *block, *left, *right;
unsigned int i = order;
while (i)
{
if (!list_empty(&chunk->available[i]))
break;
--i;
}
if (list_empty(&chunk->available[i]))
return NULL;
block = LIST_ENTRY(list_head(&chunk->available[i]), struct wined3d_allocator_block, entry);
list_remove(&block->entry);
block->free = false;
while (i < order)
{
if (!(left = wined3d_allocator_acquire_block(chunk->allocator)))
{
ERR("Failed to allocate left.\n");
break;
}
if (!(right = wined3d_allocator_acquire_block(chunk->allocator)))
{
ERR("Failed to allocate right.\n");
wined3d_allocator_release_block(chunk->allocator, left);
break;
}
wined3d_allocator_block_init(left, chunk, block, right, block->order + 1, block->offset, false);
wined3d_allocator_block_init(right, chunk, block, left, block->order + 1,
block->offset + (WINED3D_ALLOCATOR_CHUNK_SIZE >> left->order), true);
list_add_head(&chunk->available[right->order], &right->entry);
block = left;
++i;
}
return block;
}
struct wined3d_allocator_block *wined3d_allocator_allocate(struct wined3d_allocator *allocator,
struct wined3d_context *context, unsigned int memory_type, size_t size)
{
struct wined3d_allocator_chunk *chunk;
struct wined3d_allocator_block *block;
unsigned int order;
if (size > WINED3D_ALLOCATOR_CHUNK_SIZE / 2)
return NULL;
if (size < WINED3D_ALLOCATOR_MIN_BLOCK_SIZE)
order = WINED3D_ALLOCATOR_CHUNK_ORDER_COUNT - 1;
else
order = wined3d_log2i(WINED3D_ALLOCATOR_CHUNK_SIZE / size);
LIST_FOR_EACH_ENTRY(chunk, &allocator->pools[memory_type].chunks, struct wined3d_allocator_chunk, entry)
{
if ((block = wined3d_allocator_chunk_allocate(chunk, order)))
return block;
}
if (!(chunk = allocator->ops->allocator_create_chunk(allocator,
context, memory_type, WINED3D_ALLOCATOR_CHUNK_SIZE)))
return NULL;
if (!(block = wined3d_allocator_chunk_allocate(chunk, order)))
return NULL;
return block;
}
bool wined3d_allocator_init(struct wined3d_allocator *allocator,
size_t pool_count, const struct wined3d_allocator_ops *allocator_ops)
{
size_t i;
allocator->ops = allocator_ops;
allocator->pool_count = pool_count;
if (!(allocator->pools = heap_calloc(pool_count, sizeof(*allocator->pools))))
return false;
for (i = 0; i < pool_count; ++i)
{
list_init(&allocator->pools[i].chunks);
}
return true;
}

View File

@ -33,6 +33,7 @@
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <math.h>
#include <limits.h>
#include "ntstatus.h"
@ -1520,8 +1521,11 @@ do { \
struct wined3d_bo_vk
{
VkBuffer vk_buffer;
struct wined3d_allocator_block *memory;
VkDeviceMemory vk_memory;
VkDeviceSize memory_offset;
VkMemoryPropertyFlags memory_type;
uint64_t command_buffer_id;
@ -2188,6 +2192,7 @@ enum wined3d_retired_object_type_vk
{
WINED3D_RETIRED_FREE_VK,
WINED3D_RETIRED_MEMORY_VK,
WINED3D_RETIRED_ALLOCATOR_BLOCK_VK,
WINED3D_RETIRED_BUFFER_VK,
};
@ -2198,6 +2203,7 @@ struct wined3d_retired_object_vk
{
struct wined3d_retired_object_vk *next;
VkDeviceMemory vk_memory;
struct wined3d_allocator_block *block;
VkBuffer vk_buffer;
} u;
uint64_t command_buffer_id;
@ -2236,6 +2242,8 @@ static inline struct wined3d_context_vk *wined3d_context_vk(struct wined3d_conte
return CONTAINING_RECORD(context, struct wined3d_context_vk, c);
}
VkDeviceMemory wined3d_context_vk_allocate_vram_chunk_memory(struct wined3d_context_vk *context_vk,
unsigned int pool, size_t size) DECLSPEC_HIDDEN;
void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
BOOL wined3d_context_vk_create_bo(struct wined3d_context_vk *context_vk, VkDeviceSize size,
VkBufferUsageFlags usage, VkMemoryPropertyFlags memory_type, struct wined3d_bo_vk *bo) DECLSPEC_HIDDEN;
@ -3422,6 +3430,77 @@ static inline struct wined3d_device_gl *wined3d_device_gl(struct wined3d_device
return CONTAINING_RECORD(device, struct wined3d_device_gl, d);
}
#define WINED3D_ALLOCATOR_CHUNK_SIZE (64 * 1024 * 1024)
#define WINED3D_ALLOCATOR_CHUNK_ORDER_COUNT 15
#define WINED3D_ALLOCATOR_MIN_BLOCK_SIZE (WINED3D_ALLOCATOR_CHUNK_SIZE >> (WINED3D_ALLOCATOR_CHUNK_ORDER_COUNT - 1))
struct wined3d_allocator_chunk
{
struct list entry;
struct list available[WINED3D_ALLOCATOR_CHUNK_ORDER_COUNT];
struct wined3d_allocator *allocator;
unsigned int map_count;
void *map_ptr;
};
void wined3d_allocator_chunk_cleanup(struct wined3d_allocator_chunk *chunk) DECLSPEC_HIDDEN;
bool wined3d_allocator_chunk_init(struct wined3d_allocator_chunk *chunk,
struct wined3d_allocator *allocator) DECLSPEC_HIDDEN;
struct wined3d_allocator_chunk_vk
{
struct wined3d_allocator_chunk c;
VkDeviceMemory vk_memory;
};
static inline struct wined3d_allocator_chunk_vk *wined3d_allocator_chunk_vk(struct wined3d_allocator_chunk *chunk)
{
return CONTAINING_RECORD(chunk, struct wined3d_allocator_chunk_vk, c);
}
void *wined3d_allocator_chunk_vk_map(struct wined3d_allocator_chunk_vk *chunk_vk,
struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
void wined3d_allocator_chunk_vk_unmap(struct wined3d_allocator_chunk_vk *chunk_vk,
struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
struct wined3d_allocator_block
{
struct list entry;
struct wined3d_allocator_chunk *chunk;
struct wined3d_allocator_block *parent, *sibling;
unsigned int order;
size_t offset;
bool free;
};
void wined3d_allocator_block_free(struct wined3d_allocator_block *block) DECLSPEC_HIDDEN;
struct wined3d_allocator_pool
{
struct list chunks;
};
struct wined3d_allocator_ops
{
struct wined3d_allocator_chunk *(*allocator_create_chunk)(struct wined3d_allocator *allocator,
struct wined3d_context *context, unsigned int memory_type, size_t chunk_size);
void (*allocator_destroy_chunk)(struct wined3d_allocator_chunk *chunk);
};
struct wined3d_allocator
{
const struct wined3d_allocator_ops *ops;
struct wined3d_allocator_pool *pools;
size_t pool_count;
struct wined3d_allocator_block *free;
};
struct wined3d_allocator_block *wined3d_allocator_allocate(struct wined3d_allocator *allocator,
struct wined3d_context *context, unsigned int memory_type, size_t size) DECLSPEC_HIDDEN;
void wined3d_allocator_cleanup(struct wined3d_allocator *allocator) DECLSPEC_HIDDEN;
bool wined3d_allocator_init(struct wined3d_allocator *allocator,
size_t pool_count, const struct wined3d_allocator_ops *allocator_ops) DECLSPEC_HIDDEN;
struct wined3d_device_vk
{
struct wined3d_device d;
@ -3433,6 +3512,8 @@ struct wined3d_device_vk
uint32_t vk_queue_family_index;
struct wined3d_vk_info vk_info;
struct wined3d_allocator allocator;
};
static inline struct wined3d_device_vk *wined3d_device_vk(struct wined3d_device *device)