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 --- dlls/wined3d/adapter_vk.c | 121 +++++++++++++++++-- dlls/wined3d/buffer.c | 2 +- dlls/wined3d/context_vk.c | 137 +++++++++++++++++++-- dlls/wined3d/utils.c | 215 +++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 81 +++++++++++++ 5 files changed, 537 insertions(+), 19 deletions(-)
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c index e51eeccc02c..1bca53ac7f9 100644 --- a/dlls/wined3d/adapter_vk.c +++ b/dlls/wined3d/adapter_vk.c @@ -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, diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index 2e2ae239210..c45ddae7e59 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -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;
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 3fa3ce8207f..b3239a4f9ee 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -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)); diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 211160ad4db..a2765774c8d 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -7061,3 +7061,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; +} diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index fe44a6edb0c..ade1eae352c 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -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)