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:
parent
d65abdabe3
commit
9529f08e1a
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue