diff options
author | Stefan Schmidt | 2018-03-07 18:20:55 +0100 |
---|---|---|
committer | Stefan Schmidt | 2018-03-07 18:20:55 +0100 |
commit | 9cc0c1987f64a4f538e747058b53e37f4548d8f4 (patch) | |
tree | 2bac1b3e58a4e2857e5cc32d30cbe1a3423b94d6 | |
parent | 8f3ed8701334e289a8a98b275825044cecab9277 (diff) | |
download | aur-9cc0c1987f64a4f538e747058b53e37f4548d8f4.tar.gz |
Updated to wine-staging 3.3 and commit b33e274f894de751f9abe2e09aec5bc9d1e6b992
16 files changed, 1424 insertions, 2896 deletions
@@ -1,8 +1,9 @@ pkgbase = wine-staging-pba pkgdesc = A compatibility layer for running Windows programs - Staging branch - pkgver = 2.21 - pkgrel = 2 + pkgver = 3.3 + pkgrel = 1 url = http://www.wine-staging.com + install = wine.install arch = x86_64 license = LGPL makedepends = autoconf @@ -54,37 +55,41 @@ pkgbase = wine-staging-pba makedepends = lib32-gtk3 makedepends = gst-plugins-base-libs makedepends = lib32-gst-plugins-base-libs + makedepends = vulkan-icd-loader + makedepends = lib32-vulkan-icd-loader + makedepends = sdl2 + makedepends = lib32-sdl2 makedepends = samba makedepends = opencl-headers - makedepends = attr - makedepends = lib32-attr - makedepends = fontconfig - makedepends = lib32-fontconfig - makedepends = lcms2 - makedepends = lib32-lcms2 - makedepends = libxml2 - makedepends = lib32-libxml2 - makedepends = libxcursor - makedepends = lib32-libxcursor - makedepends = libxrandr - makedepends = lib32-libxrandr - makedepends = libxdamage - makedepends = lib32-libxdamage - makedepends = libxi - makedepends = lib32-libxi - makedepends = gettext - makedepends = lib32-gettext - makedepends = freetype2 - makedepends = lib32-freetype2 - makedepends = glu - makedepends = lib32-glu - makedepends = libsm - makedepends = lib32-libsm - makedepends = gcc-libs - makedepends = lib32-gcc-libs - makedepends = libpcap - makedepends = lib32-libpcap - makedepends = desktop-file-utils + depends = attr + depends = lib32-attr + depends = fontconfig + depends = lib32-fontconfig + depends = lcms2 + depends = lib32-lcms2 + depends = libxml2 + depends = lib32-libxml2 + depends = libxcursor + depends = lib32-libxcursor + depends = libxrandr + depends = lib32-libxrandr + depends = libxdamage + depends = lib32-libxdamage + depends = libxi + depends = lib32-libxi + depends = gettext + depends = lib32-gettext + depends = freetype2 + depends = lib32-freetype2 + depends = glu + depends = lib32-glu + depends = libsm + depends = lib32-libsm + depends = gcc-libs + depends = lib32-gcc-libs + depends = libpcap + depends = lib32-libpcap + depends = desktop-file-utils optdepends = giflib optdepends = lib32-giflib optdepends = libpng @@ -125,66 +130,41 @@ pkgbase = wine-staging-pba optdepends = lib32-gst-plugins-base-libs optdepends = vulkan-icd-loader optdepends = lib32-vulkan-icd-loader + optdepends = sdl2 + optdepends = lib32-sdl2 optdepends = cups optdepends = samba optdepends = dosbox - provides = wine=2.21 - provides = wine-wow64=2.21 + provides = wine=3.3 + provides = wine-wow64=3.3 conflicts = wine conflicts = wine-wow64 conflicts = wine-staging options = staticlibs - source = https://github.com/wine-compholio/wine-patched/archive/staging-2.21.tar.gz + source = https://dl.winehq.org/wine/source/3.x/wine-3.3.tar.xz + source = https://dl.winehq.org/wine/source/3.x/wine-3.3.tar.xz.sign + source = wine-staging-v3.3.tar.gz::https://github.com/wine-staging/wine-staging/archive/v3.3.tar.gz source = harmony-fix.diff source = 30-win32-aliases.conf - source = 0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch - source = 0002-wined3d-Allocate-global-write-only-persistent-buffer.patch - source = 0003-wined3d-Add-support-for-persistently-mapped-wined3d_.patch - source = 0004-wined3d-Implement-aligned-persistent-heaps-for-persi.patch - source = 0005-wined3d-Experimental-buffer-heap-fence-batching-uppe.patch - source = 0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch - source = 0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch - source = 0008-wined3d-Implement-lazy-free-using-a-deferred-free-li.patch - sha512sums = 4e3fe2eb81360bfa095194ab5b9647636cbeac0dc3955e6a3ee26062f650c66a4bd2353a1cd8063f9b7c65a6bcc1f892cc7c1d0f00c3c8525a124ec2109d1e86 + source = wine-binfmt.conf + source = 0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch + source = 0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch + source = 0003-wined3d-Use-ARB_multi_bind-to-speed-up-UBO-updates.patch + source = 0004-wined3d-Use-GL_CLIENT_STORAGE_BIT-for-persistent-map.patch + source = 0005-wined3d-Experimental-support-for-persistent-buffer-t.patch + validpgpkeys = 5AC1A08B03BD7A313E0A955AF5E6E9EEB9461DD7 + validpgpkeys = DA23579A74D4AD9AF9D3F945CEFAC8EAAF17519D + sha512sums = c9e4c75e94d745837208bf877b19c4e4e46df1e78082d21e716f52c9f9d93eaabbec8bf34783cda68e4275f53e37929b81ac128e5b8a13c1e5035223b2621d6a + sha512sums = SKIP + sha512sums = 02d48a9c403b93d01ca37b74af5dc81f86e49c72d67f194c71ccebd4556fa72c473728a1b1f9d5325c6f85f4e41bb7072a1183a2d81cafa8888e00dc53d12166 sha512sums = b86edf07bfc560f403fdfd5a71f97930ee2a4c3f76c92cc1a0dbb2e107be9db3bed3a727a0430d8a049583c63dd11f5d4567fb7aa69b193997c6da241acc4f2e sha512sums = 6e54ece7ec7022b3c9d94ad64bdf1017338da16c618966e8baf398e6f18f80f7b0576edf1d1da47ed77b96d577e4cbb2bb0156b0b11c183a0accf22654b0a2bb - sha512sums = b9141fbe8f5189eb46c83b178497f9ee6d1f2daec3009877557ba28e5f2ce6d818cfef5b0eba15c1e9e4c50dd5950486f8091793d704ec532f82155056725e71 - sha512sums = 8e112e25392fb2bd035c4b8792e43ad86bf81b1c24ff429ff8943a2c02ee761fc25446791475e4115e6b03f50cdb4cf6a8f128cc770c3941b59ee1dfbe79137b - sha512sums = 7335797924f1c4403a438ccfe36f8a650ddf8271d33ca962e270cf34762170038017cd53cad35f1ad61128f2c496edb68791783259df33cb997a73959136bdc0 - sha512sums = 52ebb56c6adfbef526d2db19618f9155084dacd7600d166f04ba5423c63a4294294589d675c391e577330f1b68755bb5d3b6a2cd3006902269cb73140973dba3 - sha512sums = d326b8da8fb02462bac178a23e18f5468de62780717c24eadb453201b2b6b6439d2be7dda38e40f24fdc570dd5bc54102e7bf05868c53b17b27f6b9a06fccdb0 - sha512sums = 04b41d4198138dbfe1399e7ed1e406fb265472d08a3e4de3c5c8584574b167613c598d7fa397c6944b809a96f699a4447694291296fa01a8e07b8ea96026ed2f - sha512sums = 9f90b7adc0ed87daac0f453caf2fff8b338061d96a9cd890f305704f9b22581232c6a207eb9eb1670c69b083caa780a6e44280df47c95b4e6e8e73f046f7c8a5 - sha512sums = 4b94c8374ecb459c35df9950b8cc4bcac5d4ccb4102e83ea9092de3e387e6f998af2968232816a94b4f21317dca6210a90ab4657f7f940072df7b050a84ad735 + sha512sums = bdde7ae015d8a98ba55e84b86dc05aca1d4f8de85be7e4bd6187054bfe4ac83b5a20538945b63fb073caab78022141e9545685e4e3698c97ff173cf30859e285 + sha512sums = b68f09aa0688ba52e40dd9a22c99699d28b3e1a7028d1c39e5705cad345e17535d9b1066babf6881668be23ab43ca7ed0203aa5a287ed343ec4383b58358f6ab + sha512sums = e7a1ab3ea00dc257de3dfdeab61df4dcd1ba3b448d3d323a5c7fed7da0b9a0ddb0b00eb6bc3f72b1fc1b10c61e181e8fe4f413a64b59d740371b2852686ce0c8 + sha512sums = 643b7575bd3e5a080c98e4435747942d39a072a662d26aefacec512263889dfda1fa154b77c6323d0cb69b5cab357258906cf17ad5013af09eda3d255706b5fe + sha512sums = 095ad54ea35f2e8317ab42a24fb92cbc214c6c3b53be165a6ddec9ef31f97b989befac4a3b51a1fcfbf5ead11b0ab3ca57ac34ad41621e81fdaa96aed17815cb + sha512sums = a58ae6201bfab1ddbda4d789054ce384434d4eb5e3d5845e995caa81b41c2814bb625216ce09c0e4bae92e3e6a45771d28ee4ef09b7c587cd56ec17d577a37a8 pkgname = wine-staging-pba - depends = attr - depends = lib32-attr - depends = fontconfig - depends = lib32-fontconfig - depends = lcms2 - depends = lib32-lcms2 - depends = libxml2 - depends = lib32-libxml2 - depends = libxcursor - depends = lib32-libxcursor - depends = libxrandr - depends = lib32-libxrandr - depends = libxdamage - depends = lib32-libxdamage - depends = libxi - depends = lib32-libxi - depends = gettext - depends = lib32-gettext - depends = freetype2 - depends = lib32-freetype2 - depends = glu - depends = lib32-glu - depends = libsm - depends = lib32-libsm - depends = gcc-libs - depends = lib32-gcc-libs - depends = libpcap - depends = lib32-libpcap - depends = desktop-file-utils 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 - diff --git a/0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch b/0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch new file mode 100644 index 000000000000..365dd861d14f --- /dev/null +++ b/0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch @@ -0,0 +1,806 @@ +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/5] 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 + diff --git a/0003-wined3d-Add-support-for-persistently-mapped-wined3d_.patch b/0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch index 5a3a499ab2a0..cb910a25df4b 100644 --- a/0003-wined3d-Add-support-for-persistently-mapped-wined3d_.patch +++ b/0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch @@ -1,24 +1,22 @@ -From 3e72163af5712be1a51957effa183edc7a9fb2a6 Mon Sep 17 00:00:00 2001 +From 6d2e04a5aeab1e3dc238b548a3f90986da4b5e1e Mon Sep 17 00:00:00 2001 From: Andrew Comminos <andrew@comminos.com> -Date: Fri, 23 Feb 2018 17:41:43 -0800 -Subject: [PATCH 3/8] wined3d: Add support for persistently mapped - wined3d_buffer resources. +Date: Mon, 5 Mar 2018 15:39:11 -0800 +Subject: [PATCH 2/5] wined3d: Add support for backing dynamic wined3d_buffer + objects by a persistent map. --- - dlls/wined3d/buffer.c | 211 ++++++++++++++++++++++++++++++++++++++++- - dlls/wined3d/buffer_heap.c | 8 +- - dlls/wined3d/cs.c | 62 +++++++++++- - dlls/wined3d/drawprim.c | 7 +- - dlls/wined3d/query.c | 2 +- - dlls/wined3d/resource.c | 20 +++- - dlls/wined3d/state.c | 6 +- + dlls/wined3d/buffer.c | 220 ++++++++++++++++++++++++++++++++++++++++- + dlls/wined3d/context.c | 6 +- + dlls/wined3d/cs.c | 60 ++++++++++- + dlls/wined3d/resource.c | 18 +++- + dlls/wined3d/state.c | 17 +++- dlls/wined3d/texture.c | 13 +++ dlls/wined3d/utils.c | 1 + - dlls/wined3d/wined3d_private.h | 13 +++ - 10 files changed, 326 insertions(+), 17 deletions(-) + dlls/wined3d/wined3d_private.h | 11 +++ + 8 files changed, 336 insertions(+), 10 deletions(-) diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c -index d61321e1a5..ccb090c907 100644 +index cae7ef8788..ad057b7fba 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -28,12 +28,14 @@ @@ -36,7 +34,7 @@ index d61321e1a5..ccb090c907 100644 #define VB_MAXDECLCHANGES 100 /* After that number of decl changes we stop converting */ #define VB_RESETDECLCHANGE 1000 /* Reset the decl changecount after that number of draws */ -@@ -269,6 +271,50 @@ fail: +@@ -269,6 +271,52 @@ fail: return FALSE; } @@ -48,14 +46,16 @@ index d61321e1a5..ccb090c907 100644 + struct wined3d_map_range map_range; + HRESULT hr; + -+ if (buffer->resource.usage & WINED3DUSAGE_WRITEONLY) ++ if (buffer->bind_flags & WINED3D_BIND_CONSTANT_BUFFER) + { -+ heap = device->wo_buffer_heap; ++ // Use a heap aligned to constant buffer offset requirements. ++ heap = device->cb_buffer_heap; + } + else + { -+ FIXME("Using write-only heap for a persistent buffer without WINED3DUSAGE_WRITEONLY.\n"); -+ heap = device->rw_buffer_heap; ++ if (!(buffer->resource.usage & WINED3DUSAGE_WRITEONLY)) ++ FIXME("Using a write-only persistent buffer for %p without WINED3DUSAGE_WRITEONLY.\n", buffer); ++ heap = device->wo_buffer_heap; + } + + buffer->buffer_heap = heap; @@ -87,7 +87,7 @@ index d61321e1a5..ccb090c907 100644 static BOOL buffer_process_converted_attribute(struct wined3d_buffer *buffer, const enum wined3d_buffer_conversion_type conversion_type, const struct wined3d_stream_info_element *attrib, DWORD *stride_this_run) -@@ -630,6 +676,16 @@ static BOOL wined3d_buffer_prepare_location(struct wined3d_buffer *buffer, +@@ -631,6 +679,16 @@ static BOOL wined3d_buffer_prepare_location(struct wined3d_buffer *buffer, return FALSE; } return buffer_create_buffer_object(buffer, context); @@ -104,7 +104,7 @@ index d61321e1a5..ccb090c907 100644 default: ERR("Invalid location %s.\n", wined3d_debug_location(location)); -@@ -688,16 +744,32 @@ BOOL wined3d_buffer_load_location(struct wined3d_buffer *buffer, +@@ -689,16 +747,32 @@ BOOL wined3d_buffer_load_location(struct wined3d_buffer *buffer, buffer_conversion_upload(buffer, context); break; @@ -138,8 +138,11 @@ index d61321e1a5..ccb090c907 100644 return TRUE; } -@@ -721,6 +793,13 @@ DWORD wined3d_buffer_get_memory(struct wined3d_buffer *buffer, +@@ -720,12 +794,25 @@ DWORD wined3d_buffer_get_memory(struct wined3d_buffer *buffer, + { + data->buffer_object = buffer->buffer_object; data->addr = NULL; ++ data->length = buffer->resource.size; return WINED3D_LOCATION_BUFFER; } + if (locations & WINED3D_LOCATION_PERSISTENT_MAP) @@ -147,12 +150,21 @@ index d61321e1a5..ccb090c907 100644 + // 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; ++ // 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; + return WINED3D_LOCATION_PERSISTENT_MAP; + } if (locations & WINED3D_LOCATION_SYSMEM) { data->buffer_object = 0; -@@ -760,6 +839,8 @@ static void buffer_unload(struct wined3d_resource *resource) + data->addr = buffer->resource.heap_memory; ++ data->length = buffer->resource.size; + return WINED3D_LOCATION_SYSMEM; + } + +@@ -761,6 +848,8 @@ static void buffer_unload(struct wined3d_resource *resource) buffer->flags &= ~WINED3D_BUFFER_HASDESC; } @@ -161,30 +173,33 @@ index d61321e1a5..ccb090c907 100644 resource_unload(resource); } -@@ -783,6 +864,8 @@ static void wined3d_buffer_destroy_object(void *object) - HeapFree(GetProcessHeap(), 0, buffer->conversion_map); +@@ -784,6 +873,8 @@ static void wined3d_buffer_destroy_object(void *object) + heap_free(buffer->conversion_map); } + buffer_free_persistent_map(buffer); + - HeapFree(GetProcessHeap(), 0, buffer->maps); - HeapFree(GetProcessHeap(), 0, buffer); + heap_free(buffer->maps); + heap_free(buffer); } -@@ -899,6 +982,13 @@ void wined3d_buffer_load(struct wined3d_buffer *buffer, struct wined3d_context * +@@ -900,6 +991,16 @@ void wined3d_buffer_load(struct wined3d_buffer *buffer, struct wined3d_context * buffer_mark_used(buffer); + if (buffer->flags & WINED3D_BUFFER_PERSISTENT) + { -+ if (!wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_PERSISTENT_MAP)) -+ ERR("Failed to preload persistent mapping.\n"); -+ return; ++ if (wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_PERSISTENT_MAP)) ++ return; ++ ++ ERR("Failed to preload persistent mapping for %p, falling back to BO.\n", buffer); ++ buffer->flags |= WINED3D_BUFFER_USE_BO; ++ buffer->flags &= ~WINED3D_BUFFER_PERSISTENT; + } + /* TODO: Make converting independent from VBOs */ if (!(buffer->flags & WINED3D_BUFFER_USE_BO)) { -@@ -1009,6 +1099,25 @@ static HRESULT wined3d_buffer_map(struct wined3d_buffer *buffer, UINT offset, UI +@@ -1010,6 +1111,25 @@ static HRESULT wined3d_buffer_map(struct wined3d_buffer *buffer, UINT offset, UI count = ++buffer->resource.map_count; @@ -210,7 +225,7 @@ index d61321e1a5..ccb090c907 100644 if (buffer->buffer_object) { unsigned int dirty_offset = offset, dirty_size = size; -@@ -1151,6 +1260,12 @@ static void wined3d_buffer_unmap(struct wined3d_buffer *buffer) +@@ -1152,6 +1272,12 @@ static void wined3d_buffer_unmap(struct wined3d_buffer *buffer) return; } @@ -223,7 +238,7 @@ index d61321e1a5..ccb090c907 100644 if (buffer->map_ptr) { struct wined3d_device *device = buffer->resource.device; -@@ -1273,6 +1388,64 @@ static void buffer_resource_preload(struct wined3d_resource *resource) +@@ -1256,6 +1382,64 @@ static void buffer_resource_preload(struct wined3d_resource *resource) static HRESULT buffer_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) @@ -248,7 +263,7 @@ index d61321e1a5..ccb090c907 100644 + struct wined3d_map_range map_range; + if (FAILED(hr = wined3d_buffer_heap_alloc(buffer->buffer_heap, resource->size, &map_range))) + { -+ FIXME("Failed to allocate new buffer, falling back to sync path.\n"); ++ 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; @@ -288,7 +303,7 @@ index d61321e1a5..ccb090c907 100644 { struct wined3d_buffer *buffer = buffer_from_resource(resource); UINT offset, size; -@@ -1316,6 +1489,18 @@ static HRESULT buffer_resource_sub_resource_map_info(struct wined3d_resource *re +@@ -1299,6 +1483,18 @@ static HRESULT buffer_resource_sub_resource_map_info(struct wined3d_resource *re } static HRESULT buffer_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) @@ -307,26 +322,23 @@ index d61321e1a5..ccb090c907 100644 { if (sub_resource_idx) { -@@ -1334,8 +1519,10 @@ static const struct wined3d_resource_ops buffer_resource_ops = - buffer_resource_preload, +@@ -1318,7 +1514,9 @@ static const struct wined3d_resource_ops buffer_resource_ops = buffer_unload, buffer_resource_sub_resource_map, -+ buffer_resource_sub_resource_map_cs, buffer_resource_sub_resource_map_info, ++ buffer_resource_sub_resource_map_cs, buffer_resource_sub_resource_unmap, + buffer_resource_sub_resource_unmap_cs, }; static GLenum buffer_type_hint_from_bind_flags(const struct wined3d_gl_info *gl_info, -@@ -1411,12 +1598,32 @@ static HRESULT buffer_init(struct wined3d_buffer *buffer, struct wined3d_device +@@ -1394,12 +1592,30 @@ static HRESULT buffer_init(struct wined3d_buffer *buffer, struct wined3d_device buffer->flags |= WINED3D_BUFFER_PIN_SYSMEM; } -+ // FIXME(acomminos) + if (buffer->resource.usage & WINED3DUSAGE_DYNAMIC) + { -+ // FIXME(acomminos): why is this returning false? -+ if (FALSE && !gl_info->supported[ARB_BUFFER_STORAGE]) ++ if (!gl_info->supported[ARB_BUFFER_STORAGE]) + { + WARN_(d3d_perf)("Not creating a persistent mapping for a dynamic buffer because ARB_buffer_storage is unsupported.\n"); + } @@ -352,56 +364,36 @@ index d61321e1a5..ccb090c907 100644 { TRACE("Not creating a BO because GL_ARB_vertex_buffer is not supported.\n"); } -diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c -index 900e2d24bb..f24fddffb4 100644 ---- a/dlls/wined3d/buffer_heap.c -+++ b/dlls/wined3d/buffer_heap.c -@@ -114,14 +114,11 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s - { - access_flags |= GL_MAP_READ_BIT; - } -- storage_flags = access_flags; // XXX(acomminos): will we need dynamic storage? -+ storage_flags = access_flags; - - // 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? -@@ -129,7 +126,6 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s - - if (!(object->map_ptr = GL_EXTCALL(glMapBufferRange(buffer_target, 0, size, access_flags)))) +diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c +index 0e2e68b4b0..eae2c3a79d 100644 +--- a/dlls/wined3d/context.c ++++ b/dlls/wined3d/context.c +@@ -5005,7 +5005,11 @@ void draw_primitive(struct wined3d_device *device, const struct wined3d_state *s + if (parameters->indexed) { -- // TODO(acomminos): include error message - ERR("Couldn't map persistent buffer.\n"); - return -1; // FIXME(acomminos): proper error code, cleanup - } -@@ -147,7 +143,7 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s - /* Context activation is done by the caller. */ - HRESULT wined3d_buffer_heap_destroy(struct wined3d_buffer_heap *heap, struct wined3d_context *context) - { -- // TODO -+ FIXME("Unimplemented, leaking buffer"); - return WINED3D_OK; - } - + struct wined3d_buffer *index_buffer = state->index_buffer; +- if (!index_buffer->buffer_object || !stream_info->all_vbo) ++ if (index_buffer->locations & WINED3D_LOCATION_PERSISTENT_MAP) ++ { ++ idx_data = index_buffer->cs_persistent_map.offset; ++ } ++ else if (!index_buffer->buffer_object || !stream_info->all_vbo) + { + idx_data = index_buffer->resource.heap_memory; + } diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index 7e72b30933..edcf521b72 100644 +index 50a4d041cd..e61b8dedbb 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -73,6 +73,7 @@ enum wined3d_cs_op + WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW, WINED3D_CS_OP_COPY_UAV_COUNTER, - WINED3D_CS_OP_COPY_SUB_RESOURCE, - WINED3D_CS_OP_GENERATE_MIPS, + WINED3D_CS_OP_GENERATE_MIPMAPS, + WINED3D_CS_OP_DISCARD_BUFFER, WINED3D_CS_OP_STOP, }; -@@ -444,6 +445,13 @@ struct wined3d_cs_generate_mips +@@ -439,6 +440,13 @@ struct wined3d_cs_generate_mipmaps struct wined3d_shader_resource_view *view; }; @@ -415,7 +407,7 @@ index 7e72b30933..edcf521b72 100644 struct wined3d_cs_stop { enum wined3d_cs_op opcode; -@@ -1986,7 +1994,7 @@ static void wined3d_cs_exec_map(struct wined3d_cs *cs, const void *data) +@@ -2002,7 +2010,7 @@ static void wined3d_cs_exec_map(struct wined3d_cs *cs, const void *data) const struct wined3d_cs_map *op = data; struct wined3d_resource *resource = op->resource; @@ -424,7 +416,7 @@ index 7e72b30933..edcf521b72 100644 op->sub_resource_idx, op->map_desc, op->box, op->flags); } -@@ -2020,7 +2028,7 @@ static void wined3d_cs_exec_unmap(struct wined3d_cs *cs, const void *data) +@@ -2036,7 +2044,7 @@ static void wined3d_cs_exec_unmap(struct wined3d_cs *cs, const void *data) const struct wined3d_cs_unmap *op = data; struct wined3d_resource *resource = op->resource; @@ -433,7 +425,7 @@ index 7e72b30933..edcf521b72 100644 } HRESULT wined3d_cs_unmap(struct wined3d_cs *cs, struct wined3d_resource *resource, unsigned int sub_resource_idx) -@@ -2630,6 +2638,55 @@ void wined3d_cs_emit_generate_mips(struct wined3d_cs *cs, struct wined3d_shader_ +@@ -2455,6 +2463,53 @@ void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shad cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); } @@ -442,32 +434,30 @@ index 7e72b30933..edcf521b72 100644 + const struct wined3d_cs_discard_buffer *op = data; + struct wined3d_buffer *buffer = op->buffer; + HRESULT hr; -+ struct wined3d_fence *fence; -+ -+ // Poll for discarded buffers whose fenced have been triggered here to avoid -+ // excessive VRAM consumption. -+ wined3d_buffer_heap_cs_poll_fences(buffer->buffer_heap, cs->device); + + // TODO(acomminos): should call into buffer.c here instead. -+ // XXX(acomminos): should we always create a new fence here? -+ if (!FAILED(hr = wined3d_fence_create(cs->device, &fence))) -+ { -+ // TODO(acomminos): make more informed fences based on prior info. for now, -+ // we do this because allocating and deleting fences repeatedly is brutal -+ // for performance. look into why. -+ wined3d_fence_issue(fence, cs->device); -+ -+ wined3d_buffer_heap_free_fenced(buffer->buffer_heap, buffer->cs_persistent_map, fence); -+ } -+ else ++ if (FAILED(hr = wined3d_buffer_heap_free_fenced(buffer->buffer_heap, cs->device, buffer->cs_persistent_map))) + { -+ ERR("Failed to create fence for discarded buffer %p, hr %x\n. Freeing anyway.", buffer, hr); ++ ERR("Failed to do a fenced free on discarded buffer %p, hr %x\n. Freeing anyway.", buffer, hr); + wined3d_buffer_heap_free(buffer->buffer_heap, buffer->cs_persistent_map); + } + + buffer->cs_persistent_map = op->map_range; + -+ device_invalidate_state(cs->device, STATE_STREAMSRC); ++ // TODO(acomminos): merge this logic with buffer.c functions for standalone BOs ++ if (buffer->bind_flags & WINED3D_BIND_VERTEX_BUFFER) ++ device_invalidate_state(cs->device, STATE_STREAMSRC); ++ if (buffer->bind_flags & WINED3D_BIND_INDEX_BUFFER) ++ device_invalidate_state(cs->device, STATE_INDEXBUFFER); ++ if (buffer->bind_flags & WINED3D_BIND_CONSTANT_BUFFER) ++ { ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_HULL)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_DOMAIN)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL)); ++ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COMPUTE)); ++ } + + wined3d_resource_release(&op->buffer->resource); +} @@ -489,50 +479,19 @@ index 7e72b30933..edcf521b72 100644 static void wined3d_cs_emit_stop(struct wined3d_cs *cs) { struct wined3d_cs_stop *op; -@@ -2690,6 +2747,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void +@@ -2515,6 +2570,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void + /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view, /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter, - /* WINED3D_CS_OP_COPY_SUB_RESOURCE */ wined3d_cs_exec_copy_sub_resource, - /* WINED3D_CS_OP_GENERATE_MIPS */ wined3d_cs_exec_generate_mips, + /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps, + /* WINED3D_CS_OP_DISCARD_BUFFER */ wined3d_cs_exec_discard_buffer, }; #if defined(STAGING_CSMT) -diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c -index 404623c9ac..7b622c9b14 100644 ---- a/dlls/wined3d/drawprim.c -+++ b/dlls/wined3d/drawprim.c -@@ -688,7 +688,12 @@ 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->buffer_object || !stream_info->all_vbo) -+ if (index_buffer->locations & WINED3D_LOCATION_PERSISTENT_MAP) -+ { -+ idx_data = index_buffer->cs_persistent_map.offset; -+ ib_fence = index_buffer->fence; // FIXME(acomminos): use this fence or not? -+ } -+ else if (!index_buffer->buffer_object || !stream_info->all_vbo) - { - idx_data = index_buffer->resource.heap_memory; - } -diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c -index f394af87c7..cf665bfd11 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/resource.c b/dlls/wined3d/resource.c -index 78deb5078b..9b3a303b08 100644 +index 8b7f17bb6b..02d469bc20 100644 --- a/dlls/wined3d/resource.c +++ b/dlls/wined3d/resource.c -@@ -358,13 +358,18 @@ static DWORD wined3d_resource_sanitise_map_flags(const struct wined3d_resource * +@@ -344,6 +344,7 @@ static DWORD wined3d_resource_sanitise_map_flags(const struct wined3d_resource * HRESULT CDECL wined3d_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) { @@ -540,21 +499,24 @@ index 78deb5078b..9b3a303b08 100644 TRACE("resource %p, sub_resource_idx %u, map_desc %p, box %s, flags %#x.\n", resource, sub_resource_idx, map_desc, debug_box(box), flags); +@@ -366,9 +367,14 @@ HRESULT CDECL wined3d_resource_map(struct wined3d_resource *resource, unsigned i + } + flags = wined3d_resource_sanitise_map_flags(resource, flags); - wined3d_resource_wait_idle(resource); -- -- return wined3d_cs_map(resource->device->cs, resource, sub_resource_idx, map_desc, box, flags); + if (FAILED(hr = resource->resource_ops->resource_sub_resource_map(resource, sub_resource_idx, map_desc, box, flags))) + { + TRACE_(d3d_perf)("Mapping resource %p on the command stream.\n", resource); + wined3d_resource_wait_idle(resource); + hr = wined3d_cs_map(resource->device->cs, resource, sub_resource_idx, map_desc, box, flags); + } + +- return wined3d_cs_map(resource->device->cs, resource, sub_resource_idx, map_desc, box, flags); + return hr; } HRESULT CDECL wined3d_resource_map_info(struct wined3d_resource *resource, unsigned int sub_resource_idx, -@@ -377,9 +382,16 @@ HRESULT CDECL wined3d_resource_map_info(struct wined3d_resource *resource, unsig +@@ -381,9 +387,15 @@ HRESULT CDECL wined3d_resource_map_info(struct wined3d_resource *resource, unsig HRESULT CDECL wined3d_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) { @@ -568,15 +530,14 @@ index 78deb5078b..9b3a303b08 100644 + hr = wined3d_cs_unmap(resource->device->cs, resource, sub_resource_idx); + } + return hr; -+ } UINT CDECL wined3d_resource_update_info(struct wined3d_resource *resource, unsigned int sub_resource_idx, diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c -index f5b9eca520..142a932d07 100644 +index 2f506c36d1..6f7805b8bd 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c -@@ -4910,7 +4910,11 @@ static void indexbuffer(struct wined3d_context *context, const struct wined3d_st +@@ -4934,7 +4934,11 @@ static void indexbuffer(struct wined3d_context *context, const struct wined3d_st else { struct wined3d_buffer *ib = state->index_buffer; @@ -589,11 +550,36 @@ index f5b9eca520..142a932d07 100644 } } +@@ -5000,6 +5004,7 @@ static void state_cb(struct wined3d_context *context, const struct wined3d_state + enum wined3d_shader_type shader_type; + struct wined3d_buffer *buffer; + unsigned int i, base, count; ++ struct wined3d_bo_address bo_addr; + + TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); + +@@ -5012,7 +5017,15 @@ static void state_cb(struct wined3d_context *context, const struct wined3d_state + for (i = 0; i < count; ++i) + { + buffer = state->cb[shader_type][i]; +- GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, buffer ? buffer->buffer_object : 0)); ++ if (buffer) ++ { ++ wined3d_buffer_get_memory(buffer, &bo_addr, buffer->locations); ++ GL_EXTCALL(glBindBufferRange(GL_UNIFORM_BUFFER, base + i, bo_addr.buffer_object, bo_addr.addr, bo_addr.length)); ++ } ++ else ++ { ++ GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, 0)); ++ } + } + checkGLcall("bind constant buffers"); + } diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c -index 69565f355d..51c37762cd 100644 +index e6af0c7508..8ca1ee7158 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c -@@ -2297,6 +2297,12 @@ static void wined3d_texture_unload(struct wined3d_resource *resource) +@@ -2301,6 +2301,12 @@ static void wined3d_texture_unload(struct wined3d_resource *resource) static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resource, unsigned int sub_resource_idx, struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags) @@ -606,7 +592,7 @@ index 69565f355d..51c37762cd 100644 { const struct wined3d_format *format = resource->format; struct wined3d_texture_sub_resource *sub_resource; -@@ -2464,6 +2470,11 @@ static HRESULT texture_resource_sub_resource_map_info(struct wined3d_resource *r +@@ -2461,6 +2467,11 @@ static HRESULT texture_resource_sub_resource_map_info(struct wined3d_resource *r } static HRESULT texture_resource_sub_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx) @@ -618,57 +604,52 @@ index 69565f355d..51c37762cd 100644 { struct wined3d_texture_sub_resource *sub_resource; struct wined3d_device *device = resource->device; -@@ -2514,8 +2525,10 @@ static const struct wined3d_resource_ops texture_resource_ops = - texture_resource_preload, +@@ -2512,7 +2523,9 @@ static const struct wined3d_resource_ops texture_resource_ops = wined3d_texture_unload, texture_resource_sub_resource_map, -+ texture_resource_sub_resource_map_cs, texture_resource_sub_resource_map_info, ++ texture_resource_sub_resource_map_cs, texture_resource_sub_resource_unmap, + texture_resource_sub_resource_unmap_cs, }; static HRESULT texture1d_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc, diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c -index ee519d2b32..25626749fa 100644 +index b8b7880501..62758ae056 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c -@@ -6264,6 +6264,7 @@ const char *wined3d_debug_location(DWORD location) +@@ -6404,6 +6404,7 @@ const char *wined3d_debug_location(DWORD location) LOCATION_TO_STR(WINED3D_LOCATION_DRAWABLE); LOCATION_TO_STR(WINED3D_LOCATION_RB_MULTISAMPLE); LOCATION_TO_STR(WINED3D_LOCATION_RB_RESOLVED); + LOCATION_TO_STR(WINED3D_LOCATION_PERSISTENT_MAP); #undef LOCATION_TO_STR - if (location) FIXME("Unrecognized location flag(s) %#x.\n", location); - + if (location) + FIXME("Unrecognized location flag(s) %#x.\n", location); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 96bda81eb9..d049d57206 100644 +index 3d535f4e17..6d32a368a2 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h -@@ -1701,6 +1701,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 -@@ -3009,9 +3012,12 @@ struct wined3d_resource_ops - void (*resource_unload)(struct wined3d_resource *resource); - HRESULT (*resource_sub_resource_map)(struct wined3d_resource *resource, unsigned int sub_resource_idx, +@@ -1470,6 +1470,7 @@ struct wined3d_bo_address + { + GLuint buffer_object; + BYTE *addr; ++ GLsizeiptr length; + }; + + struct wined3d_const_bo_address +@@ -3046,7 +3047,10 @@ struct wined3d_resource_ops struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags); -+ HRESULT (*resource_sub_resource_map_cs)(struct wined3d_resource *resource, unsigned int sub_resource_idx, -+ struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags); HRESULT (*resource_map_info)(struct wined3d_resource *resource, unsigned int sub_resource_idx, struct wined3d_map_info *info, DWORD flags); ++ HRESULT (*resource_sub_resource_map_cs)(struct wined3d_resource *resource, unsigned int sub_resource_idx, ++ struct wined3d_map_desc *map_desc, const struct wined3d_box *box, DWORD flags); HRESULT (*resource_sub_resource_unmap)(struct wined3d_resource *resource, unsigned int sub_resource_idx); + HRESULT (*resource_sub_resource_unmap_cs)(struct wined3d_resource *resource, unsigned int sub_resource_idx); }; struct wined3d_resource -@@ -3266,6 +3272,7 @@ void wined3d_texture_validate_location(struct wined3d_texture *texture, +@@ -3325,6 +3329,7 @@ void wined3d_texture_validate_location(struct wined3d_texture *texture, #define WINED3D_LOCATION_DRAWABLE 0x00000040 #define WINED3D_LOCATION_RB_MULTISAMPLE 0x00000080 #define WINED3D_LOCATION_RB_RESOLVED 0x00000100 @@ -676,15 +657,15 @@ index 96bda81eb9..d049d57206 100644 const char *wined3d_debug_location(DWORD location) DECLSPEC_HIDDEN; -@@ -3622,6 +3629,7 @@ void wined3d_cs_emit_copy_sub_resource(struct wined3d_cs *cs, struct wined3d_res - unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box, struct wined3d_resource *src_resource, - unsigned int src_sub_resource_idx, const struct wined3d_box *src_box) DECLSPEC_HIDDEN; - void wined3d_cs_emit_generate_mips(struct wined3d_cs *cs, struct wined3d_shader_resource_view *view) DECLSPEC_HIDDEN; +@@ -3672,6 +3677,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_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, -@@ -3712,6 +3720,11 @@ struct wined3d_buffer +@@ -3784,6 +3790,11 @@ struct wined3d_buffer UINT stride; /* 0 if no conversion */ enum wined3d_buffer_conversion_type *conversion_map; /* NULL if no conversion */ UINT conversion_stride; /* 0 if no shifted conversion */ diff --git a/0002-wined3d-Allocate-global-write-only-persistent-buffer.patch b/0002-wined3d-Allocate-global-write-only-persistent-buffer.patch deleted file mode 100644 index 66e2e25d69f8..000000000000 --- a/0002-wined3d-Allocate-global-write-only-persistent-buffer.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 7f141de6d631a6e0c9cd778f6b3259d41a700bb4 Mon Sep 17 00:00:00 2001 -From: Andrew Comminos <andrew@comminos.com> -Date: Fri, 23 Feb 2018 17:42:21 -0800 -Subject: [PATCH 2/8] wined3d: Allocate global write-only persistent buffer - heap at device initialization. - ---- - dlls/wined3d/device.c | 28 ++++++++++++++++++++++++++++ - dlls/wined3d/wined3d_private.h | 3 +++ - 2 files changed, 31 insertions(+) - -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index 58f4993abe..363dcb17f0 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -845,6 +845,29 @@ 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) -+{ -+ // TODO(acomminos): check if ARB_buffer_storage is supported, first- -+ // possibly make wined3d_buffer_heap_create fail. -+ // TODO(acomminos): definitely don't take up all of vram. this is gonna get -+ // paged anyway, though. -+ const GLsizeiptr HBO_SIZE = device->adapter->vram_bytes / 4; -+ -+ HRESULT hr; -+ if (FAILED(hr = wined3d_buffer_heap_create(context, HBO_SIZE, TRUE, &device->wo_buffer_heap))) -+ { -+ ERR("Failed to create write-only persistent buffer heap, hr %#x.\n", hr); -+ } -+} -+ -+/* 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); -+} -+ - static LONG fullscreen_style(LONG style) - { - /* Make sure the window is managed, otherwise we won't get keyboard input. */ -@@ -1013,6 +1036,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) -@@ -1060,6 +1085,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/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 4d0555a76c..96bda81eb9 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -2966,6 +2966,9 @@ struct wined3d_device - /* Context management */ - struct wined3d_context **contexts; - UINT context_count; -+ -+ /* Dynamic buffer heap */ -+ struct wined3d_buffer_heap *wo_buffer_heap; - }; - - void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb, --- -2.16.2 - diff --git a/0003-wined3d-Use-ARB_multi_bind-to-speed-up-UBO-updates.patch b/0003-wined3d-Use-ARB_multi_bind-to-speed-up-UBO-updates.patch new file mode 100644 index 000000000000..b0de3a7183e1 --- /dev/null +++ b/0003-wined3d-Use-ARB_multi_bind-to-speed-up-UBO-updates.patch @@ -0,0 +1,121 @@ +From d64aafc0ede047d1eff93ee7aa77411c0d27aa21 Mon Sep 17 00:00:00 2001 +From: Andrew Comminos <andrew@comminos.com> +Date: Mon, 5 Mar 2018 20:28:34 -0800 +Subject: [PATCH 3/5] wined3d: Use ARB_multi_bind to speed up UBO updates. + +More frequent UBO remaps as a result of the persistent buffer allocator +causes glBindBufferRange to be a bottleneck. Using ARB_multi_bind +massively reduces state change overhead. +--- + dlls/wined3d/directx.c | 4 ++++ + dlls/wined3d/state.c | 46 +++++++++++++++++++++++++++++++++++++++------- + dlls/wined3d/wined3d_gl.h | 1 + + 3 files changed, 44 insertions(+), 7 deletions(-) + +diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c +index 46c6a59536..8789a501ec 100644 +--- a/dlls/wined3d/directx.c ++++ b/dlls/wined3d/directx.c +@@ -149,6 +149,7 @@ static const struct wined3d_extension_map gl_extension_map[] = + {"GL_ARB_internalformat_query2", ARB_INTERNALFORMAT_QUERY2 }, + {"GL_ARB_map_buffer_alignment", ARB_MAP_BUFFER_ALIGNMENT }, + {"GL_ARB_map_buffer_range", ARB_MAP_BUFFER_RANGE }, ++ {"GL_ARB_multi_bind", ARB_MULTI_BIND }, + {"GL_ARB_multisample", ARB_MULTISAMPLE }, + {"GL_ARB_multitexture", ARB_MULTITEXTURE }, + {"GL_ARB_occlusion_query", ARB_OCCLUSION_QUERY }, +@@ -2796,6 +2797,8 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info) + /* GL_ARB_map_buffer_range */ + USE_GL_FUNC(glFlushMappedBufferRange) + USE_GL_FUNC(glMapBufferRange) ++ /* GL_ARB_multi_bind */ ++ USE_GL_FUNC(glBindBuffersRange) + /* GL_ARB_multisample */ + USE_GL_FUNC(glSampleCoverageARB) + /* GL_ARB_multitexture */ +@@ -3973,6 +3976,7 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter, + {ARB_TEXTURE_VIEW, MAKEDWORD_VERSION(4, 3)}, + + {ARB_CLEAR_TEXTURE, MAKEDWORD_VERSION(4, 4)}, ++ {ARB_MULTI_BIND, MAKEDWORD_VERSION(4, 4)}, + + {ARB_CLIP_CONTROL, MAKEDWORD_VERSION(4, 5)}, + {ARB_CULL_DISTANCE, MAKEDWORD_VERSION(4, 5)}, +diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c +index 6f7805b8bd..4d0718514f 100644 +--- a/dlls/wined3d/state.c ++++ b/dlls/wined3d/state.c +@@ -5014,19 +5014,51 @@ static void state_cb(struct wined3d_context *context, const struct wined3d_state + shader_type = WINED3D_SHADER_TYPE_COMPUTE; + + wined3d_gl_limits_get_uniform_block_range(&gl_info->limits, shader_type, &base, &count); +- for (i = 0; i < count; ++i) ++ ++ if (gl_info->supported[ARB_MULTI_BIND]) + { +- buffer = state->cb[shader_type][i]; +- if (buffer) ++ GLuint buffer_objects[count]; ++ GLsizeiptr buffer_offsets[count]; ++ GLsizeiptr buffer_sizes[count]; ++ ++ for (i = 0; i < count; ++i) + { +- wined3d_buffer_get_memory(buffer, &bo_addr, buffer->locations); +- GL_EXTCALL(glBindBufferRange(GL_UNIFORM_BUFFER, base + i, bo_addr.buffer_object, bo_addr.addr, bo_addr.length)); ++ buffer = state->cb[shader_type][i]; ++ if (buffer) ++ { ++ wined3d_buffer_get_memory(buffer, &bo_addr, buffer->locations); ++ buffer_objects[i] = bo_addr.buffer_object; ++ buffer_offsets[i] = bo_addr.addr; ++ buffer_sizes[i] = bo_addr.length; ++ } ++ else ++ { ++ buffer_objects[i] = buffer_offsets[i] = 0; ++ // The ARB_multi_bind spec states that an error may be thrown if ++ // `size` is less than or equal to zero, Thus, we specify a size for ++ // unused buffers anyway. ++ buffer_sizes[i] = 1; ++ } + } +- else ++ GL_EXTCALL(glBindBuffersRange(GL_UNIFORM_BUFFER, base, count, buffer_objects, buffer_offsets, buffer_sizes)); ++ } ++ else ++ { ++ for (i = 0; i < count; ++i) + { +- GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, 0)); ++ buffer = state->cb[shader_type][i]; ++ if (buffer) ++ { ++ wined3d_buffer_get_memory(buffer, &bo_addr, buffer->locations); ++ GL_EXTCALL(glBindBufferRange(GL_UNIFORM_BUFFER, base + i, bo_addr.buffer_object, bo_addr.addr, bo_addr.length)); ++ } ++ else ++ { ++ GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, 0)); ++ } + } + } ++ + checkGLcall("bind constant buffers"); + } + +diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h +index 7626864ef2..25c3301c94 100644 +--- a/dlls/wined3d/wined3d_gl.h ++++ b/dlls/wined3d/wined3d_gl.h +@@ -82,6 +82,7 @@ enum wined3d_gl_extension + ARB_INTERNALFORMAT_QUERY2, + ARB_MAP_BUFFER_ALIGNMENT, + ARB_MAP_BUFFER_RANGE, ++ ARB_MULTI_BIND, + ARB_MULTISAMPLE, + ARB_MULTITEXTURE, + ARB_OCCLUSION_QUERY, +-- +2.16.2 + diff --git a/0004-wined3d-Implement-aligned-persistent-heaps-for-persi.patch b/0004-wined3d-Implement-aligned-persistent-heaps-for-persi.patch deleted file mode 100644 index 7b4a9e433488..000000000000 --- a/0004-wined3d-Implement-aligned-persistent-heaps-for-persi.patch +++ /dev/null @@ -1,240 +0,0 @@ -From 65595c191d2a01b2486ba10618f743c930af362b Mon Sep 17 00:00:00 2001 -From: Andrew Comminos <andrew@comminos.com> -Date: Sat, 24 Feb 2018 14:38:59 -0800 -Subject: [PATCH 4/8] wined3d: Implement aligned persistent heaps for - persistently mapped UBOs. - ---- - dlls/wined3d/buffer.c | 16 ++++++++++++---- - dlls/wined3d/buffer_heap.c | 12 +++++++++--- - dlls/wined3d/cs.c | 15 ++++++++++++++- - dlls/wined3d/device.c | 15 ++++++++++++++- - dlls/wined3d/state.c | 11 ++++++++++- - dlls/wined3d/wined3d_private.h | 5 ++++- - 6 files changed, 63 insertions(+), 11 deletions(-) - -diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c -index ccb090c907..7d7e506817 100644 ---- a/dlls/wined3d/buffer.c -+++ b/dlls/wined3d/buffer.c -@@ -279,14 +279,16 @@ static BOOL buffer_alloc_persistent_map(struct wined3d_buffer *buffer, struct wi - struct wined3d_map_range map_range; - HRESULT hr; - -- if (buffer->resource.usage & WINED3DUSAGE_WRITEONLY) -+ if (buffer->bind_flags & WINED3D_BIND_CONSTANT_BUFFER) - { -- heap = device->wo_buffer_heap; -+ // Use a heap aligned to constant buffer offset requirements. -+ heap = device->cb_buffer_heap; - } - else - { -- FIXME("Using write-only heap for a persistent buffer without WINED3DUSAGE_WRITEONLY.\n"); -- heap = device->rw_buffer_heap; -+ if (!(buffer->resource.usage & WINED3DUSAGE_WRITEONLY)) -+ FIXME("Using a write-only persistent buffer for %p without WINED3DUSAGE_WRITEONLY.\n", buffer); -+ heap = device->wo_buffer_heap; - } - - buffer->buffer_heap = heap; -@@ -791,6 +793,7 @@ DWORD wined3d_buffer_get_memory(struct wined3d_buffer *buffer, - { - data->buffer_object = buffer->buffer_object; - data->addr = NULL; -+ data->length = buffer->resource.size; - return WINED3D_LOCATION_BUFFER; - } - if (locations & WINED3D_LOCATION_PERSISTENT_MAP) -@@ -798,12 +801,17 @@ 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; -+ // 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; - return WINED3D_LOCATION_PERSISTENT_MAP; - } - if (locations & WINED3D_LOCATION_SYSMEM) - { - data->buffer_object = 0; - data->addr = buffer->resource.heap_memory; -+ data->length = buffer->resource.size; - return WINED3D_LOCATION_SYSMEM; - } - -diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c -index f24fddffb4..02b925b658 100644 ---- a/dlls/wined3d/buffer_heap.c -+++ b/dlls/wined3d/buffer_heap.c -@@ -95,7 +95,7 @@ static void element_merge_adjacent(struct wined3d_buffer_heap *heap, struct wine - } - - /* 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) -+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; -@@ -133,6 +133,7 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s - - object->free_list_head = element_new(0, size); - object->fenced_head = object->fenced_tail = NULL; -+ object->alignment = alignment; - InitializeCriticalSection(&object->temp_lock); - - *buffer_heap = object; -@@ -147,12 +148,17 @@ 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_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. -+ -+ // Round up the size to a multiple of the heap's alignment. -+ if (heap->alignment) -+ size += heap->alignment - (size % heap->alignment); -+ - while (elem != NULL) - { - TRACE("allocation at %p, size %lld\n", heap->map_ptr + elem->range.offset, elem->range.size); -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index edcf521b72..d7bdc21a25 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -2668,7 +2668,20 @@ static void wined3d_cs_exec_discard_buffer(struct wined3d_cs *cs, const void *da - - buffer->cs_persistent_map = op->map_range; - -- device_invalidate_state(cs->device, STATE_STREAMSRC); -+ // TODO(acomminos): merge this logic with buffer.c functions for standalone BOs -+ if (buffer->bind_flags & WINED3D_BIND_VERTEX_BUFFER) -+ device_invalidate_state(cs->device, STATE_STREAMSRC); -+ if (buffer->bind_flags & WINED3D_BIND_INDEX_BUFFER) -+ device_invalidate_state(cs->device, STATE_INDEXBUFFER); -+ if (buffer->bind_flags & WINED3D_BIND_CONSTANT_BUFFER) -+ { -+ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_VERTEX)); -+ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_HULL)); -+ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_DOMAIN)); -+ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_GEOMETRY)); -+ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_PIXEL)); -+ device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COMPUTE)); -+ } - - wined3d_resource_release(&op->buffer->resource); - } -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index 363dcb17f0..e0871d1636 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -853,12 +853,22 @@ static void create_buffer_heap(struct wined3d_device *device, struct wined3d_con - // TODO(acomminos): definitely don't take up all of vram. this is gonna get - // paged anyway, though. - const GLsizeiptr HBO_SIZE = device->adapter->vram_bytes / 4; -+ const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; -+ -+ GLint ub_alignment; -+ gl_info->gl_ops.gl.p_glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &ub_alignment); - - HRESULT hr; -- if (FAILED(hr = wined3d_buffer_heap_create(context, HBO_SIZE, TRUE, &device->wo_buffer_heap))) -+ if (FAILED(hr = wined3d_buffer_heap_create(context, HBO_SIZE, 0, TRUE, &device->wo_buffer_heap))) - { - ERR("Failed to create write-only persistent buffer heap, hr %#x.\n", hr); - } -+ -+ // TODO(acomminos): can likely use a way smaller heap for CBs by querying limits -+ if (FAILED(hr = wined3d_buffer_heap_create(context, HBO_SIZE, ub_alignment, TRUE, &device->cb_buffer_heap))) -+ { -+ ERR("Failed to create persistent buffer heap for constant buffers, hr %#x.\n", hr); -+ } - } - - /* Context activation is done by the caller. */ -@@ -866,6 +876,9 @@ static void destroy_buffer_heap(struct wined3d_device *device, struct wined3d_co - { - 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) -diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c -index 142a932d07..ce007d1a8e 100644 ---- a/dlls/wined3d/state.c -+++ b/dlls/wined3d/state.c -@@ -4980,6 +4980,7 @@ static void state_cb(struct wined3d_context *context, const struct wined3d_state - enum wined3d_shader_type shader_type; - struct wined3d_buffer *buffer; - unsigned int i, base, count; -+ struct wined3d_bo_address bo_addr; - - TRACE("context %p, state %p, state_id %#x.\n", context, state, state_id); - -@@ -4992,7 +4993,15 @@ static void state_cb(struct wined3d_context *context, const struct wined3d_state - for (i = 0; i < count; ++i) - { - buffer = state->cb[shader_type][i]; -- GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, buffer ? buffer->buffer_object : 0)); -+ if (buffer) -+ { -+ wined3d_buffer_get_memory(buffer, &bo_addr, buffer->locations); -+ GL_EXTCALL(glBindBufferRange(GL_UNIFORM_BUFFER, base + i, bo_addr.buffer_object, bo_addr.addr, bo_addr.length)); -+ } -+ else -+ { -+ GL_EXTCALL(glBindBufferBase(GL_UNIFORM_BUFFER, base + i, 0)); -+ } - } - checkGLcall("bind constant buffers"); - } -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index d049d57206..cfa48a5f3e 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -1462,6 +1462,7 @@ struct wined3d_bo_address - { - GLuint buffer_object; - BYTE *addr; -+ GLsizeiptr length; - }; - - struct wined3d_const_bo_address -@@ -2972,6 +2973,7 @@ struct wined3d_device - - /* 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, -@@ -3671,6 +3673,7 @@ 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. - - // TODO: add buckets for free regions of a given size. -@@ -3684,7 +3687,7 @@ struct wined3d_buffer_heap - 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_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. - HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr size, struct wined3d_map_range* out_range) DECLSPEC_HIDDEN; --- -2.16.2 - diff --git a/0004-wined3d-Use-GL_CLIENT_STORAGE_BIT-for-persistent-map.patch b/0004-wined3d-Use-GL_CLIENT_STORAGE_BIT-for-persistent-map.patch new file mode 100644 index 000000000000..45c7ada812c6 --- /dev/null +++ b/0004-wined3d-Use-GL_CLIENT_STORAGE_BIT-for-persistent-map.patch @@ -0,0 +1,26 @@ +From 780cb020b7064eac55b1394aa6dbef2f11f2488a Mon Sep 17 00:00:00 2001 +From: Andrew Comminos <andrew@comminos.com> +Date: Tue, 6 Mar 2018 02:07:31 -0800 +Subject: [PATCH 4/5] wined3d: Use GL_CLIENT_STORAGE_BIT for persistent + mappings. + +--- + dlls/wined3d/buffer_heap.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c +index b133bd6893..75f84b0088 100644 +--- a/dlls/wined3d/buffer_heap.c ++++ b/dlls/wined3d/buffer_heap.c +@@ -169,7 +169,7 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s + { + access_flags |= GL_MAP_READ_BIT; + } +- storage_flags = access_flags; ++ storage_flags = GL_CLIENT_STORAGE_BIT | access_flags; + + // TODO(acomminos): where should we be checking for errors here? + GL_EXTCALL(glGenBuffers(1, &object->buffer_object)); +-- +2.16.2 + diff --git a/0005-wined3d-Experimental-buffer-heap-fence-batching-uppe.patch b/0005-wined3d-Experimental-buffer-heap-fence-batching-uppe.patch deleted file mode 100644 index cac70eac997d..000000000000 --- a/0005-wined3d-Experimental-buffer-heap-fence-batching-uppe.patch +++ /dev/null @@ -1,455 +0,0 @@ -From 7a630d56cb1bddfd03cae3cdc43aee949b04abe2 Mon Sep 17 00:00:00 2001 -From: Andrew Comminos <andrew@comminos.com> -Date: Mon, 26 Feb 2018 21:35:40 -0800 -Subject: [PATCH 5/8] wined3d: Experimental buffer heap fence batching, upper - bound on heap size. - ---- - dlls/wined3d/buffer.c | 11 +- - dlls/wined3d/buffer_heap.c | 232 ++++++++++++++++++++++++----------------- - dlls/wined3d/cs.c | 15 +-- - dlls/wined3d/device.c | 5 +- - dlls/wined3d/wined3d_private.h | 12 ++- - 5 files changed, 154 insertions(+), 121 deletions(-) - -diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c -index 7d7e506817..fbec613c92 100644 ---- a/dlls/wined3d/buffer.c -+++ b/dlls/wined3d/buffer.c -@@ -992,9 +992,12 @@ void wined3d_buffer_load(struct wined3d_buffer *buffer, struct wined3d_context * - - if (buffer->flags & WINED3D_BUFFER_PERSISTENT) - { -- if (!wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_PERSISTENT_MAP)) -- ERR("Failed to preload persistent mapping.\n"); -- return; -+ if (wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_PERSISTENT_MAP)) -+ return; -+ -+ ERR("Failed to preload persistent mapping for %p, falling back to BO.\n", buffer); -+ buffer->flags |= WINED3D_BUFFER_USE_BO; -+ buffer->flags &= ~WINED3D_BUFFER_PERSISTENT; - } - - /* TODO: Make converting independent from VBOs */ -@@ -1417,7 +1420,7 @@ static HRESULT buffer_resource_sub_resource_map(struct wined3d_resource *resourc - struct wined3d_map_range map_range; - if (FAILED(hr = wined3d_buffer_heap_alloc(buffer->buffer_heap, resource->size, &map_range))) - { -- FIXME("Failed to allocate new buffer, falling back to sync path.\n"); -+ 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; -diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c -index 02b925b658..165a957edd 100644 ---- a/dlls/wined3d/buffer_heap.c -+++ b/dlls/wined3d/buffer_heap.c -@@ -22,6 +22,7 @@ - #include "wined3d_private.h" - - WINE_DEFAULT_DEBUG_CHANNEL(d3d); -+WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); - - struct wined3d_buffer_heap_element - { -@@ -33,7 +34,7 @@ struct wined3d_buffer_heap_element - - struct wined3d_buffer_heap_fenced_element - { -- struct wined3d_map_range range; -+ struct wined3d_buffer_heap_element *ranges; - struct wined3d_fence *fence; - - struct wined3d_buffer_heap_element *next; -@@ -52,19 +53,19 @@ static struct wined3d_buffer_heap_element* element_new(GLintptr offset, GLsizeip - return elem; - } - --static struct wined3d_buffer_heap_fenced_element* fenced_element_new(struct wined3d_map_range range, struct wined3d_fence* fence) -+static struct wined3d_buffer_heap_fenced_element* fenced_element_new(struct wined3d_buffer_heap_element *ranges, 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->ranges = ranges; - elem->fence = fence; - elem->next = NULL; - return elem; - } - --static void element_merge_adjacent(struct wined3d_buffer_heap *heap, struct wined3d_buffer_heap_element *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; -@@ -77,8 +78,8 @@ static void element_merge_adjacent(struct wined3d_buffer_heap *heap, struct wine - if (cur_prev->prev) - cur_prev->prev->next = elem; - -- if (cur_prev == heap->free_list_head) -- heap->free_list_head = elem; -+ if (cur_prev == *head) -+ *head = elem; - - HeapFree(GetProcessHeap(), 0, cur_prev); - } -@@ -94,6 +95,69 @@ static void element_merge_adjacent(struct wined3d_buffer_heap *heap, struct wine - } - } - -+// 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) -+{ -+ 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; -+} -+ - /* 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) - { -@@ -134,6 +198,9 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s - object->free_list_head = element_new(0, size); - object->fenced_head = object->fenced_tail = NULL; - object->alignment = alignment; -+ object->pending_fenced_bytes = 0; -+ object->pending_fenced_head = NULL; -+ object->pending_fenced_threshold_bytes = size / 4; // FIXME(acomminos): make this externally declared - InitializeCriticalSection(&object->temp_lock); - - *buffer_heap = object; -@@ -155,6 +222,9 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s - // TODO(acomminos): free list binning? - struct wined3d_buffer_heap_element *elem = heap->free_list_head; - -+ // Round to the nearest power of two to reduce fragmentation. -+ size = 1ULL << (int)ceil(log2(size)); -+ - // Round up the size to a multiple of the heap's alignment. - if (heap->alignment) - size += heap->alignment - (size % heap->alignment); -@@ -188,6 +258,7 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s - } - HeapFree(GetProcessHeap(), 0, elem); - } -+ - LeaveCriticalSection(&heap->temp_lock); - return WINED3D_OK; - } -@@ -201,87 +272,53 @@ 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) - { - 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; -- } -+ element_insert_range(&heap->free_list_head, range); - -- while (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); -+ -+ heap->pending_fenced_bytes += range.size; -+ if (heap->pending_fenced_bytes >= heap->pending_fenced_threshold_bytes) - { -- struct wined3d_map_range *erange = &elem->range; -- if (range.offset + range.size == erange->offset) -+ // TODO(acomminos): break this out into a separate function -+ struct wined3d_buffer_heap_fenced_element *fenced_elem; -+ struct wined3d_fence *fence; -+ HRESULT hr; -+ -+ if (FAILED(hr = wined3d_fence_create(device, &fence))) - { -- // 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; -+ ERR("Failed to create fence.\n"); -+ return hr; - } -- else if (erange->offset + erange->size == range.offset) -+ -+ fenced_elem = fenced_element_new(heap->pending_fenced_head, fence); -+ if (!fenced_elem) -+ return E_OUTOFMEMORY; -+ -+ TRACE_(d3d_perf)("Dispatching fenced buffer set.\n"); -+ heap->pending_fenced_bytes = 0; -+ heap->pending_fenced_head = NULL; -+ -+ // 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) - { -- // Right side merge -- erange->size += range.size; -- // Check if this causes a merge with elem->prev -- element_merge_adjacent(heap, elem); -- goto success; -+ heap->fenced_head = fenced_elem; -+ heap->fenced_tail = fenced_elem; - } -- else if (range.offset < erange->offset) -+ else - { -- // 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; -+ heap->fenced_tail->next = fenced_elem; -+ heap->fenced_tail = fenced_elem; - } -- 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; -+ wined3d_fence_issue(fence, device); - } - - return WINED3D_OK; -@@ -294,29 +331,32 @@ HRESULT wined3d_buffer_heap_cs_poll_fences(struct wined3d_buffer_heap *heap, str - if (!elem) - return WINED3D_OK; - -- while (elem) -+ res = wined3d_fence_test(elem->fence, device, 0); -+ switch (res) - { -- res = wined3d_fence_test(elem->fence, device, 0); -- switch (res) -- { -- case WINED3D_FENCE_OK: -- case WINED3D_FENCE_NOT_STARTED: -+ case WINED3D_FENCE_OK: -+ case WINED3D_FENCE_NOT_STARTED: -+ { -+ TRACE_(d3d_perf)("Freed fence group.\n"); -+ struct wined3d_buffer_heap_element *range_elem = elem->ranges; -+ // FIXME(acomminos): this might take a while. incrementally do this? -+ while (range_elem) - { -- struct wined3d_buffer_heap_fenced_element *next = elem->next; -- -- wined3d_fence_destroy(elem->fence); -- wined3d_buffer_heap_free(heap, elem->range); -+ struct wined3d_buffer_heap_element *next = range_elem->next; -+ wined3d_buffer_heap_free(heap, range_elem->range); -+ HeapFree(GetProcessHeap(), 0, range_elem); -+ range_elem = next; -+ } - -- heap->fenced_head = elem->next; -- HeapFree(GetProcessHeap(), 0, elem); -- // TODO(acomminos): bother to null out fenced_tail? -+ wined3d_fence_destroy(elem->fence); - -- elem = next; -- break; -- } -- default: -- return WINED3D_OK; -- } -+ 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; -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index d7bdc21a25..bae5d9f4a1 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -2643,26 +2643,15 @@ static void wined3d_cs_exec_discard_buffer(struct wined3d_cs *cs, const void *da - const struct wined3d_cs_discard_buffer *op = data; - struct wined3d_buffer *buffer = op->buffer; - HRESULT hr; -- struct wined3d_fence *fence; - - // Poll for discarded buffers whose fenced have been triggered here to avoid - // excessive VRAM consumption. - wined3d_buffer_heap_cs_poll_fences(buffer->buffer_heap, cs->device); - - // TODO(acomminos): should call into buffer.c here instead. -- // XXX(acomminos): should we always create a new fence here? -- if (!FAILED(hr = wined3d_fence_create(cs->device, &fence))) -+ if (FAILED(hr = wined3d_buffer_heap_free_fenced(buffer->buffer_heap, cs->device, buffer->cs_persistent_map))) - { -- // TODO(acomminos): make more informed fences based on prior info. for now, -- // we do this because allocating and deleting fences repeatedly is brutal -- // for performance. look into why. -- wined3d_fence_issue(fence, cs->device); -- -- wined3d_buffer_heap_free_fenced(buffer->buffer_heap, buffer->cs_persistent_map, fence); -- } -- else -- { -- ERR("Failed to create fence for discarded buffer %p, hr %x\n. Freeing anyway.", buffer, hr); -+ ERR("Failed to do a fenced free on discarded buffer %p, hr %x\n. Freeing anyway.", buffer, hr); - wined3d_buffer_heap_free(buffer->buffer_heap, buffer->cs_persistent_map); - } - -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index e0871d1636..bdab83b935 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -850,9 +850,8 @@ static void create_buffer_heap(struct wined3d_device *device, struct wined3d_con - { - // TODO(acomminos): check if ARB_buffer_storage is supported, first- - // possibly make wined3d_buffer_heap_create fail. -- // TODO(acomminos): definitely don't take up all of vram. this is gonna get -- // paged anyway, though. -- const GLsizeiptr HBO_SIZE = device->adapter->vram_bytes / 4; -+ // TODO(acomminos): 512MB is sane for geometry, maybe not for PBO. -+ const GLsizeiptr HBO_SIZE = min(512000000, device->adapter->vram_bytes / 4); - const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; - - GLint ub_alignment; -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index cfa48a5f3e..62433a39b1 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -3679,10 +3679,12 @@ struct wined3d_buffer_heap - // 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 -+ // Elements that need to be fenced, but haven't reached the required size. -+ struct wined3d_buffer_heap_element *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. -+ -+ // 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; - }; -@@ -3694,7 +3696,7 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s - // 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; -+HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct wined3d_device *device, struct wined3d_map_range range) 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; --- -2.16.2 - diff --git a/0005-wined3d-Experimental-support-for-persistent-buffer-t.patch b/0005-wined3d-Experimental-support-for-persistent-buffer-t.patch new file mode 100644 index 000000000000..a039c7e622c8 --- /dev/null +++ b/0005-wined3d-Experimental-support-for-persistent-buffer-t.patch @@ -0,0 +1,180 @@ +From 1e4c2e45a18a6eb445c507745f1c7b568c22aca6 Mon Sep 17 00:00:00 2001 +From: Andrew Comminos <andrew@comminos.com> +Date: Tue, 6 Mar 2018 15:58:05 -0800 +Subject: [PATCH 5/5] wined3d: Experimental support for persistent buffer + textures. + +Fixes missing models in Overwatch. +--- + dlls/wined3d/cs.c | 6 ++++ + dlls/wined3d/view.c | 79 +++++++++++++++++++++++++++++++++-------------------- + 2 files changed, 55 insertions(+), 30 deletions(-) + +diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c +index e61b8dedbb..63cdb74e02 100644 +--- a/dlls/wined3d/cs.c ++++ b/dlls/wined3d/cs.c +@@ -2493,6 +2493,12 @@ static void wined3d_cs_exec_discard_buffer(struct wined3d_cs *cs, const void *da + device_invalidate_state(cs->device, STATE_CONSTANT_BUFFER(WINED3D_SHADER_TYPE_COMPUTE)); + } + ++ if (buffer->bind_flags & WINED3D_BIND_SHADER_RESOURCE) ++ { ++ device_invalidate_state(cs->device, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); ++ device_invalidate_state(cs->device, STATE_COMPUTE_SHADER_RESOURCE_BINDING); ++ } ++ + wined3d_resource_release(&op->buffer->resource); + } + +diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c +index bed39dbc5f..100b3e34d8 100644 +--- a/dlls/wined3d/view.c ++++ b/dlls/wined3d/view.c +@@ -227,9 +227,7 @@ static void create_texture_view(struct wined3d_gl_view *view, GLenum view_target + context_release(context); + } + +-static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_context *context, +- struct wined3d_buffer *buffer, const struct wined3d_format *view_format, +- unsigned int offset, unsigned int size) ++static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_context *context) + { + const struct wined3d_gl_info *gl_info = context->gl_info; + +@@ -239,34 +237,58 @@ static void create_buffer_texture(struct wined3d_gl_view *view, struct wined3d_c + return; + } + +- if ((offset & (gl_info->limits.texture_buffer_offset_alignment - 1))) ++ view->target = GL_TEXTURE_BUFFER; ++ gl_info->gl_ops.gl.p_glGenTextures(1, &view->name); ++ ++ context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); ++ context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); ++} ++ ++static void bind_buffer_texture(struct wined3d_gl_view *view, struct wined3d_context *context, ++ struct wined3d_buffer *buffer, const struct wined3d_format *view_format, ++ unsigned int offset, unsigned int size) ++{ ++ const struct wined3d_gl_info *gl_info = context->gl_info; ++ struct wined3d_bo_address bo_addr; ++ unsigned int addr_offset; ++ ++ if (!wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER) && ++ !wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_PERSISTENT_MAP)) + { +- FIXME("Buffer offset %u is not %u byte aligned.\n", +- offset, gl_info->limits.texture_buffer_offset_alignment); ++ ERR("Failed to load a supported buffer location for %p.\n", buffer); + return; + } + +- wined3d_buffer_load_location(buffer, context, WINED3D_LOCATION_BUFFER); + +- view->target = GL_TEXTURE_BUFFER; +- gl_info->gl_ops.gl.p_glGenTextures(1, &view->name); ++ if (FAILED(wined3d_buffer_get_memory(buffer, &bo_addr, buffer->locations))) ++ { ++ ERR("Failed to get buffer memory to create a buffer texture.\n"); ++ return; ++ } ++ ++ // TODO(acomminos): use a special heap for texture buffer alignment? ++ addr_offset = offset + bo_addr.addr; ++ ++ if ((addr_offset & (gl_info->limits.texture_buffer_offset_alignment - 1))) ++ { ++ FIXME("Buffer offset %u is not %u byte aligned.\n", ++ offset, gl_info->limits.texture_buffer_offset_alignment); ++ return; ++ } + +- context_bind_texture(context, GL_TEXTURE_BUFFER, view->name); + if (gl_info->supported[ARB_TEXTURE_BUFFER_RANGE]) + { + GL_EXTCALL(glTexBufferRange(GL_TEXTURE_BUFFER, view_format->glInternal, +- buffer->buffer_object, offset, size)); ++ bo_addr.buffer_object, addr_offset, size)); + } + else + { +- if (offset || size != buffer->resource.size) ++ if (addr_offset || size != buffer->resource.size) + FIXME("OpenGL implementation does not support ARB_texture_buffer_range.\n"); +- GL_EXTCALL(glTexBuffer(GL_TEXTURE_BUFFER, view_format->glInternal, buffer->buffer_object)); ++ GL_EXTCALL(glTexBuffer(GL_TEXTURE_BUFFER, view_format->glInternal, bo_addr.buffer_object)); + } +- checkGLcall("Create buffer texture"); ++ checkGLcall("Bind buffer texture"); + +- context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); +- context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); + } + + static void get_buffer_view_range(const struct wined3d_buffer *buffer, +@@ -285,16 +307,6 @@ static void get_buffer_view_range(const struct wined3d_buffer *buffer, + } + } + +-static void create_buffer_view(struct wined3d_gl_view *view, struct wined3d_context *context, +- const struct wined3d_view_desc *desc, struct wined3d_buffer *buffer, +- const struct wined3d_format *view_format) +-{ +- unsigned int offset, size; +- +- get_buffer_view_range(buffer, desc, view_format, &offset, &size); +- create_buffer_texture(view, context, buffer, view_format, offset, size); +-} +- + static void wined3d_view_invalidate_location(struct wined3d_resource *resource, + const struct wined3d_view_desc *desc, DWORD location) + { +@@ -711,11 +723,10 @@ static void wined3d_shader_resource_view_cs_init(void *object) + + if (resource->type == WINED3D_RTYPE_BUFFER) + { +- struct wined3d_buffer *buffer = buffer_from_resource(resource); + struct wined3d_context *context; + + context = context_acquire(resource->device, NULL, 0); +- create_buffer_view(&view->gl_view, context, desc, buffer, view_format); ++ create_buffer_texture(&view->gl_view, context); + context_release(context); + } + else +@@ -814,7 +825,16 @@ void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view + + if (view->gl_view.name) + { ++ // XXX(acomminos): only rebind buffer texture range when needed (i.e. on discards) + context_bind_texture(context, view->gl_view.target, view->gl_view.name); ++ if (view->resource->type == WINED3D_RTYPE_BUFFER) ++ { ++ unsigned int offset, size; ++ struct wined3d_buffer *buffer = buffer_from_resource(view->resource); ++ get_buffer_view_range(buffer, &view->desc, view->format, &offset, &size); ++ bind_buffer_texture(&view->gl_view, context, buffer_from_resource(view->resource), view->format, offset, size); ++ } ++ + wined3d_sampler_bind(sampler, unit, NULL, context); + return; + } +@@ -1092,12 +1112,11 @@ static void wined3d_unordered_access_view_cs_init(void *object) + + if (resource->type == WINED3D_RTYPE_BUFFER) + { +- struct wined3d_buffer *buffer = buffer_from_resource(resource); + struct wined3d_context *context; + + context = context_acquire(resource->device, NULL, 0); + gl_info = context->gl_info; +- create_buffer_view(&view->gl_view, context, desc, buffer, view->format); ++ create_buffer_texture(&view->gl_view, context); + if (desc->flags & (WINED3D_VIEW_BUFFER_COUNTER | WINED3D_VIEW_BUFFER_APPEND)) + { + static const GLuint initial_value = 0; +-- +2.16.2 + 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 deleted file mode 100644 index 89c9c8ec9eda..000000000000 --- a/0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch +++ /dev/null @@ -1,383 +0,0 @@ -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 - diff --git a/0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch b/0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch deleted file mode 100644 index fb80a0f89597..000000000000 --- a/0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch +++ /dev/null @@ -1,305 +0,0 @@ -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 - diff --git a/0008-wined3d-Implement-lazy-free-using-a-deferred-free-li.patch b/0008-wined3d-Implement-lazy-free-using-a-deferred-free-li.patch deleted file mode 100644 index 1597c85366f6..000000000000 --- a/0008-wined3d-Implement-lazy-free-using-a-deferred-free-li.patch +++ /dev/null @@ -1,638 +0,0 @@ -From 831d8bc7117ddb24507bd60f4c9c0df37b4b9699 Mon Sep 17 00:00:00 2001 -From: Andrew Comminos <andrew@comminos.com> -Date: Wed, 28 Feb 2018 22:46:31 -0800 -Subject: [PATCH 8/8] wined3d: Implement lazy-free using a deferred free list. - ---- - dlls/wined3d/buffer_heap.c | 325 ++++++++++++++++++++++++++++------------- - dlls/wined3d/cs.c | 12 +- - dlls/wined3d/device.c | 16 +- - dlls/wined3d/wined3d_private.h | 22 ++- - 4 files changed, 261 insertions(+), 114 deletions(-) - -diff --git a/dlls/wined3d/buffer_heap.c b/dlls/wined3d/buffer_heap.c -index f4af1b93b9..4d90dcf861 100644 ---- a/dlls/wined3d/buffer_heap.c -+++ b/dlls/wined3d/buffer_heap.c -@@ -27,24 +27,20 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d_perf); - - struct wined3d_buffer_heap_element - { -- struct wine_rb_entry entry; - struct wined3d_map_range range; - -+ // rbtree data -+ struct wine_rb_entry entry; -+ BOOL in_tree; -+ - // Binned free list positions - struct wined3d_buffer_heap_element *next; - struct wined3d_buffer_heap_element *prev; - }; - --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_range *ranges; -+ struct wined3d_buffer_heap_bin_set free_list; - struct wined3d_fence *fence; - - struct wined3d_buffer_heap_fenced_element *next; -@@ -53,13 +49,12 @@ struct wined3d_buffer_heap_fenced_element - 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)); -+ elem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct wined3d_buffer_heap_element)); - if (!elem) - return NULL; - elem->range.offset = offset; - elem->range.size = size; -- elem->prev = NULL; -- elem->next = NULL; -+ elem->in_tree = FALSE; - return elem; - } - -@@ -86,27 +81,41 @@ 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) -+// 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_bins[bin]; -- if (heap->free_bins[bin]) -- heap->free_bins[bin]->prev = elem; -- heap->free_bins[bin] = elem; -+ 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); -+} -+ -+// Inserts an elemnet into the free tree. Does not perform coalescing. -+static void element_insert_free_tree(struct wined3d_buffer_heap *heap, struct wined3d_buffer_heap_element *elem) -+{ -+ if (elem->in_tree) -+ { -+ FIXME("Element %p already in free tree, ignoring.\n", elem); -+ return; -+ } - if (wine_rb_put(&heap->free_tree, &elem->range.offset, &elem->entry) == -1) - { - ERR("Failed to insert element into free tree.\n"); -+ return; - } -- -- TRACE("Inserted allocation at %p of size %lld into bin %d\n", elem->range.offset, elem->range.size, bin); -+ TRACE("Inserted allocation at %p of size %lld into free tree\n", elem->range.offset, elem->range.size); -+ elem->in_tree = TRUE; - } - --// Removes an element from the free tree and its 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); -@@ -117,24 +126,31 @@ static void element_remove_free(struct wined3d_buffer_heap *heap, struct wined3d - if (elem->next) - elem->next->prev = elem->prev; - -- if (!elem->prev) -- heap->free_bins[bin] = elem->next; -+ 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; - -- wine_rb_remove(&heap->free_tree, &elem->entry); -+ if (elem->in_tree) -+ { -+ wine_rb_remove(&heap->free_tree, &elem->entry); -+ elem->in_tree = FALSE; -+ } - - 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) -+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(), 0, sizeof(struct wined3d_buffer_heap_fenced_element)); -+ elem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct wined3d_buffer_heap_fenced_element)); - if (!elem) - return NULL; -- elem->ranges = ranges; -+ elem->free_list = bins; - elem->fence = fence; - elem->next = NULL; - return elem; -@@ -163,6 +179,11 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s - - 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; -@@ -194,13 +215,13 @@ HRESULT wined3d_buffer_heap_create(struct wined3d_context *context, GLsizeiptr s - - object->fenced_head = object->fenced_tail = NULL; - object->alignment = alignment; -- object->pending_fenced_bytes = 0; -- object->pending_fenced_head = NULL; -- object->pending_fenced_threshold_bytes = size / 4; // FIXME(acomminos): make this externally declared -+ // FIXME(acomminos): make this externally declared -+ object->pending_fenced_threshold_bytes = 16 * 1024 * 1024; - InitializeCriticalSection(&object->temp_lock); - - initial_elem = element_new(0, size); -- element_insert_free(object, initial_elem); -+ // Don't bother adding the initial allocation to the coalescing tree. -+ element_insert_free_bin(object, initial_elem); - - *buffer_heap = object; - -@@ -217,21 +238,24 @@ 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) - { - int initial_bin; -+ int initial_size = size; -+ - EnterCriticalSection(&heap->temp_lock); - -- // Round to the nearest power of two to reduce fragmentation. -- size = 1ULL << bitwise_log2_ceil(size); -+ // 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); - -- // Round up the size to a multiple of the heap's alignment. -- if (heap->alignment) -+ // Align size values where possible. -+ if (heap->alignment && (size % heap->alignment != 0)) - size += heap->alignment - (size % heap->alignment); - -- // 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 = heap->free_bins[i]; -+ struct wined3d_buffer_heap_element *elem = heap->free_list.bins[i].head; - if (elem) - { - struct wined3d_map_range remaining_range; -@@ -241,13 +265,17 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s - 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(heap, elem); -+ element_insert_free_bin(heap, elem); - } - else - { -@@ -260,68 +288,33 @@ HRESULT wined3d_buffer_heap_alloc(struct wined3d_buffer_heap *heap, GLsizeiptr s - } - - LeaveCriticalSection(&heap->temp_lock); -+ -+ // Attempt to coalesce blocks until an allocation of the requested size is -+ // available. -+ GLsizei coalesced_size; -+ while (SUCCEEDED(wined3d_buffer_heap_deferred_coalesce(heap, &coalesced_size))) -+ { -+ FIXME_(d3d_perf)("Forcing coalesce, not enough free space in buffer heap.\n"); -+ if (coalesced_size >= size) -+ { -+ return wined3d_buffer_heap_alloc(heap, size, out_range); -+ } -+ } -+ - 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; - - if (!elem) - return E_OUTOFMEMORY; - - EnterCriticalSection(&heap->temp_lock); - -- // 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); -- return E_FAIL; -- } -- -- // 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 = coalesced_range.size + left_elem->range.size; -- -- element_remove_free(heap, left_elem); -- HeapFree(GetProcessHeap(), 0, 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(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; -- -- 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); -+ // Only insert the element into a free bin, coalescing will occur later. -+ element_insert_free_bin(heap, elem); - - LeaveCriticalSection(&heap->temp_lock); - -@@ -330,10 +323,21 @@ HRESULT wined3d_buffer_heap_free(struct wined3d_buffer_heap *heap, struct wined3 - - HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct wined3d_device *device, struct wined3d_map_range 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; -+ 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; -+ } - - heap->pending_fenced_bytes += range.size; - if (heap->pending_fenced_bytes >= heap->pending_fenced_threshold_bytes) -@@ -349,13 +353,13 @@ HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct - return hr; - } - -- fenced_elem = fenced_element_new(heap->pending_fenced_head, fence); -+ fenced_elem = fenced_element_new(heap->pending_fenced_bins, fence); - if (!fenced_elem) - return E_OUTOFMEMORY; - - TRACE_(d3d_perf)("Dispatching fenced buffer set.\n"); - heap->pending_fenced_bytes = 0; -- heap->pending_fenced_head = NULL; -+ 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. -@@ -390,15 +394,33 @@ 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_range *range_elem = elem->ranges; -- // FIXME(acomminos): this might take a while. incrementally do this? -- while (range_elem) -+ -+ EnterCriticalSection(&heap->temp_lock); -+ for (int i = 0; i < WINED3D_BUFFER_HEAP_BINS; i++) - { -- 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; -+ 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); - -@@ -413,3 +435,102 @@ HRESULT wined3d_buffer_heap_cs_poll_fences(struct wined3d_buffer_heap *heap, str - - return WINED3D_OK; - } -+ -+HRESULT wined3d_buffer_heap_deferred_coalesce(struct wined3d_buffer_heap *heap, GLsizei *coalesced_size) -+{ -+ struct wined3d_buffer_heap_element *elem = NULL; -+ struct wine_rb_entry *entry; -+ struct wined3d_map_range coalesced_range; -+ -+ // XXX(acomminos): is it always the best idea to coalesce by smallest -+ // chunks? these are the most likely to be useless. -+ 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 && elem == NULL; i++) -+ { -+ struct wined3d_buffer_heap_element *next = heap->free_list.bins[i].head; -+ while (next) -+ { -+ if (next->in_tree == FALSE) -+ { -+ // Find the first element not in-tree. -+ elem = next; -+ break; -+ } -+ next = next->next; -+ } -+ } -+ -+ // TODO(acomminos): acquire a separate lock for the free tree here. -+ if (!elem) -+ { -+ ERR("Failed to find element to coalesce.\n"); -+ LeaveCriticalSection(&heap->temp_lock); -+ return E_FAIL; -+ } -+ element_remove_free(heap, elem); -+ -+ // Remove element from free list, we may change its size or offset. -+ coalesced_range = elem->range; -+ -+ // 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); -+ return E_FAIL; -+ } -+ -+ // 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; -+ -+ element_remove_free(heap, left_elem); -+ HeapFree(GetProcessHeap(), 0, 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(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; -+ -+ element_remove_free(heap, right_elem); -+ HeapFree(GetProcessHeap(), 0, right_elem); -+ } -+ } -+ -+ wine_rb_remove(&heap->free_tree, &elem->entry); -+ -+ if (coalesced_range.size > elem->range.size) -+ FIXME_(d3d_perf)("Coalesced out an extra %lld bytes\n", coalesced_range.size - elem->range.size); -+ -+ // Update with coalesced range. -+ elem->range = coalesced_range; -+ -+ if (coalesced_size) -+ *coalesced_size = coalesced_range.size; -+ -+ element_insert_free_bin(heap, elem); -+ element_insert_free_tree(heap, elem); -+ -+ LeaveCriticalSection(&heap->temp_lock); -+ return WINED3D_OK; -+} -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index bae5d9f4a1..8fd9b01a36 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -2644,10 +2644,6 @@ static void wined3d_cs_exec_discard_buffer(struct wined3d_cs *cs, const void *da - struct wined3d_buffer *buffer = op->buffer; - HRESULT hr; - -- // Poll for discarded buffers whose fenced have been triggered here to avoid -- // excessive VRAM consumption. -- wined3d_buffer_heap_cs_poll_fences(buffer->buffer_heap, cs->device); -- - // TODO(acomminos): should call into buffer.c here instead. - if (FAILED(hr = wined3d_buffer_heap_free_fenced(buffer->buffer_heap, cs->device, buffer->cs_persistent_map))) - { -@@ -2975,6 +2971,14 @@ static void poll_queries(struct wined3d_cs *cs) - list_init(&query->poll_list_entry); - InterlockedIncrement(&query->counter_retrieved); - } -+ -+ // Poll for discarded persistent buffers whose fences have been triggered -+ // here to avoid excessive VRAM consumption. -+ // XXX(acomminos): clean this up, integrate with prior section. -+ if (cs->device->wo_buffer_heap) -+ wined3d_buffer_heap_cs_poll_fences(cs->device->wo_buffer_heap, cs->device); -+ if (cs->device->cb_buffer_heap) -+ wined3d_buffer_heap_cs_poll_fences(cs->device->cb_buffer_heap, cs->device); - } - - static void wined3d_cs_wait_event(struct wined3d_cs *cs) -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index bdab83b935..9f300ca572 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -848,26 +848,32 @@ static void destroy_default_samplers(struct wined3d_device *device, struct wined - /* 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): check if ARB_buffer_storage is supported, first- - // possibly make wined3d_buffer_heap_create fail. -- // TODO(acomminos): 512MB is sane for geometry, maybe not for PBO. -- const GLsizeiptr HBO_SIZE = min(512000000, device->adapter->vram_bytes / 4); -- 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; -+ GLsizeiptr cb_heap_size = 256 * 1024 * 1024; - - GLint ub_alignment; - 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; -+ - HRESULT hr; -- if (FAILED(hr = wined3d_buffer_heap_create(context, HBO_SIZE, 0, TRUE, &device->wo_buffer_heap))) -+ 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); - } - - // TODO(acomminos): can likely use a way smaller heap for CBs by querying limits -- if (FAILED(hr = wined3d_buffer_heap_create(context, HBO_SIZE, ub_alignment, TRUE, &device->cb_buffer_heap))) -+ 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 wine-pba (geo_heap_size: %lld, cb_heap_size: %lld, ub_align: %d)\n", geo_heap_size, cb_heap_size, ub_alignment); - } - - /* Context activation is done by the caller. */ -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 14cad92f0f..3011609ee1 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -3667,11 +3667,21 @@ enum wined3d_buffer_conversion_type - - 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 - -+struct wined3d_buffer_heap_bin -+{ -+ 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 - { -@@ -3680,11 +3690,11 @@ struct wined3d_buffer_heap - GLsizeiptr alignment; - CRITICAL_SECTION temp_lock; // Temporary lock while we implement the fenced free list. - -- struct wined3d_buffer_heap_element *free_bins[WINED3D_BUFFER_HEAP_BINS]; -+ struct wined3d_buffer_heap_bin_set free_list; - 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_range *pending_fenced_head; -+ struct wined3d_buffer_heap_bin_set pending_fenced_bins; - GLsizeiptr pending_fenced_bytes; // Number of free bytes in the active fenced region. - GLsizeiptr pending_fenced_threshold_bytes; // Number of bytes required before fencing. - -@@ -3696,6 +3706,7 @@ struct wined3d_buffer_heap - 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; -@@ -3704,6 +3715,11 @@ HRESULT wined3d_buffer_heap_free_fenced(struct wined3d_buffer_heap *heap, struct - // 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; -+// Performs deferred coalescing of fenced buffers. To be called when the CS -+// thread is idle, or under memory pressure. -+// Outputs the size of the new coalesced region in `coalesced_size`, or an error -+// if there are no remaining elements to be coalesced. -+HRESULT wined3d_buffer_heap_deferred_coalesce(struct wined3d_buffer_heap *heap, GLsizei *coalesced_size) DECLSPEC_HIDDEN; - - struct wined3d_buffer - { --- -2.16.2 - @@ -7,34 +7,34 @@ # Contributor: Giovanni Scafora <giovanni@archlinux.org> pkgname=wine-staging-pba -pkgver=2.21 -pkgrel=2 +pkgver=3.3 +pkgrel=1 _pkgbasever=${pkgver/rc/-rc} -source=("https://github.com/wine-compholio/wine-patched/archive/staging-$_pkgbasever.tar.gz" +source=(https://dl.winehq.org/wine/source/3.x/wine-$_pkgbasever.tar.xz{,.sign} + "wine-staging-v$_pkgbasever.tar.gz::https://github.com/wine-staging/wine-staging/archive/v$_pkgbasever.tar.gz" harmony-fix.diff 30-win32-aliases.conf - "0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch" - "0002-wined3d-Allocate-global-write-only-persistent-buffer.patch" - "0003-wined3d-Add-support-for-persistently-mapped-wined3d_.patch" - "0004-wined3d-Implement-aligned-persistent-heaps-for-persi.patch" - "0005-wined3d-Experimental-buffer-heap-fence-batching-uppe.patch" - "0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch" - "0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch" - "0008-wined3d-Implement-lazy-free-using-a-deferred-free-li.patch") - -sha512sums=('4e3fe2eb81360bfa095194ab5b9647636cbeac0dc3955e6a3ee26062f650c66a4bd2353a1cd8063f9b7c65a6bcc1f892cc7c1d0f00c3c8525a124ec2109d1e86' + wine-binfmt.conf + 0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch + 0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch + 0003-wined3d-Use-ARB_multi_bind-to-speed-up-UBO-updates.patch + 0004-wined3d-Use-GL_CLIENT_STORAGE_BIT-for-persistent-map.patch + 0005-wined3d-Experimental-support-for-persistent-buffer-t.patch) +sha512sums=('c9e4c75e94d745837208bf877b19c4e4e46df1e78082d21e716f52c9f9d93eaabbec8bf34783cda68e4275f53e37929b81ac128e5b8a13c1e5035223b2621d6a' + 'SKIP' + '02d48a9c403b93d01ca37b74af5dc81f86e49c72d67f194c71ccebd4556fa72c473728a1b1f9d5325c6f85f4e41bb7072a1183a2d81cafa8888e00dc53d12166' 'b86edf07bfc560f403fdfd5a71f97930ee2a4c3f76c92cc1a0dbb2e107be9db3bed3a727a0430d8a049583c63dd11f5d4567fb7aa69b193997c6da241acc4f2e' '6e54ece7ec7022b3c9d94ad64bdf1017338da16c618966e8baf398e6f18f80f7b0576edf1d1da47ed77b96d577e4cbb2bb0156b0b11c183a0accf22654b0a2bb' - 'b9141fbe8f5189eb46c83b178497f9ee6d1f2daec3009877557ba28e5f2ce6d818cfef5b0eba15c1e9e4c50dd5950486f8091793d704ec532f82155056725e71' - '8e112e25392fb2bd035c4b8792e43ad86bf81b1c24ff429ff8943a2c02ee761fc25446791475e4115e6b03f50cdb4cf6a8f128cc770c3941b59ee1dfbe79137b' - '7335797924f1c4403a438ccfe36f8a650ddf8271d33ca962e270cf34762170038017cd53cad35f1ad61128f2c496edb68791783259df33cb997a73959136bdc0' - '52ebb56c6adfbef526d2db19618f9155084dacd7600d166f04ba5423c63a4294294589d675c391e577330f1b68755bb5d3b6a2cd3006902269cb73140973dba3' - 'd326b8da8fb02462bac178a23e18f5468de62780717c24eadb453201b2b6b6439d2be7dda38e40f24fdc570dd5bc54102e7bf05868c53b17b27f6b9a06fccdb0' - '04b41d4198138dbfe1399e7ed1e406fb265472d08a3e4de3c5c8584574b167613c598d7fa397c6944b809a96f699a4447694291296fa01a8e07b8ea96026ed2f' - '9f90b7adc0ed87daac0f453caf2fff8b338061d96a9cd890f305704f9b22581232c6a207eb9eb1670c69b083caa780a6e44280df47c95b4e6e8e73f046f7c8a5' - '4b94c8374ecb459c35df9950b8cc4bcac5d4ccb4102e83ea9092de3e387e6f998af2968232816a94b4f21317dca6210a90ab4657f7f940072df7b050a84ad735') + 'bdde7ae015d8a98ba55e84b86dc05aca1d4f8de85be7e4bd6187054bfe4ac83b5a20538945b63fb073caab78022141e9545685e4e3698c97ff173cf30859e285' + 'b68f09aa0688ba52e40dd9a22c99699d28b3e1a7028d1c39e5705cad345e17535d9b1066babf6881668be23ab43ca7ed0203aa5a287ed343ec4383b58358f6ab' + 'e7a1ab3ea00dc257de3dfdeab61df4dcd1ba3b448d3d323a5c7fed7da0b9a0ddb0b00eb6bc3f72b1fc1b10c61e181e8fe4f413a64b59d740371b2852686ce0c8' + '643b7575bd3e5a080c98e4435747942d39a072a662d26aefacec512263889dfda1fa154b77c6323d0cb69b5cab357258906cf17ad5013af09eda3d255706b5fe' + '095ad54ea35f2e8317ab42a24fb92cbc214c6c3b53be165a6ddec9ef31f97b989befac4a3b51a1fcfbf5ead11b0ab3ca57ac34ad41621e81fdaa96aed17815cb' + 'a58ae6201bfab1ddbda4d789054ce384434d4eb5e3d5845e995caa81b41c2814bb625216ce09c0e4bae92e3e6a45771d28ee4ef09b7c587cd56ec17d577a37a8') +validpgpkeys=(5AC1A08B03BD7A313E0A955AF5E6E9EEB9461DD7 + DA23579A74D4AD9AF9D3F945CEFAC8EAAF17519D) pkgdesc="A compatibility layer for running Windows programs - Staging branch" url="http://www.wine-staging.com" @@ -42,7 +42,7 @@ arch=(x86_64) options=(staticlibs) license=(LGPL) -_depends=( +depends=( attr lib32-attr fontconfig lib32-fontconfig lcms2 lib32-lcms2 @@ -83,6 +83,8 @@ makedepends=(autoconf ncurses bison perl fontforge flex libva lib32-libva gtk3 lib32-gtk3 gst-plugins-base-libs lib32-gst-plugins-base-libs + vulkan-icd-loader lib32-vulkan-icd-loader + sdl2 lib32-sdl2 samba opencl-headers ) @@ -108,27 +110,23 @@ optdepends=( gtk3 lib32-gtk3 gst-plugins-base-libs lib32-gst-plugins-base-libs vulkan-icd-loader lib32-vulkan-icd-loader + sdl2 lib32-sdl2 cups samba dosbox ) -if [[ $CARCH == i686 ]]; then - # Strip lib32 etc. on i686 - _depends=(${_depends[@]/*32-*/}) - makedepends=(${makedepends[@]/*32-*/} ${_depends[@]}) - makedepends=(${makedepends[@]/*-multilib*/}) - optdepends=(${optdepends[@]/*32-*/}) - provides=("wine=$pkgver") - conflicts=('wine' 'wine-staging') -else - makedepends=(${makedepends[@]} ${_depends[@]}) - provides=("wine=$pkgver" "wine-wow64=$pkgver") - conflicts=('wine' 'wine-wow64' 'wine-staging') -fi +provides=("wine=$pkgver" "wine-wow64=$pkgver") +conflicts=('wine' 'wine-wow64' 'wine-staging') +install=wine.install prepare() { # Allow ccache to work - mv wine-patched-staging-$_pkgbasever $pkgname + mv wine-$_pkgbasever $pkgname + + # apply wine-staging patchset + pushd wine-staging-$_pkgbasever/patches + ./patchinstall.sh DESTDIR="$srcdir/$pkgname" --all + popd # https://bugs.winehq.org/show_bug.cgi?id=43530 export CFLAGS="${CFLAGS/-fno-plt/}" @@ -136,84 +134,69 @@ prepare() { patch -d $pkgname -Np1 < harmony-fix.diff - patch -d $pkgname -Np1 < 0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch - patch -d $pkgname -Np1 < 0002-wined3d-Allocate-global-write-only-persistent-buffer.patch - patch -d $pkgname -Np1 < 0003-wined3d-Add-support-for-persistently-mapped-wined3d_.patch - patch -d $pkgname -Np1 < 0004-wined3d-Implement-aligned-persistent-heaps-for-persi.patch - patch -d $pkgname -Np1 < 0005-wined3d-Experimental-buffer-heap-fence-batching-uppe.patch - patch -d $pkgname -Np1 < 0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch - patch -d $pkgname -Np1 < 0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch - patch -d $pkgname -Np1 < 0008-wined3d-Implement-lazy-free-using-a-deferred-free-li.patch + patch -d $pkgname -Np1 < 0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch + patch -d $pkgname -Np1 < 0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch + patch -d $pkgname -Np1 < 0003-wined3d-Use-ARB_multi_bind-to-speed-up-UBO-updates.patch + patch -d $pkgname -Np1 < 0004-wined3d-Use-GL_CLIENT_STORAGE_BIT-for-persistent-map.patch + patch -d $pkgname -Np1 < 0005-wined3d-Experimental-support-for-persistent-buffer-t.patch sed 's|OpenCL/opencl.h|CL/opencl.h|g' -i $pkgname/configure* # Get rid of old build dirs rm -rf $pkgname-{32,64}-build - mkdir $pkgname-32-build + mkdir $pkgname-{32,64}-build } build() { cd "$srcdir" - if [[ $CARCH == x86_64 ]]; then - msg2 "Building Wine-64..." - - mkdir $pkgname-64-build - cd "$srcdir/$pkgname-64-build" - ../$pkgname/configure \ - --prefix=/usr \ - --libdir=/usr/lib \ - --with-x \ - --with-gstreamer \ - --enable-win64 \ - --with-xattr + msg2 "Building Wine-64..." - make - - _wine32opts=( - --libdir=/usr/lib32 - --with-wine64="$srcdir/$pkgname-64-build" - ) + cd "$srcdir/$pkgname-64-build" + ../$pkgname/configure \ + --prefix=/usr \ + --libdir=/usr/lib \ + --with-x \ + --with-gstreamer \ + --enable-win64 \ + --with-xattr - export PKG_CONFIG_PATH="/usr/lib32/pkgconfig" - fi + make msg2 "Building Wine-32..." + + export PKG_CONFIG_PATH="/usr/lib32/pkgconfig" cd "$srcdir/$pkgname-32-build" ../$pkgname/configure \ --prefix=/usr \ --with-x \ --with-gstreamer \ --with-xattr \ - "${_wine32opts[@]}" + --libdir=/usr/lib32 \ + --with-wine64="$srcdir/$pkgname-64-build" make } package() { - depends=(${_depends[@]}) - msg2 "Packaging Wine-32..." cd "$srcdir/$pkgname-32-build" - if [[ $CARCH == i686 ]]; then - make prefix="$pkgdir/usr" install - else - make prefix="$pkgdir/usr" \ - libdir="$pkgdir/usr/lib32" \ - dlldir="$pkgdir/usr/lib32/wine" install + make prefix="$pkgdir/usr" \ + libdir="$pkgdir/usr/lib32" \ + dlldir="$pkgdir/usr/lib32/wine" install - msg2 "Packaging Wine-64..." - cd "$srcdir/$pkgname-64-build" - make prefix="$pkgdir/usr" \ - libdir="$pkgdir/usr/lib" \ - dlldir="$pkgdir/usr/lib/wine" install - fi + msg2 "Packaging Wine-64..." + cd "$srcdir/$pkgname-64-build" + make prefix="$pkgdir/usr" \ + libdir="$pkgdir/usr/lib" \ + dlldir="$pkgdir/usr/lib/wine" install # Font aliasing settings for Win32 applications install -d "$pkgdir"/etc/fonts/conf.{avail,d} install -m644 "$srcdir/30-win32-aliases.conf" "$pkgdir/etc/fonts/conf.avail" ln -s ../conf.avail/30-win32-aliases.conf "$pkgdir/etc/fonts/conf.d/30-win32-aliases.conf" + install -Dm 644 "$srcdir/wine-binfmt.conf" "$pkgdir/usr/lib/binfmt.d/wine.conf" } # vim:set ts=8 sts=2 sw=2 et: diff --git a/wine-binfmt.conf b/wine-binfmt.conf new file mode 100644 index 000000000000..4d4307336587 --- /dev/null +++ b/wine-binfmt.conf @@ -0,0 +1,2 @@ +# Start WINE on Windows executables +:DOSWin:M::MZ::/usr/bin/wine: diff --git a/wine.install b/wine.install new file mode 100644 index 000000000000..cbe10cc59dc7 --- /dev/null +++ b/wine.install @@ -0,0 +1,7 @@ +post_install() { + echo "Run 'systemctl restart systemd-binfmt' in order to make the wine binfmt available on your system." +} + +post_remove() { + echo "binfmt binary formats will be updated at reboot" +} |