diff options
Diffstat (limited to '0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch')
-rw-r--r-- | 0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch | 456 |
1 files changed, 0 insertions, 456 deletions
diff --git a/0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch b/0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch deleted file mode 100644 index 565b172be923..000000000000 --- a/0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch +++ /dev/null @@ -1,456 +0,0 @@ -From 636d39db43f9cd176fe85869db5e07d3a39f80fb Mon Sep 17 00:00:00 2001 -From: Andrew Comminos <andrew@comminos.com> -Date: Fri, 23 Feb 2018 17:39:13 -0800 -Subject: [PATCH 1/8] wined3d: Implement a simple heap allocator backed by a - persistent buffer. - ---- - dlls/wined3d-csmt/Makefile.in | 1 + - dlls/wined3d/Makefile.in | 1 + - dlls/wined3d/buffer_heap.c | 321 +++++++++++++++++++++++++++++++++++++++++ - dlls/wined3d/directx.c | 3 + - dlls/wined3d/wined3d_gl.h | 1 + - dlls/wined3d/wined3d_private.h | 41 +++++- - 6 files changed, 364 insertions(+), 4 deletions(-) - create mode 100644 dlls/wined3d/buffer_heap.c - -diff --git a/dlls/wined3d-csmt/Makefile.in b/dlls/wined3d-csmt/Makefile.in -index bf064ed16f..cab1e6fdc1 100644 ---- a/dlls/wined3d-csmt/Makefile.in -+++ b/dlls/wined3d-csmt/Makefile.in -@@ -8,6 +8,7 @@ C_SRCS = \ - arb_program_shader.c \ - ati_fragment_shader.c \ - buffer.c \ -+ buffer_heap.c \ - context.c \ - cs.c \ - device.c \ -diff --git a/dlls/wined3d/Makefile.in b/dlls/wined3d/Makefile.in -index 70f47c6a5f..e78745cc11 100644 ---- a/dlls/wined3d/Makefile.in -+++ b/dlls/wined3d/Makefile.in -@@ -6,6 +6,7 @@ C_SRCS = \ - arb_program_shader.c \ - ati_fragment_shader.c \ - buffer.c \ -+ buffer_heap.c \ - context.c \ - cs.c \ - device.c \ -diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c -new file mode 100644 -index 0000000000..900e2d24bb ---- /dev/null -+++ b/dlls/wined3d/buffer_heap.c -@@ -0,0 +1,321 @@ -+/* -+ * Copyright 2018 Andrew Comminos -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ * -+ */ -+ -+#include "config.h" -+#include "wine/port.h" -+#include "wined3d_private.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(d3d); -+ -+struct wined3d_buffer_heap_element -+{ -+ struct wined3d_map_range range; -+ -+ struct wined3d_buffer_heap_element *prev; -+ struct wined3d_buffer_heap_element *next; -+}; -+ -+struct wined3d_buffer_heap_fenced_element -+{ -+ struct wined3d_map_range range; -+ struct wined3d_fence *fence; -+ -+ struct wined3d_buffer_heap_element *next; -+}; -+ -+static struct wined3d_buffer_heap_element* element_new(GLintptr offset, GLsizeiptr size) -+{ -+ struct wined3d_buffer_heap_element* elem; -+ elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_buffer_heap_element)); -+ if (!elem) -+ 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_map_range range, struct wined3d_fence* fence) -+{ -+ struct wined3d_buffer_heap_fenced_element* elem; -+ elem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_buffer_heap_fenced_element)); -+ if (!elem) -+ return NULL; -+ elem->range = range; -+ elem->fence = fence; -+ elem->next = NULL; -+ return elem; -+} -+ -+static void element_merge_adjacent(struct wined3d_buffer_heap *heap, 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 == heap->free_list_head) -+ heap->free_list_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); -+ } -+} -+ -+/* Context activation is done by the caller. */ -+HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr size, BOOL write_only, struct wined3d_buffer_heap **buffer_heap) -+{ -+ const struct wined3d_gl_info *gl_info = context->gl_info; -+ const GLenum buffer_target = GL_ARRAY_BUFFER; -+ GLbitfield access_flags; -+ GLbitfield storage_flags; -+ -+ struct wined3d_buffer_heap *object; -+ -+ if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) -+ { -+ return E_OUTOFMEMORY; -+ } -+ -+ access_flags = GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT | GL_MAP_WRITE_BIT; -+ if (!write_only) -+ { -+ access_flags |= GL_MAP_READ_BIT; -+ } -+ storage_flags = access_flags; // XXX(acomminos): will we need dynamic storage? -+ -+ // TODO(acomminos): where should we be checking for errors here? -+ -+ // TODO(acomminos): assert from CS thread? -+ GL_EXTCALL(glGenBuffers(1, &object->buffer_object)); -+ -+ // XXX(acomminos): use glNamedBufferStorage? -+ context_bind_bo(context, buffer_target, object->buffer_object); -+ -+ // TODO(acomminos): assert glBufferStorage supported? -+ GL_EXTCALL(glBufferStorage(buffer_target, size, NULL, storage_flags)); -+ -+ if (!(object->map_ptr = GL_EXTCALL(glMapBufferRange(buffer_target, 0, size, access_flags)))) -+ { -+ // TODO(acomminos): include error message -+ ERR("Couldn't map persistent buffer.\n"); -+ return -1; // FIXME(acomminos): proper error code, cleanup -+ } -+ context_bind_bo(context, buffer_target, 0); -+ -+ object->free_list_head = element_new(0, size); -+ object->fenced_head = object->fenced_tail = NULL; -+ InitializeCriticalSection(&object->temp_lock); -+ -+ *buffer_heap = object; -+ -+ return WINED3D_OK; -+} -+ -+/* Context activation is done by the caller. */ -+HRESULT wined3d_buffer_heap_destroy(struct wined3d_buffer_heap *heap, struct wined3d_context *context) -+{ -+ // TODO -+ return WINED3D_OK; -+} -+ -+HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_map_range *out_range) { -+ EnterCriticalSection(&heap->temp_lock); -+ -+ // TODO(acomminos): free list binning? -+ struct wined3d_buffer_heap_element *elem = heap->free_list_head; -+ // XXX(acomminos): Avoid fragmentation by rounding to nearest power of two. -+ while (elem != NULL) -+ { -+ 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. -+ 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? -+ -+ elem->range.offset += size; -+ elem->range.size -= size; -+ -+ if (elem->range.size == 0) -+ { -+ 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); -+ } -+ LeaveCriticalSection(&heap->temp_lock); -+ return WINED3D_OK; -+ } -+ elem = elem->next; -+ } -+ -+ LeaveCriticalSection(&heap->temp_lock); -+ return WINED3DERR_OUTOFVIDEOMEMORY; // FIXME(acomminos): probably wrong return code. -+} -+ -+HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3d_map_range range) -+{ -+ EnterCriticalSection(&heap->temp_lock); -+ struct wined3d_buffer_heap_element *new_elem; -+ struct wined3d_buffer_heap_element *elem = heap->free_list_head; -+ 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); -+ heap->free_list_head = new_elem; -+ goto success; -+ } -+ -+ 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(heap, elem); -+ goto success; -+ } -+ 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(heap, elem); -+ goto success; -+ } -+ 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 (heap->free_list_head == elem) -+ { -+ heap->free_list_head = new_elem; -+ } -+ elem->prev = new_elem; -+ goto success; -+ } -+ 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; -+ -+success: -+ LeaveCriticalSection(&heap->temp_lock); -+ return WINED3D_OK; -+} -+ -+HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct wined3d_map_range range, struct wined3d_fence *fence) -+{ -+ struct wined3d_buffer_heap_fenced_element *elem; -+ elem = fenced_element_new(range, fence); -+ if (!elem) -+ return E_OUTOFMEMORY; -+ -+ // Append to end of fenced list, which works well if you assume that buffers -+ // are freed in some ascending draw call ordering. -+ if (!heap->fenced_head) -+ { -+ heap->fenced_head = elem; -+ heap->fenced_tail = elem; -+ } -+ else -+ { -+ heap->fenced_tail->next = elem; -+ heap->fenced_tail = elem; -+ } -+ -+ return WINED3D_OK; -+} -+ -+HRESULT wined3d_buffer_heap_cs_poll_fences(struct wined3d_buffer_heap *heap, struct wined3d_device *device) -+{ -+ enum wined3d_fence_result res; -+ struct wined3d_buffer_heap_fenced_element *elem = heap->fenced_head; -+ if (!elem) -+ return WINED3D_OK; -+ -+ while (elem) -+ { -+ res = wined3d_fence_test(elem->fence, device, 0); -+ switch (res) -+ { -+ case WINED3D_FENCE_OK: -+ case WINED3D_FENCE_NOT_STARTED: -+ { -+ struct wined3d_buffer_heap_fenced_element *next = elem->next; -+ -+ wined3d_fence_destroy(elem->fence); -+ wined3d_buffer_heap_free(heap, elem->range); -+ -+ heap->fenced_head = elem->next; -+ HeapFree(GetProcessHeap(), 0, elem); -+ // TODO(acomminos): bother to null out fenced_tail? -+ -+ elem = next; -+ break; -+ } -+ default: -+ return WINED3D_OK; -+ } -+ } -+ -+ return WINED3D_OK; -+} -diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c -index 012561090f..9cf8f8efe5 100644 ---- a/dlls/wined3d/directx.c -+++ b/dlls/wined3d/directx.c -@@ -2711,6 +2711,9 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info) - /* GL_ARB_blend_func_extended */ - USE_GL_FUNC(glBindFragDataLocationIndexed) - USE_GL_FUNC(glGetFragDataIndex) -+ /* GL_ARB_buffer_storage */ -+ USE_GL_FUNC(glBufferStorage) -+ USE_GL_FUNC(glNamedBufferStorage) - /* GL_ARB_clear_buffer_object */ - USE_GL_FUNC(glClearBufferData) - USE_GL_FUNC(glClearBufferSubData) -diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h -index 7ac163459b..04957cb5b1 100644 ---- a/dlls/wined3d/wined3d_gl.h -+++ b/dlls/wined3d/wined3d_gl.h -@@ -44,6 +44,7 @@ enum wined3d_gl_extension - /* ARB */ - ARB_BASE_INSTANCE, - ARB_BLEND_FUNC_EXTENDED, -+ ARB_BUFFER_STORAGE, - ARB_CLEAR_BUFFER_OBJECT, - ARB_CLEAR_TEXTURE, - ARB_CLIP_CONTROL, -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 9b16a361e4..4d0555a76c 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -3465,6 +3465,12 @@ void state_init(struct wined3d_state *state, struct wined3d_fb_state *fb, - DWORD flags) DECLSPEC_HIDDEN; - void state_unbind_resources(struct wined3d_state *state) DECLSPEC_HIDDEN; - -+struct wined3d_map_range -+{ -+ GLintptr offset; -+ GLsizeiptr size; -+}; -+ - enum wined3d_cs_queue_id - { - WINED3D_CS_QUEUE_DEFAULT = 0, -@@ -3646,11 +3652,38 @@ enum wined3d_buffer_conversion_type - CONV_POSITIONT, - }; - --struct wined3d_map_range -+struct wined3d_buffer_heap_element; -+struct wined3d_buffer_heap_fenced_element; -+ -+// A heap that manages allocations with a single GL buffer. -+struct wined3d_buffer_heap - { -- UINT offset; -- UINT size; --}; -+ GLuint buffer_object; -+ void *map_ptr; -+ 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; -+ -+ // store in FIFO order? that way, we can minimize our amount of time -+ // waiting on fences? -+ // XXX(acomminos): are fences guaranteed to be triggered in a serial -+ // ordering? if so, we can early-terminate our polling -+ struct wined3d_buffer_heap_fenced_element *fenced_head; -+ struct wined3d_buffer_heap_fenced_element *fenced_tail; -+}; -+ -+HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr size, BOOL write_only, struct wined3d_buffer_heap **heap) DECLSPEC_HIDDEN; -+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. -+HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_map_range* out_range) 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; -+// 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_map_range range, struct wined3d_fence *fence) DECLSPEC_HIDDEN; -+// Moves a buffers with a signaled fence from the fenced list to the free list. -+// Must be executed on the CS thread. -+HRESULT wined3d_buffer_heap_cs_poll_fences(struct wined3d_buffer_heap *heap, struct wined3d_device *device) DECLSPEC_HIDDEN; - - struct wined3d_buffer - { --- -2.16.2 - |