summarylogtreecommitdiffstats
path: root/0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch
diff options
context:
space:
mode:
authorStefan Schmidt2018-03-01 13:40:31 +0100
committerStefan Schmidt2018-03-01 13:40:31 +0100
commit9065f70a5d47e4cf8f466b68104d5ddeb7f02409 (patch)
tree7227516d4faeca513d8ff787cd22ed72ba2cd064 /0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch
downloadaur-9065f70a5d47e4cf8f466b68104d5ddeb7f02409.tar.gz
Initial version (tracks 68de8e9b3f26e68bc6d64f353e0954ddab2f7590)
Diffstat (limited to '0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch')
-rw-r--r--0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch305
1 files changed, 305 insertions, 0 deletions
diff --git a/0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch b/0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch
new file mode 100644
index 000000000000..fb80a0f89597
--- /dev/null
+++ b/0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch
@@ -0,0 +1,305 @@
+From 89ca25afda23b8ed5f6dc5cc6a3fe010a4b63352 Mon Sep 17 00:00:00 2001
+From: Andrew Comminos <andrew@comminos.com>
+Date: Tue, 27 Feb 2018 18:10:36 -0800
+Subject: [PATCH 7/8] wined3d: Add segregated free bins to complement
+ rbtree-backed free list.
+
+---
+ dlls/wined3d/buffer_heap.c | 154 +++++++++++++++++++++++++++++++----------
+ dlls/wined3d/wined3d_private.h | 8 ++-
+ 2 files changed, 122 insertions(+), 40 deletions(-)
+
+diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c
+index 45d3a2c7d7..f4af1b93b9 100644
+--- a/dlls/wined3d/buffer_heap.c
++++ b/dlls/wined3d/buffer_heap.c
+@@ -29,6 +29,10 @@ struct wined3d_buffer_heap_element
+ {
+ struct wine_rb_entry entry;
+ struct wined3d_map_range range;
++
++ // Binned free list positions
++ struct wined3d_buffer_heap_element *next;
++ struct wined3d_buffer_heap_element *prev;
+ };
+
+ struct wined3d_buffer_heap_range
+@@ -54,9 +58,76 @@ static struct wined3d_buffer_heap_element* element_new(GLsizei offset, GLsizei s
+ return NULL;
+ elem->range.offset = offset;
+ elem->range.size = size;
++ elem->prev = NULL;
++ elem->next = NULL;
+ return elem;
+ }
+
++static inline int bitwise_log2_floor(GLsizei size)
++{
++ // XXX(acomminos): I hope this gets unrolled.
++ for (int i = 8 * sizeof(GLsizei) - 1; i >= 0; i--)
++ {
++ if ((size >> i) & 1) {
++ return i;
++ }
++ }
++ return 0;
++}
++
++static inline int bitwise_log2_ceil(GLsizei size)
++{
++ // Add one to the floor of size if size isn't a power of two.
++ return bitwise_log2_floor(size) + !!(size & (size - 1));
++}
++
++static int element_bin(struct wined3d_buffer_heap_element *elem)
++{
++ return min(WINED3D_BUFFER_HEAP_BINS - 1, bitwise_log2_floor(elem->range.size));
++}
++
++// Inserts and element into the free tree and its bin.
++// Does not coalesce.
++static void element_insert_free(struct wined3d_buffer_heap *heap, struct wined3d_buffer_heap_element *elem)
++{
++ int bin = element_bin(elem);
++
++ elem->prev = NULL;
++ elem->next = heap->free_bins[bin];
++ if (heap->free_bins[bin])
++ heap->free_bins[bin]->prev = elem;
++ heap->free_bins[bin] = elem;
++
++ if (wine_rb_put(&heap->free_tree, &elem->range.offset, &elem->entry) == -1)
++ {
++ ERR("Failed to insert element into free tree.\n");
++ }
++
++ TRACE("Inserted allocation at %p of size %lld into bin %d\n", elem->range.offset, elem->range.size, bin);
++}
++
++// Removes an element from the free tree and its bin.
++static void element_remove_free(struct wined3d_buffer_heap *heap, struct wined3d_buffer_heap_element *elem)
++{
++ int bin = element_bin(elem);
++
++ if (elem->prev)
++ elem->prev->next = elem->next;
++
++ if (elem->next)
++ elem->next->prev = elem->prev;
++
++ if (!elem->prev)
++ heap->free_bins[bin] = elem->next;
++
++ elem->prev = NULL;
++ elem->next = NULL;
++
++ wine_rb_remove(&heap->free_tree, &elem->entry);
++
++ TRACE("Freed allocation at %p of size %lld from bin %d\n", elem->range.offset, elem->range.size, bin);
++}
++
+ 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;
+@@ -71,7 +142,7 @@ static struct wined3d_buffer_heap_fenced_element* fenced_element_new(struct wine
+
+ static int free_tree_compare(const void *key, const struct wine_rb_entry *entry)
+ {
+- const GLsizei offset = (const GLsizei) key;
++ 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)
+@@ -121,9 +192,6 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s
+
+ 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;
+@@ -131,6 +199,9 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s
+ object->pending_fenced_threshold_bytes = size / 4; // FIXME(acomminos): make this externally declared
+ InitializeCriticalSection(&object->temp_lock);
+
++ initial_elem = element_new(0, size);
++ element_insert_free(object, initial_elem);
++
+ *buffer_heap = object;
+
+ return WINED3D_OK;
+@@ -145,56 +216,57 @@ 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)
+ {
+- struct wine_rb_entry *iter;
+-
+- // TODO(acomminos): free list binning?
++ int initial_bin;
+ EnterCriticalSection(&heap->temp_lock);
+
+ // Round to the nearest power of two to reduce fragmentation.
+- size = 1ULL << (int)ceil(log2(size));
++ size = 1ULL << bitwise_log2_ceil(size);
+
+ // Round up the size to a multiple of the heap's alignment.
+ if (heap->alignment)
+ size += heap->alignment - (size % heap->alignment);
+
+- iter = wine_rb_head(heap->free_tree.root);
+- while (iter)
++ // TODO(acomminos): use bitwise arithmetic instead
++ initial_bin = min(WINED3D_BUFFER_HEAP_BINS - 1, bitwise_log2_ceil(size));
++
++ for (int i = initial_bin; i < WINED3D_BUFFER_HEAP_BINS; i++)
+ {
+- struct wined3d_buffer_heap_element *elem = WINE_RB_ENTRY_VALUE(iter, struct wined3d_buffer_heap_element, entry);
+- if (elem->range.size >= size)
++ struct wined3d_buffer_heap_element *elem = heap->free_bins[i];
++ if (elem)
+ {
+- // 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;
++ struct wined3d_map_range remaining_range;
++ remaining_range.offset = elem->range.offset + size;
++ remaining_range.size = elem->range.size - size;
+
+ out_range->offset = elem->range.offset;
+ out_range->size = size;
+
+- wine_rb_remove(&heap->free_tree, iter);
+- if (remaining > 0)
++ // Remove the element from its current free bin to move it to the correct list.
++ element_remove_free(heap, elem);
++
++ if (remaining_range.size > 0)
+ {
+- elem->range.offset += size;
+- elem->range.size -= size;
+- wine_rb_put(&heap->free_tree, (const void*) elem->range.offset, &elem->entry);
++ elem->range = remaining_range;
++ element_insert_free(heap, elem);
+ }
+ else
+ {
+ HeapFree(GetProcessHeap(), 0, elem);
+ }
+- TRACE("Allocated %lld bytes at %lld\n", out_range->size, out_range->offset);
++
+ LeaveCriticalSection(&heap->temp_lock);
+ return WINED3D_OK;
+ }
+- iter = wine_rb_next(iter);
+ }
+
+ LeaveCriticalSection(&heap->temp_lock);
+- return WINED3DERR_OUTOFVIDEOMEMORY; // FIXME(acomminos): probably wrong return code.
++ return WINED3DERR_OUTOFVIDEOMEMORY;
+ }
+
+ 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 wined3d_map_range coalesced_range = range;
+ struct wine_rb_entry *entry;
+ HRESULT hr;
+
+@@ -202,7 +274,12 @@ HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3
+ return E_OUTOFMEMORY;
+
+ EnterCriticalSection(&heap->temp_lock);
+- if (wine_rb_put(&heap->free_tree, (const void*) elem->range.offset, &elem->entry) == -1)
++
++ // TODO(acomminos): implement lower_bound, upper_bound.
++ // we don't have to allocate a new elem here, this sentry
++ // is just so I can get this proof of concept out the door.
++
++ if (wine_rb_put(&heap->free_tree, &elem->range.offset, &elem->entry) == -1)
+ {
+ LeaveCriticalSection(&heap->temp_lock);
+ HeapFree(GetProcessHeap(), 0, elem);
+@@ -214,17 +291,14 @@ HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3
+ 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)
++ struct wined3d_buffer_heap_element *left_elem = WINE_RB_ENTRY_VALUE(entry, struct wined3d_buffer_heap_element, entry);
++ if (left_elem->range.offset + left_elem->range.size == coalesced_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);
++ coalesced_range.offset = left_elem->range.offset;
++ coalesced_range.size = coalesced_range.size + left_elem->range.size;
+
+- elem = left_elem;
++ element_remove_free(heap, left_elem);
++ HeapFree(GetProcessHeap(), 0, left_elem);
+ }
+ }
+
+@@ -233,18 +307,22 @@ HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3
+ if (entry)
+ {
+ TRACE("Coalesced right.\n");
+- struct wined3d_buffer_heap_element *right_elem = WINE_RB_ENTRY_VALUE(elem, struct wined3d_buffer_heap_element, entry);
++ struct wined3d_buffer_heap_element *right_elem = WINE_RB_ENTRY_VALUE(entry, 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;
++ coalesced_range.size += right_elem->range.size;
+
+- wine_rb_remove(&heap->free_tree, &right_elem->entry);
++ element_remove_free(heap, right_elem);
+ HeapFree(GetProcessHeap(), 0, right_elem);
+ }
+ }
+
++ wine_rb_remove(&heap->free_tree, &elem->entry);
++
++ // Update with coalesced range.
++ elem->range = coalesced_range;
++ element_insert_free(heap, elem);
++
+ LeaveCriticalSection(&heap->temp_lock);
+
+ return WINED3D_OK;
+diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
+index 3a45d9931e..14cad92f0f 100644
+--- a/dlls/wined3d/wined3d_private.h
++++ b/dlls/wined3d/wined3d_private.h
+@@ -3665,8 +3665,12 @@ enum wined3d_buffer_conversion_type
+ CONV_POSITIONT,
+ };
+
+-struct wined3d_buffer_heap_range;
++struct wined3d_buffer_heap_element;
+ struct wined3d_buffer_heap_fenced_element;
++struct wined3d_buffer_heap_range;
++
++// Number of power-of-two buckets to populate.
++#define WINED3D_BUFFER_HEAP_BINS 32
+
+ // A heap that manages allocations with a single GL buffer.
+ struct wined3d_buffer_heap
+@@ -3676,7 +3680,7 @@ struct wined3d_buffer_heap
+ GLsizeiptr alignment;
+ 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_bins[WINED3D_BUFFER_HEAP_BINS];
+ 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.
+--
+2.16.2
+