summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Schmidt2018-03-07 18:20:55 +0100
committerStefan Schmidt2018-03-07 18:20:55 +0100
commit9cc0c1987f64a4f538e747058b53e37f4548d8f4 (patch)
tree2bac1b3e58a4e2857e5cc32d30cbe1a3423b94d6
parent8f3ed8701334e289a8a98b275825044cecab9277 (diff)
downloadaur-9cc0c1987f64a4f538e747058b53e37f4548d8f4.tar.gz
Updated to wine-staging 3.3 and commit b33e274f894de751f9abe2e09aec5bc9d1e6b992
-rw-r--r--.SRCINFO140
-rw-r--r--0001-wined3d-Implement-a-simple-heap-allocator-backed-by-.patch456
-rw-r--r--0001-wined3d-Initial-implementation-of-a-persistent-mappe.patch806
-rw-r--r--0002-wined3d-Add-support-for-backing-dynamic-wined3d_buff.patch (renamed from 0003-wined3d-Add-support-for-persistently-mapped-wined3d_.patch)337
-rw-r--r--0002-wined3d-Allocate-global-write-only-persistent-buffer.patch81
-rw-r--r--0003-wined3d-Use-ARB_multi_bind-to-speed-up-UBO-updates.patch121
-rw-r--r--0004-wined3d-Implement-aligned-persistent-heaps-for-persi.patch240
-rw-r--r--0004-wined3d-Use-GL_CLIENT_STORAGE_BIT-for-persistent-map.patch26
-rw-r--r--0005-wined3d-Experimental-buffer-heap-fence-batching-uppe.patch455
-rw-r--r--0005-wined3d-Experimental-support-for-persistent-buffer-t.patch180
-rw-r--r--0006-wined3d-Switch-wined3d_buffer_heap-to-be-backed-by-a.patch383
-rw-r--r--0007-wined3d-Add-segregated-free-bins-to-complement-rbtre.patch305
-rw-r--r--0008-wined3d-Implement-lazy-free-using-a-deferred-free-li.patch638
-rw-r--r--PKGBUILD143
-rw-r--r--wine-binfmt.conf2
-rw-r--r--wine.install7
16 files changed, 1424 insertions, 2896 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 645d5a8b22a..a34f6540a08 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -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 565b172be92..00000000000
--- 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 00000000000..365dd861d14
--- /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 5a3a499ab2a..cb910a25df4 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 66e2e25d69f..00000000000
--- 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 00000000000..b0de3a7183e
--- /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 7b4a9e43348..00000000000
--- 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 00000000000..45c7ada812c
--- /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 cac70eac997..00000000000
--- 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 00000000000..a039c7e622c
--- /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 89c9c8ec9ed..00000000000
--- 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 fb80a0f8959..00000000000
--- 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 1597c85366f..00000000000
--- 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
-
diff --git a/PKGBUILD b/PKGBUILD
index 0a227025023..b0a0fa5dd49 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -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 00000000000..4d430733658
--- /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 00000000000..cbe10cc59dc
--- /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"
+}