diff options
Diffstat (limited to '0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch')
-rw-r--r-- | 0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch | 806 |
1 files changed, 0 insertions, 806 deletions
diff --git a/0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch b/0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch deleted file mode 100644 index ab14b215569b..000000000000 --- a/0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch +++ /dev/null @@ -1,806 +0,0 @@ -From 1f69076549bf2351eb6d8d885b35a46b4dc69813 Mon Sep 17 00:00:00 2001 -From: Andrew Comminos <andrew@comminos.com> -Date: Mon, 5 Mar 2018 15:38:35 -0800 -Subject: [PATCH 1/9] wined3d: Initial implementation of a persistent mapped - buffer allocator. - ---- - dlls/wined3d-csmt/Makefile.in | 1 + - dlls/wined3d/Makefile.in | 1 + - dlls/wined3d/buffer_heap.c | 508 +++++++++++++++++++++++++++++++++++++++++ - dlls/wined3d/cs.c | 9 + - dlls/wined3d/device.c | 52 +++++ - dlls/wined3d/directx.c | 3 + - dlls/wined3d/query.c | 2 +- - dlls/wined3d/wined3d_gl.h | 1 + - dlls/wined3d/wined3d_private.h | 68 +++++- - 9 files changed, 641 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 1d0458eb46..cb3a5484c6 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 b850ba6872..52ef8666fb 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..b133bd6893 ---- /dev/null -+++ b/dlls/wined3d/buffer_heap.c -@@ -0,0 +1,508 @@ -+/* -+ * 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 "wine/rbtree.h" -+#include "wined3d_private.h" -+ -+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; -+ struct wined3d_fence *fence; -+ -+ struct wined3d_buffer_heap_fenced_element *next; -+}; -+ -+static struct wined3d_buffer_heap_element* element_new(GLsizei offset, GLsizei size) -+{ -+ struct wined3d_buffer_heap_element* elem; -+ elem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct wined3d_buffer_heap_element)); -+ if (!elem) -+ return NULL; -+ elem->range.offset = offset; -+ elem->range.size = size; -+ 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 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) -+{ -+ int bin = element_bin(elem); -+ -+ elem->prev = NULL; -+ elem->next = heap->free_list.bins[bin].head; -+ if (heap->free_list.bins[bin].head) -+ heap->free_list.bins[bin].head->prev = elem; -+ heap->free_list.bins[bin].head = elem; -+ -+ if (!heap->free_list.bins[bin].tail) -+ heap->free_list.bins[bin].tail = elem; -+ -+ 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, its bin, and the coalesce list. -+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 == heap->free_list.bins[bin].head) -+ heap->free_list.bins[bin].head = elem->next; -+ -+ if (elem == heap->free_list.bins[bin].tail) -+ heap->free_list.bins[bin].tail = elem->prev; -+ -+ elem->prev = NULL; -+ elem->next = NULL; -+ -+ 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_bin_set bins, struct wined3d_fence* fence) -+{ -+ struct wined3d_buffer_heap_fenced_element* elem; -+ elem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct wined3d_buffer_heap_fenced_element)); -+ if (!elem) -+ return NULL; -+ elem->free_list = bins; -+ elem->fence = fence; -+ elem->next = NULL; -+ return elem; -+} -+ -+static int free_tree_compare(const void *key, const struct wine_rb_entry *entry) -+{ -+ 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. */ -+HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr size, GLsizeiptr alignment, 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_element *initial_elem; -+ -+ struct wined3d_buffer_heap *object; -+ -+ if ((alignment & (alignment - 1)) != 0) -+ { -+ return E_FAIL; -+ } -+ -+ 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; -+ -+ // TODO(acomminos): where should we be checking for errors here? -+ GL_EXTCALL(glGenBuffers(1, &object->buffer_object)); -+ -+ 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)))) -+ { -+ ERR("Couldn't map persistent buffer.\n"); -+ return -1; // FIXME(acomminos): proper error code, cleanup -+ } -+ context_bind_bo(context, buffer_target, 0); -+ -+ object->fenced_head = object->fenced_tail = NULL; -+ object->alignment = alignment; -+ InitializeCriticalSection(&object->temp_lock); -+ -+ initial_elem = element_new(0, size); -+ // Don't bother adding the initial allocation to the coalescing tree. -+ element_insert_free_bin(object, initial_elem); -+ -+ *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) -+{ -+ FIXME("Unimplemented, leaking buffer"); -+ return WINED3D_OK; -+} -+ -+HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_map_range *out_range) -+{ -+ int initial_bin; -+ int initial_size = size; -+ -+ EnterCriticalSection(&heap->temp_lock); -+ -+ // After alignment, reduce fragmentation by rounding to next power of two. -+ // If the alignment is a power of two (which it should be), this should be -+ // no problem. -+ size = 1 << bitwise_log2_ceil(size); -+ -+ // Align size values where possible. -+ if (heap->alignment && (size % heap->alignment != 0)) -+ size += heap->alignment - (size % heap->alignment); -+ -+ 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 = heap->free_list.bins[i].head; -+ if (elem) -+ { -+ 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; -+ -+ TRACE_(d3d_perf)("Allocated %d (requested %d) at %p from bin %d (initial %d)\n", size, initial_size, elem->range.offset, i, initial_bin); -+ -+ // 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) -+ { -+ 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); -+ } -+ -+ LeaveCriticalSection(&heap->temp_lock); -+ return WINED3D_OK; -+ } -+ } -+ -+ LeaveCriticalSection(&heap->temp_lock); -+ -+ FIXME_(d3d_perf)("Forcing coalesce, not enough free space in buffer heap.\n"); -+ int num_coalesced; -+ if (SUCCEEDED(wined3d_buffer_heap_deferred_coalesce(heap, &num_coalesced))) -+ { -+ if (num_coalesced > 0) -+ return wined3d_buffer_heap_alloc(heap, size, out_range); -+ } -+ -+ FIXME_(d3d_perf)("Coalescing did not create new blocks, failing.\n"); -+ -+ 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); -+ -+ if (!elem) -+ return E_OUTOFMEMORY; -+ -+ EnterCriticalSection(&heap->temp_lock); -+ -+ // Only insert the element into a free bin, coalescing will occur later. -+ element_insert_free_bin(heap, 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) -+{ -+ 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]; -+ -+ if (bin->tail) -+ { -+ bin->tail->next = elem; -+ elem->prev = bin->tail; -+ bin->tail = elem; -+ } -+ else -+ { -+ bin->head = elem; -+ bin->tail = elem; -+ } -+ -+ return WINED3D_OK; -+} -+ -+HRESULT wined3d_buffer_heap_cs_fence_issue(struct wined3d_buffer_heap *heap, struct wined3d_device *device) -+{ -+ struct wined3d_buffer_heap_fenced_element *fenced_elem; -+ struct wined3d_fence *fence; -+ HRESULT hr; -+ -+ if (heap->fenced_head) -+ { -+ // XXX(acomminos): double or triple buffer this? -+ wined3d_buffer_heap_cs_fence_wait(heap, device); -+ } -+ -+ if (FAILED(hr = wined3d_fence_create(device, &fence))) -+ { -+ ERR("Failed to create fence.\n"); -+ return hr; -+ } -+ -+ fenced_elem = fenced_element_new(heap->pending_fenced_bins, fence); -+ if (!fenced_elem) -+ return E_OUTOFMEMORY; -+ -+ TRACE_(d3d_perf)("Dispatching fenced buffer set.\n"); -+ memset(&heap->pending_fenced_bins, 0, sizeof(heap->pending_fenced_bins)); -+ -+ // 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 = fenced_elem; -+ heap->fenced_tail = fenced_elem; -+ } -+ else -+ { -+ heap->fenced_tail->next = fenced_elem; -+ heap->fenced_tail = fenced_elem; -+ } -+ -+ wined3d_fence_issue(fence, device); -+ return WINED3D_OK; -+} -+ -+HRESULT wined3d_buffer_heap_cs_fence_wait(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; -+ -+ res = wined3d_fence_wait(elem->fence, device); -+ switch (res) -+ { -+ case WINED3D_FENCE_OK: -+ case WINED3D_FENCE_NOT_STARTED: -+ { -+ TRACE_(d3d_perf)("Freed fence group.\n"); -+ -+ EnterCriticalSection(&heap->temp_lock); -+ for (int i = 0; i < WINED3D_BUFFER_HEAP_BINS; i++) -+ { -+ struct wined3d_buffer_heap_bin *elem_bin = &elem->free_list.bins[i]; -+ if (!elem_bin->tail) -+ continue; -+ -+ struct wined3d_buffer_heap_bin *heap_bin = &heap->free_list.bins[i]; -+ if (heap_bin->head) -+ { -+ // Insert to front. -+ elem_bin->tail->next = heap_bin->head; -+ heap_bin->head->prev = elem_bin->tail; -+ -+ elem_bin->head->prev = NULL; -+ heap_bin->head = elem_bin->head; -+ } -+ else -+ { -+ elem_bin->head->prev = NULL; -+ heap_bin->head = elem_bin->head; -+ elem_bin->tail->next = NULL; -+ heap_bin->tail = elem_bin->tail; -+ } -+ } -+ LeaveCriticalSection(&heap->temp_lock); -+ -+ wined3d_fence_destroy(elem->fence); -+ -+ heap->fenced_head = elem->next; -+ HeapFree(GetProcessHeap(), 0, elem); -+ // TODO(acomminos): bother to null out fenced_tail? -+ break; -+ } -+ default: -+ return WINED3D_OK; -+ } -+ -+ return WINED3D_OK; -+} -+ -+HRESULT wined3d_buffer_heap_deferred_coalesce(struct wined3d_buffer_heap *heap, int *coalesced_count) -+{ -+ struct wined3d_buffer_heap_element *elem = NULL; -+ struct wined3d_buffer_heap_element *next = NULL; -+ struct wine_rb_entry *entry; -+ struct wined3d_map_range coalesced_range; -+ -+ struct wine_rb_tree free_tree; -+ int num_coalesced = 0; -+ -+ wine_rb_init(&free_tree, free_tree_compare); -+ -+ EnterCriticalSection(&heap->temp_lock); -+ -+ // TODO(acomminos): on one hand, if there's a lot of elements in the list, -+ // it's highly fragmented. on the other, we can potentially waste a decent -+ // sum of time checking for uncoalesced bins. -+ for (int i = 0; i < WINED3D_BUFFER_HEAP_BINS; i++) -+ { -+ elem = heap->free_list.bins[i].head; -+ while (elem) -+ { -+ // Insert a sentry. FIXME(acomminos): can skip this with traversal. -+ if (wine_rb_put(&free_tree, &elem->range.offset, &elem->entry) == -1) -+ { -+ ERR("Failed to insert key %x in tree.\n", elem->range.offset); -+ elem = elem->next; -+ continue; -+ } -+ -+ coalesced_range = elem->range; -+ -+ // 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(entry, struct wined3d_buffer_heap_element, entry); -+ if (elem->range.offset + elem->range.size == right_elem->range.offset) -+ { -+ coalesced_range.size += right_elem->range.size; -+ -+ wine_rb_remove(&free_tree, entry); -+ element_remove_free(heap, right_elem); -+ HeapFree(GetProcessHeap(), 0, right_elem); -+ -+ num_coalesced++; -+ } -+ } -+ -+ // 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(entry, struct wined3d_buffer_heap_element, entry); -+ if (left_elem->range.offset + left_elem->range.size == coalesced_range.offset) -+ { -+ coalesced_range.offset = left_elem->range.offset; -+ coalesced_range.size += left_elem->range.size; -+ -+ wine_rb_remove(&free_tree, entry); -+ element_remove_free(heap, left_elem); -+ HeapFree(GetProcessHeap(), 0, left_elem); -+ -+ num_coalesced++; -+ } -+ } -+ -+ next = elem->next; -+ -+ if (elem->range.size != coalesced_range.size) -+ { -+ FIXME_(d3d_perf)("Coalesced range from (%p, %ld) to (%p, %ld)\n", elem->range.offset, elem->range.size, coalesced_range.offset, coalesced_range.size); -+ -+ wine_rb_remove(&free_tree, &elem->entry); -+ -+ // Move to the correct free bin. -+ element_remove_free(heap, elem); -+ elem->range = coalesced_range; -+ element_insert_free_bin(heap, elem); -+ -+ wine_rb_put(&free_tree, &elem->range.offset, &elem->entry); -+ } -+ -+ elem = next; -+ } -+ } -+ -+ LeaveCriticalSection(&heap->temp_lock); -+ -+ FIXME_(d3d_perf)("Performed %d coalesces.\n", num_coalesced); -+ if (coalesced_count) -+ *coalesced_count = num_coalesced; -+ -+ return WINED3D_OK; -+} -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index 3a7c95ddd8..50a4d041cd 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -472,6 +472,15 @@ static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data) - } - - InterlockedDecrement(&cs->pending_presents); -+ -+ // FIXME(acomminos): is this the right place to put double-buffered frame -+ // timing based logic? -+ // FIXME(acomminos): this conditional sucks, replace with fancier feature check -+ if (cs->device->wo_buffer_heap && cs->device->cb_buffer_heap) -+ { -+ wined3d_buffer_heap_cs_fence_issue(cs->device->wo_buffer_heap, cs->device); -+ wined3d_buffer_heap_cs_fence_issue(cs->device->cb_buffer_heap, cs->device); -+ } - } - - void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain, -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index e2b27e0cf4..785841a062 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -833,6 +833,53 @@ static void destroy_default_samplers(struct wined3d_device *device, struct wined - device->null_sampler = NULL; - } - -+/* Context activation is done by the caller. */ -+static void create_buffer_heap(struct wined3d_device *device, struct wined3d_context *context) -+{ -+ const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; -+ // TODO(acomminos): kill this magic number. perhaps base on vram. -+ GLsizeiptr geo_heap_size = 512 * 1024 * 1024; -+ // We choose a constant buffer size of 128MB, the same as NVIDIA claims to -+ // use in their Direct3D driver for discarded constant buffers. -+ GLsizeiptr cb_heap_size = 128 * 1024 * 1024; -+ GLint ub_alignment; -+ HRESULT hr; -+ -+ if (gl_info->supported[ARB_BUFFER_STORAGE]) -+ { -+ gl_info->gl_ops.gl.p_glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &ub_alignment); -+ -+ // Align constant buffer heap size, in case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT isn't a power of two (for some reason). -+ cb_heap_size -= cb_heap_size % ub_alignment; -+ -+ if (FAILED(hr = wined3d_buffer_heap_create(context, geo_heap_size, 0, TRUE, &device->wo_buffer_heap))) -+ { -+ ERR("Failed to create write-only persistent buffer heap, hr %#x.\n", hr); -+ } -+ -+ if (FAILED(hr = wined3d_buffer_heap_create(context, cb_heap_size, ub_alignment, TRUE, &device->cb_buffer_heap))) -+ { -+ ERR("Failed to create persistent buffer heap for constant buffers, hr %#x.\n", hr); -+ } -+ -+ FIXME("Initialized PBA (geo_heap_size: %ld, cb_heap_size: %ld, ub_align: %d)\n", geo_heap_size, cb_heap_size, ub_alignment); -+ } -+ else -+ { -+ FIXME("Not using PBA, ARB_buffer_storage unsupported.\n"); -+ } -+} -+ -+/* Context activation is done by the caller. */ -+static void destroy_buffer_heap(struct wined3d_device *device, struct wined3d_context *context) -+{ -+ if (device->wo_buffer_heap) -+ wined3d_buffer_heap_destroy(device->wo_buffer_heap, context); -+ -+ if (device->cb_buffer_heap) -+ wined3d_buffer_heap_destroy(device->cb_buffer_heap, context); -+} -+ - static LONG fullscreen_style(LONG style) - { - /* Make sure the window is managed, otherwise we won't get keyboard input. */ -@@ -997,6 +1044,8 @@ static void wined3d_device_delete_opengl_contexts_cs(void *object) - device->shader_backend->shader_free_private(device); - destroy_dummy_textures(device, context); - destroy_default_samplers(device, context); -+ destroy_buffer_heap(device, context); -+ - context_release(context); - - while (device->context_count) -@@ -1045,6 +1094,9 @@ static void wined3d_device_create_primary_opengl_context_cs(void *object) - context = context_acquire(device, target, 0); - create_dummy_textures(device, context); - create_default_samplers(device, context); -+ -+ create_buffer_heap(device, context); -+ - context_release(context); - } - -diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c -index 8720fc7ad6..46c6a59536 100644 ---- a/dlls/wined3d/directx.c -+++ b/dlls/wined3d/directx.c -@@ -111,6 +111,7 @@ static const struct wined3d_extension_map gl_extension_map[] = - /* ARB */ - {"GL_ARB_base_instance", ARB_BASE_INSTANCE }, - {"GL_ARB_blend_func_extended", ARB_BLEND_FUNC_EXTENDED }, -+ {"GL_ARB_buffer_storage", ARB_BUFFER_STORAGE }, - {"GL_ARB_clear_buffer_object", ARB_CLEAR_BUFFER_OBJECT }, - {"GL_ARB_clear_texture", ARB_CLEAR_TEXTURE }, - {"GL_ARB_clip_control", ARB_CLIP_CONTROL }, -@@ -2714,6 +2715,8 @@ 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) - /* GL_ARB_clear_buffer_object */ - USE_GL_FUNC(glClearBufferData) - USE_GL_FUNC(glClearBufferSubData) -diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c -index 5ea79b6e4a..f3ca1630e5 100644 ---- a/dlls/wined3d/query.c -+++ b/dlls/wined3d/query.c -@@ -88,7 +88,7 @@ static BOOL wined3d_fence_supported(const struct wined3d_gl_info *gl_info) - return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE]; - } - --static enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence, -+enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence, - const struct wined3d_device *device, DWORD flags) - { - const struct wined3d_gl_info *gl_info; -diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h -index 87283c850e..7626864ef2 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 8aa61d811f..3d535f4e17 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -1712,6 +1712,9 @@ void wined3d_fence_destroy(struct wined3d_fence *fence) DECLSPEC_HIDDEN; - void wined3d_fence_issue(struct wined3d_fence *fence, const struct wined3d_device *device) DECLSPEC_HIDDEN; - enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence, - const struct wined3d_device *device) DECLSPEC_HIDDEN; -+// XXX(acomminos): really expose this? -+enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence, -+ const struct wined3d_device *device, DWORD flags) DECLSPEC_HIDDEN; - - /* Direct3D terminology with little modifications. We do not have an issued - * state because only the driver knows about it, but we have a created state -@@ -2993,6 +2996,10 @@ struct wined3d_device - /* Context management */ - struct wined3d_context **contexts; - UINT context_count; -+ -+ /* Dynamic buffer heap */ -+ struct wined3d_buffer_heap *wo_buffer_heap; -+ struct wined3d_buffer_heap *cb_buffer_heap; - }; - - void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb, -@@ -3513,6 +3520,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, -@@ -3692,12 +3705,61 @@ enum wined3d_buffer_conversion_type - CONV_POSITIONT, - }; - --struct wined3d_map_range -+struct wined3d_buffer_heap_element; -+struct wined3d_buffer_heap_fenced_element; -+ -+// Number of power-of-two buckets to populate. -+#define WINED3D_BUFFER_HEAP_BINS 32 -+ -+struct wined3d_buffer_heap_bin - { -- UINT offset; -- UINT size; -+ struct wined3d_buffer_heap_element *head; -+ struct wined3d_buffer_heap_element *tail; -+}; -+ -+struct wined3d_buffer_heap_bin_set -+{ -+ struct wined3d_buffer_heap_bin bins[WINED3D_BUFFER_HEAP_BINS]; - }; - -+// A heap that manages allocations with a single GL buffer. -+struct wined3d_buffer_heap -+{ -+ GLuint buffer_object; -+ void *map_ptr; -+ GLsizeiptr alignment; -+ CRITICAL_SECTION temp_lock; // Temporary lock while we implement the fenced free list. -+ -+ struct wined3d_buffer_heap_bin_set free_list; -+ -+ // Elements that need to be fenced, but haven't reached the required size. -+ struct wined3d_buffer_heap_bin_set pending_fenced_bins; -+ -+ // List of sets of buffers behind a common fence, in FIFO order. -+ 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, GLsizeiptr alignment, 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. -+// 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; -+// 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_device *device, struct wined3d_map_range range) 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. -+HRESULT wined3d_buffer_heap_cs_fence_issue(struct wined3d_buffer_heap *heap, struct wined3d_device *device) DECLSPEC_HIDDEN; -+// Waits on the next issued fence in FIFO order. Frees the fenced buffers after -+// the fence has been triggered. -+HRESULT wined3d_buffer_heap_cs_fence_wait(struct wined3d_buffer_heap *heap, struct wined3d_device *device) DECLSPEC_HIDDEN; -+// Performs deferred coalescing of buffers. To be called under memory pressure. -+// Outputs the number of coalesced regions in `num_coalesced`. -+HRESULT wined3d_buffer_heap_deferred_coalesce(struct wined3d_buffer_heap *heap, int *num_coalesced) DECLSPEC_HIDDEN; -+ - struct wined3d_buffer - { - struct wined3d_resource resource; --- -2.16.2 - |