diff options
Diffstat (limited to '0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch')
-rw-r--r-- | 0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch b/0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch new file mode 100644 index 000000000000..89c9c8ec9eda --- /dev/null +++ b/0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch @@ -0,0 +1,383 @@ +From 2acd4b6ca9cadb84eb38bf1fc4bd5b2ccab3c532 Mon Sep 17 00:00:00 2001 +From: Andrew Comminos <andrew@comminos.com> +Date: Tue, 27 Feb 2018 16:11:10 -0800 +Subject: [PATCH 6/8] wined3d: Switch wined3d_buffer_heap to be backed by an + rb-tree. + +--- + dlls/wined3d/buffer_heap.c | 230 ++++++++++++++++++----------------------- + dlls/wined3d/wined3d_private.h | 6 +- + 2 files changed, 105 insertions(+), 131 deletions(-) + +diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c +index 165a957edd..45d3a2c7d7 100644 +--- a/dlls/wined3d/buffer_heap.c ++++ b/dlls/wined3d/buffer_heap.c +@@ -19,6 +19,7 @@ + + #include "config.h" + #include "wine/port.h" ++#include "wine/rbtree.h" + #include "wined3d_private.h" + + WINE_DEFAULT_DEBUG_CHANNEL(d3d); +@@ -26,21 +27,26 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); + + struct wined3d_buffer_heap_element + { ++ struct wine_rb_entry entry; + struct wined3d_map_range range; ++}; + +- struct wined3d_buffer_heap_element *prev; +- struct wined3d_buffer_heap_element *next; ++struct wined3d_buffer_heap_range ++{ ++ struct wined3d_map_range range; ++ ++ struct wined3d_buffer_heap_range *next; + }; + + struct wined3d_buffer_heap_fenced_element + { +- struct wined3d_buffer_heap_element *ranges; ++ struct wined3d_buffer_heap_range *ranges; + struct wined3d_fence *fence; + +- struct wined3d_buffer_heap_element *next; ++ struct wined3d_buffer_heap_fenced_element *next; + }; + +-static struct wined3d_buffer_heap_element* element_new(GLintptr offset, GLsizeiptr size) ++static struct wined3d_buffer_heap_element* element_new(GLsizei offset, GLsizei size) + { + struct wined3d_buffer_heap_element* elem; + elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_buffer_heap_element)); +@@ -48,12 +54,10 @@ static struct wined3d_buffer_heap_element* element_new(GLintptr offset, GLsizeip + return NULL; + elem->range.offset = offset; + elem->range.size = size; +- elem->next = NULL; +- elem->prev = NULL; + return elem; + } + +-static struct wined3d_buffer_heap_fenced_element* fenced_element_new(struct wined3d_buffer_heap_element *ranges, struct wined3d_fence* fence) ++static struct wined3d_buffer_heap_fenced_element* fenced_element_new(struct wined3d_buffer_heap_range *ranges, struct wined3d_fence* fence) + { + struct wined3d_buffer_heap_fenced_element* elem; + elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_buffer_heap_fenced_element)); +@@ -65,97 +69,16 @@ static struct wined3d_buffer_heap_fenced_element* fenced_element_new(struct wine + return elem; + } + +-static void element_merge_adjacent(struct wined3d_buffer_heap_element **head, struct wined3d_buffer_heap_element *elem) +-{ +- struct wined3d_buffer_heap_element *cur_prev = elem->prev; +- struct wined3d_buffer_heap_element *cur_next = elem->next; +- if (cur_prev && cur_prev->range.offset + cur_prev->range.size == elem->range.offset) +- { +- elem->range.offset = cur_prev->range.offset; +- elem->range.size += cur_prev->range.size; +- +- elem->prev = cur_prev->prev; +- if (cur_prev->prev) +- cur_prev->prev->next = elem; +- +- if (cur_prev == *head) +- *head = elem; +- +- HeapFree(GetProcessHeap(), 0, cur_prev); +- } +- if (cur_next && cur_next->range.offset == elem->range.offset + elem->range.size) +- { +- elem->range.size += cur_next->range.size; +- elem->next = cur_next->next; +- if (cur_next->next) +- { +- cur_next->next->prev = elem; +- } +- HeapFree(GetProcessHeap(), 0, cur_next); +- } +-} +- +-// Inserts a range into the list starting at `elem`. +-// Updates the head of the list, if necessary. +-static void element_insert_range(struct wined3d_buffer_heap_element **head, struct wined3d_map_range range) ++static int free_tree_compare(const void *key, const struct wine_rb_entry *entry) + { +- struct wined3d_buffer_heap_element *elem = *head; +- struct wined3d_buffer_heap_element *new_elem; +- struct wined3d_buffer_heap_element *last_elem = NULL; +- +- // Special case where the head doesn't exist. +- if (!elem) +- { +- new_elem = element_new(range.offset, range.size); +- *head = new_elem; +- return; +- } +- +- while (elem) +- { +- struct wined3d_map_range *erange = &elem->range; +- if (range.offset + range.size == erange->offset) +- { +- // Left side merge +- erange->offset = range.offset; +- erange->size += range.size; +- // Check if this causes a merge with elem->prev +- element_merge_adjacent(head, elem); +- return; +- } +- else if (erange->offset + erange->size == range.offset) +- { +- // Right side merge +- erange->size += range.size; +- // Check if this causes a merge with elem->prev +- element_merge_adjacent(head, elem); +- return; +- } +- else if (range.offset < erange->offset) +- { +- // Append to left, non-merge case. +- new_elem = element_new(range.offset, range.size); +- new_elem->prev = elem->prev; +- new_elem->next = elem; +- if (elem->prev) +- { +- elem->prev->next = new_elem; +- } +- if (*head == elem) +- { +- *head = new_elem; +- } +- elem->prev = new_elem; +- return; +- } +- last_elem = elem; +- elem = elem->next; +- } +- +- // Larger offset than all other elements in the list, append to the end. +- new_elem = element_new(range.offset, range.size); +- new_elem->prev = last_elem; +- last_elem->next = new_elem; ++ const GLsizei offset = (const GLsizei) key; ++ struct wined3d_buffer_heap_element *elem = WINE_RB_ENTRY_VALUE(entry, struct wined3d_buffer_heap_element, entry); ++ ++ if (offset < elem->range.offset) ++ return -1; ++ if (offset > elem->range.offset) ++ return 1; ++ return 0; + } + + /* Context activation is done by the caller. */ +@@ -165,6 +88,7 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s + const GLenum buffer_target = GL_ARRAY_BUFFER; + GLbitfield access_flags; + GLbitfield storage_flags; ++ struct wined3d_buffer_heap_element *initial_elem; + + struct wined3d_buffer_heap *object; + +@@ -195,7 +119,11 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s + } + context_bind_bo(context, buffer_target, 0); + +- object->free_list_head = element_new(0, size); ++ wine_rb_init(&object->free_tree, free_tree_compare); ++ ++ initial_elem = element_new(0, size); ++ wine_rb_put(&object->free_tree, initial_elem->range.offset, &initial_elem->entry); ++ + object->fenced_head = object->fenced_tail = NULL; + object->alignment = alignment; + object->pending_fenced_bytes = 0; +@@ -217,10 +145,10 @@ HRESULT wined3d_buffer_heap_destroy(struct wined3d_buffer_heap *heap, struct win + + HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_map_range *out_range) + { +- EnterCriticalSection(&heap->temp_lock); ++ struct wine_rb_entry *iter; + + // TODO(acomminos): free list binning? +- struct wined3d_buffer_heap_element *elem = heap->free_list_head; ++ EnterCriticalSection(&heap->temp_lock); + + // Round to the nearest power of two to reduce fragmentation. + size = 1ULL << (int)ceil(log2(size)); +@@ -229,40 +157,35 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s + if (heap->alignment) + size += heap->alignment - (size % heap->alignment); + +- while (elem != NULL) ++ iter = wine_rb_head(heap->free_tree.root); ++ while (iter) + { +- TRACE("allocation at %p, size %lld\n", heap->map_ptr + elem->range.offset, elem->range.size); +- // XXX(acomminos): first fit is highly likely to be dumb, needs more analysis. ++ struct wined3d_buffer_heap_element *elem = WINE_RB_ENTRY_VALUE(iter, struct wined3d_buffer_heap_element, entry); + if (elem->range.size >= size) + { +- // Pull the range from the start of the free list element. +- out_range->offset = elem->range.offset; +- out_range->size = size; // XXX(acomminos): should we really give the exact size requested? ++ // FIXME(acomminos): should key based on end so that we can slice ++ // off the front without changing the key. ++ GLsizei remaining = elem->range.size - size; + +- elem->range.offset += size; +- elem->range.size -= size; ++ out_range->offset = elem->range.offset; ++ out_range->size = size; + +- if (elem->range.size == 0) ++ wine_rb_remove(&heap->free_tree, iter); ++ if (remaining > 0) ++ { ++ elem->range.offset += size; ++ elem->range.size -= size; ++ wine_rb_put(&heap->free_tree, (const void*) elem->range.offset, &elem->entry); ++ } ++ else + { +- if (elem->prev) +- { +- elem->prev->next = elem->next; +- } +- if (elem->next) +- { +- elem->next->prev = elem->prev; +- } +- if (heap->free_list_head == elem) +- { +- heap->free_list_head = elem->next; +- } + HeapFree(GetProcessHeap(), 0, elem); + } +- ++ TRACE("Allocated %lld bytes at %lld\n", out_range->size, out_range->offset); + LeaveCriticalSection(&heap->temp_lock); + return WINED3D_OK; + } +- elem = elem->next; ++ iter = wine_rb_next(iter); + } + + LeaveCriticalSection(&heap->temp_lock); +@@ -271,17 +194,68 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s + + HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3d_map_range range) + { ++ struct wined3d_buffer_heap_element *elem = element_new(range.offset, range.size); ++ struct wine_rb_entry *entry; ++ HRESULT hr; ++ ++ if (!elem) ++ return E_OUTOFMEMORY; ++ + EnterCriticalSection(&heap->temp_lock); ++ if (wine_rb_put(&heap->free_tree, (const void*) elem->range.offset, &elem->entry) == -1) ++ { ++ LeaveCriticalSection(&heap->temp_lock); ++ HeapFree(GetProcessHeap(), 0, elem); ++ return E_FAIL; ++ } + +- element_insert_range(&heap->free_list_head, range); ++ // Coalesce left. ++ entry = wine_rb_prev(&elem->entry); ++ if (entry) ++ { ++ TRACE("Coalesced left.\n"); ++ struct wined3d_buffer_heap_element *left_elem = WINE_RB_ENTRY_VALUE(elem, struct wined3d_buffer_heap_element, entry); ++ if (left_elem->range.offset + left_elem->range.size == elem->range.offset) ++ { ++ // Replace the newly inserted element with an extended node to its ++ // left. This doesn't change the key properties of the left node. ++ left_elem->range.size += range.size; ++ ++ wine_rb_remove(&heap->free_tree, &elem->entry); ++ HeapFree(GetProcessHeap(), 0, elem); ++ ++ elem = left_elem; ++ } ++ } ++ ++ // Coalesce right. ++ entry = wine_rb_next(&elem->entry); ++ if (entry) ++ { ++ TRACE("Coalesced right.\n"); ++ struct wined3d_buffer_heap_element *right_elem = WINE_RB_ENTRY_VALUE(elem, struct wined3d_buffer_heap_element, entry); ++ if (elem->range.offset + elem->range.size == right_elem->range.offset) ++ { ++ // Remove the right element, this doesn't change the keying of our ++ // newly inserted element. ++ elem->range.size += right_elem->range.size; ++ ++ wine_rb_remove(&heap->free_tree, &right_elem->entry); ++ HeapFree(GetProcessHeap(), 0, right_elem); ++ } ++ } + + LeaveCriticalSection(&heap->temp_lock); ++ + return WINED3D_OK; + } + + HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct wined3d_device *device, struct wined3d_map_range range) + { +- element_insert_range(&heap->pending_fenced_head, range); ++ struct wined3d_buffer_heap_range *elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_buffer_heap_range)); ++ elem->range = range; ++ elem->next = heap->pending_fenced_head; ++ heap->pending_fenced_head = elem; + + heap->pending_fenced_bytes += range.size; + if (heap->pending_fenced_bytes >= heap->pending_fenced_threshold_bytes) +@@ -338,11 +312,11 @@ HRESULT wined3d_buffer_heap_cs_poll_fences(struct wined3d_buffer_heap *heap, str + case WINED3D_FENCE_NOT_STARTED: + { + TRACE_(d3d_perf)("Freed fence group.\n"); +- struct wined3d_buffer_heap_element *range_elem = elem->ranges; ++ struct wined3d_buffer_heap_range *range_elem = elem->ranges; + // FIXME(acomminos): this might take a while. incrementally do this? + while (range_elem) + { +- struct wined3d_buffer_heap_element *next = range_elem->next; ++ struct wined3d_buffer_heap_range *next = range_elem->next; + wined3d_buffer_heap_free(heap, range_elem->range); + HeapFree(GetProcessHeap(), 0, range_elem); + range_elem = next; +diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h +index 62433a39b1..3a45d9931e 100644 +--- a/dlls/wined3d/wined3d_private.h ++++ b/dlls/wined3d/wined3d_private.h +@@ -3665,7 +3665,7 @@ enum wined3d_buffer_conversion_type + CONV_POSITIONT, + }; + +-struct wined3d_buffer_heap_element; ++struct wined3d_buffer_heap_range; + struct wined3d_buffer_heap_fenced_element; + + // A heap that manages allocations with a single GL buffer. +@@ -3677,10 +3677,10 @@ struct wined3d_buffer_heap + CRITICAL_SECTION temp_lock; // Temporary lock while we implement the fenced free list. + + // TODO: add buckets for free regions of a given size. +- struct wined3d_buffer_heap_element *free_list_head; ++ struct wine_rb_tree free_tree; // Free regions keyed on their base address. + + // Elements that need to be fenced, but haven't reached the required size. +- struct wined3d_buffer_heap_element *pending_fenced_head; ++ struct wined3d_buffer_heap_range *pending_fenced_head; + GLsizeiptr pending_fenced_bytes; // Number of free bytes in the active fenced region. + GLsizeiptr pending_fenced_threshold_bytes; // Number of bytes required before fencing. + +-- +2.16.2 + |