summarylogtreecommitdiffstats
path: root/0007-wined3d-Avoid-freeing-persistent-buffer-heap-element.patch
diff options
context:
space:
mode:
authorLars Norberg2018-03-26 22:40:54 +0200
committerLars Norberg2018-03-26 22:40:54 +0200
commit60a34983d19f8aabe667b20cf951ab4dda41d293 (patch)
treefba2b8424435d5853781e875fa78e86c7aac32a8 /0007-wined3d-Avoid-freeing-persistent-buffer-heap-element.patch
parentb9ee62f46a35e7eb1a40f0c7872e48f5ec776e82 (diff)
downloadaur-60a34983d19f8aabe667b20cf951ab4dda41d293.tar.gz
rebased wine-pba
Diffstat (limited to '0007-wined3d-Avoid-freeing-persistent-buffer-heap-element.patch')
-rw-r--r--0007-wined3d-Avoid-freeing-persistent-buffer-heap-element.patch351
1 files changed, 351 insertions, 0 deletions
diff --git a/0007-wined3d-Avoid-freeing-persistent-buffer-heap-element.patch b/0007-wined3d-Avoid-freeing-persistent-buffer-heap-element.patch
new file mode 100644
index 000000000000..d0872df82707
--- /dev/null
+++ b/0007-wined3d-Avoid-freeing-persistent-buffer-heap-element.patch
@@ -0,0 +1,351 @@
+From fc7907d5264c1606477f9287c949c3c8794859ec Mon Sep 17 00:00:00 2001
+From: Andrew Comminos <andrew@comminos.com>
+Date: Thu, 8 Mar 2018 23:01:50 -0800
+Subject: [PATCH 7/9] wined3d: Avoid freeing persistent buffer heap elements
+ during use.
+
+Using HeapFree is expensive, especially when we don't have our buffers
+for long.
+---
+ dlls/wined3d/buffer.c | 29 +++++++++++----------
+ dlls/wined3d/buffer_heap.c | 57 ++++++++++++++++++------------------------
+ dlls/wined3d/context.c | 4 +--
+ dlls/wined3d/cs.c | 6 ++---
+ dlls/wined3d/wined3d_private.h | 25 ++++++++++++------
+ 5 files changed, 61 insertions(+), 60 deletions(-)
+
+diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c
+index c492fcc8c6..74b3ba8abd 100644
+--- a/dlls/wined3d/buffer.c
++++ b/dlls/wined3d/buffer.c
+@@ -276,7 +276,7 @@ static BOOL buffer_alloc_persistent_map(struct wined3d_buffer *buffer)
+ {
+ struct wined3d_device *device = buffer->resource.device;
+ struct wined3d_buffer_heap *heap;
+- struct wined3d_map_range map_range;
++ struct wined3d_buffer_heap_element *elem;
+ HRESULT hr;
+
+ if (buffer->bind_flags & WINED3D_BIND_CONSTANT_BUFFER)
+@@ -292,12 +292,12 @@ static BOOL buffer_alloc_persistent_map(struct wined3d_buffer *buffer)
+ }
+
+ buffer->buffer_heap = heap;
+- if (FAILED(hr = wined3d_buffer_heap_alloc(heap, buffer->resource.size, &map_range)))
++ if (FAILED(hr = wined3d_buffer_heap_alloc(heap, buffer->resource.size, &elem)))
+ {
+ goto fail;
+ }
+- buffer->cs_persistent_map = map_range;
+- buffer->mt_persistent_map = map_range;
++ buffer->cs_persistent_map = elem;
++ buffer->mt_persistent_map = elem;
+ return TRUE;
+
+ fail:
+@@ -753,7 +753,7 @@ BOOL wined3d_buffer_load_location(struct wined3d_buffer *buffer,
+ if (buffer->conversion_map)
+ FIXME("Attempting to use conversion map with persistent mapping.\n");
+ memcpy(buffer->buffer_heap->map_ptr +
+- buffer->cs_persistent_map.offset,
++ buffer->cs_persistent_map->range.offset,
+ buffer->resource.heap_memory, buffer->resource.size);
+ break;
+
+@@ -801,11 +801,11 @@ DWORD wined3d_buffer_get_memory(struct wined3d_buffer *buffer,
+ {
+ // FIXME(acomminos): should we expose a buffer object we don't wholly own here?
+ data->buffer_object = buffer->buffer_heap->buffer_object;
+- data->addr = buffer->cs_persistent_map.offset;
++ data->addr = buffer->cs_persistent_map->range.offset;
+ // Note that the size of the underlying buffer allocation may be larger
+ // than the buffer knows about. In this case, we've rounded it up to be
+ // aligned (e.g. for uniform buffer offsets).
+- data->length = buffer->cs_persistent_map.size;
++ data->length = buffer->cs_persistent_map->range.size;
+ return WINED3D_LOCATION_PERSISTENT_MAP;
+ }
+ if (locations & WINED3D_LOCATION_SYSMEM)
+@@ -1122,7 +1122,7 @@ static HRESULT wined3d_buffer_map(struct wined3d_buffer *buffer, UINT offset, UI
+ gl_info->gl_ops.gl.p_glFinish();
+
+ base = buffer->buffer_heap->map_ptr
+- + buffer->cs_persistent_map.offset;
++ + buffer->cs_persistent_map->range.offset;
+ *data = base + offset;
+
+ context_release(context);
+@@ -1412,22 +1412,21 @@ static HRESULT buffer_resource_sub_resource_map(struct wined3d_resource *resourc
+ if (flags & WINED3D_MAP_DISCARD)
+ {
+ HRESULT hr;
+- struct wined3d_map_range map_range;
+- if (FAILED(hr = wined3d_buffer_heap_alloc(buffer->buffer_heap, resource->size, &map_range)))
++ struct wined3d_buffer_heap_element *mt_elem;
++ if (FAILED(hr = wined3d_buffer_heap_alloc(buffer->buffer_heap, resource->size, &mt_elem)))
+ {
+ FIXME_(d3d_perf)("Failed to allocate new buffer, falling back to sync path.\n");
+ return hr;
+ }
+- map_desc->data = buffer->buffer_heap->map_ptr + map_range.offset + offset;
++ map_desc->data = buffer->buffer_heap->map_ptr + mt_elem->range.offset + offset;
+ resource->map_count++;
+
+- buffer->mt_persistent_map = map_range;
++ buffer->mt_persistent_map = mt_elem;
+
+ // Discard handler on CSMT thread is responsible for returning the
+ // currently used buffer to the free pool, along with the fence that
+ // must be called before the buffer can be reused.
+- wined3d_cs_emit_discard_buffer(resource->device->cs, buffer, map_range);
+-
++ wined3d_cs_emit_discard_buffer(resource->device->cs, buffer, mt_elem);
+ return WINED3D_OK;
+ }
+ else if (flags & WINED3D_MAP_NOOVERWRITE)
+@@ -1435,7 +1434,7 @@ static HRESULT buffer_resource_sub_resource_map(struct wined3d_resource *resourc
+ // Allow immediate access for persistent buffers without a fence.
+ // Always use the latest buffer in this case in case the latest
+ // DISCARDed one hasn't reached the command stream yet.
+- struct wined3d_map_range map_range = buffer->mt_persistent_map;
++ struct wined3d_map_range map_range = buffer->mt_persistent_map->range;
+ map_desc->data = buffer->buffer_heap->map_ptr + map_range.offset + offset;
+ resource->map_count++;
+
+diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c
+index 75f84b0088..80670c515f 100644
+--- a/dlls/wined3d/buffer_heap.c
++++ b/dlls/wined3d/buffer_heap.c
+@@ -25,18 +25,6 @@
+ WINE_DEFAULT_DEBUG_CHANNEL(d3d);
+ WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
+
+-struct wined3d_buffer_heap_element
+-{
+- struct wined3d_map_range range;
+-
+- // rbtree data
+- struct wine_rb_entry entry;
+-
+- // Binned free list positions
+- struct wined3d_buffer_heap_element *next;
+- struct wined3d_buffer_heap_element *prev;
+-};
+-
+ struct wined3d_buffer_heap_fenced_element
+ {
+ struct wined3d_buffer_heap_bin_set free_list;
+@@ -82,6 +70,11 @@ static int element_bin(struct wined3d_buffer_heap_element *elem)
+ // Inserts an element into the appropriate free list bin.
+ static void element_insert_free_bin(struct wined3d_buffer_heap *heap, struct wined3d_buffer_heap_element *elem)
+ {
++ if (elem->prev || elem->next)
++ {
++ ERR("Element %p in already in a free list (for some reason).\n", elem);
++ }
++
+ int bin = element_bin(elem);
+
+ elem->prev = NULL;
+@@ -206,7 +199,7 @@ HRESULT wined3d_buffer_heap_destroy(struct wined3d_buffer_heap *heap, struct win
+ return WINED3D_OK;
+ }
+
+-HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_map_range *out_range)
++HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_buffer_heap_element **out_elem)
+ {
+ int initial_bin;
+ int initial_size = size;
+@@ -233,24 +226,24 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s
+ remaining_range.offset = elem->range.offset + size;
+ remaining_range.size = elem->range.size - size;
+
+- out_range->offset = elem->range.offset;
+- out_range->size = size;
++ // Take the element from the free list, transferring ownership to
++ // the caller.
++ element_remove_free(heap, elem);
++ // Resize the element so that we can free the remainder.
++ elem->range.size = size;
+
+- TRACE_(d3d_perf)("Allocated %d (requested %d) at %p from bin %d (initial %d)\n", size, initial_size, elem->range.offset, i, initial_bin);
++ *out_elem = elem;
+
+- // Remove the element from its current free bin to move it to the correct list.
+- element_remove_free(heap, elem);
++ TRACE_(d3d_perf)("Allocated %d (requested %d) at %p from bin %d (initial %d)\n", size, initial_size, elem->range.offset, i, initial_bin);
+
+ if (remaining_range.size > 0)
+ {
++ struct wined3d_buffer_heap_element *remaining_elem;
++
+ TRACE_(d3d_perf)("Imperfect fit allocated, fragmenting remainder of %lld at %p.\n", remaining_range.size, remaining_range.offset);
+
+- elem->range = remaining_range;
+- element_insert_free_bin(heap, elem);
+- }
+- else
+- {
+- HeapFree(GetProcessHeap(), 0, elem);
++ remaining_elem = element_new(remaining_range.offset, remaining_range.size);
++ element_insert_free_bin(heap, remaining_elem);
+ }
+
+ LeaveCriticalSection(&heap->temp_lock);
+@@ -265,7 +258,7 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s
+ if (SUCCEEDED(wined3d_buffer_heap_deferred_coalesce(heap, &num_coalesced)))
+ {
+ if (num_coalesced > 0)
+- return wined3d_buffer_heap_alloc(heap, size, out_range);
++ return wined3d_buffer_heap_alloc(heap, size, out_elem);
+ }
+
+ FIXME_(d3d_perf)("Coalescing did not create new blocks, failing.\n");
+@@ -273,16 +266,15 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s
+ return WINED3DERR_OUTOFVIDEOMEMORY;
+ }
+
+-HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3d_map_range range)
++HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3d_buffer_heap_element *elem)
+ {
+- struct wined3d_buffer_heap_element *elem = element_new(range.offset, range.size);
+-
+- if (!elem)
+- return E_OUTOFMEMORY;
+-
+ EnterCriticalSection(&heap->temp_lock);
+
+ // Only insert the element into a free bin, coalescing will occur later.
++ //
++ // Note that the reason that we pass around wined3d_buffer_heap_element
++ // instead of a range is to avoid frequent HeapAlloc/HeapFree operations
++ // when we're reusing buffers.
+ element_insert_free_bin(heap, elem);
+
+ LeaveCriticalSection(&heap->temp_lock);
+@@ -290,9 +282,8 @@ HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3
+ return WINED3D_OK;
+ }
+
+-HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct wined3d_device *device, struct wined3d_map_range range)
++HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct wined3d_device *device, struct wined3d_buffer_heap_element *elem)
+ {
+- struct wined3d_buffer_heap_element *elem = element_new(range.offset, range.size);
+ int bin_index = element_bin(elem);
+ struct wined3d_buffer_heap_bin *bin = &heap->pending_fenced_bins.bins[bin_index];
+
+diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
+index eae2c3a79d..01aa53597f 100644
+--- a/dlls/wined3d/context.c
++++ b/dlls/wined3d/context.c
+@@ -5005,9 +5005,9 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s
+ if (parameters->indexed)
+ {
+ struct wined3d_buffer *index_buffer = state->index_buffer;
+- if (index_buffer->locations & WINED3D_LOCATION_PERSISTENT_MAP)
++ if (index_buffer->cs_persistent_map)
+ {
+- idx_data = index_buffer->cs_persistent_map.offset;
++ idx_data = index_buffer->cs_persistent_map->range.offset;
+ }
+ else if (!index_buffer->buffer_object || !stream_info->all_vbo)
+ {
+diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
+index e61b8dedbb..d1f665d505 100644
+--- a/dlls/wined3d/cs.c
++++ b/dlls/wined3d/cs.c
+@@ -444,7 +444,7 @@ struct wined3d_cs_discard_buffer
+ {
+ enum wined3d_cs_op opcode;
+ struct wined3d_buffer *buffer;
+- struct wined3d_map_range map_range;
++ struct wined3d_buffer_heap_element *map_range;
+ };
+
+ struct wined3d_cs_stop
+@@ -2496,14 +2496,14 @@ static void wined3d_cs_exec_discard_buffer(struct wined3d_cs *cs, const void *da
+ wined3d_resource_release(&op->buffer->resource);
+ }
+
+-void wined3d_cs_emit_discard_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer, struct wined3d_map_range map_range)
++void wined3d_cs_emit_discard_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer, struct wined3d_buffer_heap_element *elem)
+ {
+ struct wined3d_cs_discard_buffer *op;
+
+ op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
+ op->opcode = WINED3D_CS_OP_DISCARD_BUFFER;
+ op->buffer = buffer;
+- op->map_range = map_range;
++ op->map_range = elem;
+
+ wined3d_resource_acquire(&buffer->resource);
+
+diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
+index b3fd0136ff..0114444943 100644
+--- a/dlls/wined3d/wined3d_private.h
++++ b/dlls/wined3d/wined3d_private.h
+@@ -3531,6 +3531,18 @@ struct wined3d_map_range
+ GLsizeiptr size;
+ };
+
++struct wined3d_buffer_heap_element
++{
++ struct wined3d_map_range range;
++
++ // rbtree data
++ struct wine_rb_entry entry;
++
++ // Binned free list positions
++ struct wined3d_buffer_heap_element *next;
++ struct wined3d_buffer_heap_element *prev;
++};
++
+ enum wined3d_cs_queue_id
+ {
+ WINED3D_CS_QUEUE_DEFAULT = 0,
+@@ -3677,7 +3689,7 @@ void wined3d_cs_emit_unload_resource(struct wined3d_cs *cs, struct wined3d_resou
+ void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
+ unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
+ unsigned int slice_pitch) DECLSPEC_HIDDEN;
+-void wined3d_cs_emit_discard_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer, struct wined3d_map_range map_range) DECLSPEC_HIDDEN;
++void wined3d_cs_emit_discard_buffer(struct wined3d_cs *cs, struct wined3d_buffer *buffer, struct wined3d_buffer_heap_element *map_range) DECLSPEC_HIDDEN;
+ void wined3d_cs_init_object(struct wined3d_cs *cs,
+ void (*callback)(void *object), void *object) DECLSPEC_HIDDEN;
+ HRESULT wined3d_cs_map(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx,
+@@ -3711,7 +3723,6 @@ enum wined3d_buffer_conversion_type
+ CONV_POSITIONT,
+ };
+
+-struct wined3d_buffer_heap_element;
+ struct wined3d_buffer_heap_fenced_element;
+
+ // Number of power-of-two buckets to populate.
+@@ -3750,11 +3761,11 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s
+ HRESULT wined3d_buffer_heap_destroy(struct wined3d_buffer_heap *heap, struct wined3d_context *context) DECLSPEC_HIDDEN;
+ // Fetches a buffer from the heap of at least the given size.
+ // Attempts to coalesce blocks under memory pressure.
+-HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_map_range* out_range) DECLSPEC_HIDDEN;
++HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_buffer_heap_element** out_elem) DECLSPEC_HIDDEN;
+ // Immediately frees a heap-allocated buffer segment.
+-HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3d_map_range range) DECLSPEC_HIDDEN;
++HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3d_buffer_heap_element *elem) DECLSPEC_HIDDEN;
+ // Enqueues a buffer segment to return to the heap once its fence has been signaled.
+-HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct wined3d_device *device, struct wined3d_map_range range) DECLSPEC_HIDDEN;
++HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct wined3d_device *device, struct wined3d_buffer_heap_element *elem) DECLSPEC_HIDDEN;
+ // Issues a fence for the current set of pending fenced buffers.
+ // Double-buffered: if the last fence issued has not yet been triggered, waits
+ // on it.
+@@ -3793,8 +3804,8 @@ struct wined3d_buffer
+
+ /* persistent mapped buffer */
+ struct wined3d_buffer_heap *buffer_heap;
+- struct wined3d_map_range cs_persistent_map;
+- struct wined3d_map_range mt_persistent_map; // TODO: make struct list?
++ struct wined3d_buffer_heap_element *cs_persistent_map;
++ struct wined3d_buffer_heap_element *mt_persistent_map;
+ };
+
+ static inline struct wined3d_buffer *buffer_from_resource(struct wined3d_resource *resource)
+--
+2.16.2
+