Zebediah Figura : d3d8: Upload sysmem vertex buffers into the streaming buffer in d3d8_device_DrawPrimitive().

Alexandre Julliard julliard at winehq.org
Wed Jul 13 16:54:56 CDT 2022


Module: wine
Branch: master
Commit: fc0f0090f6ba24cc68d2b04503977fbcebc1f96d
URL:    https://gitlab.winehq.org/wine/wine/-/commit/fc0f0090f6ba24cc68d2b04503977fbcebc1f96d

Author: Zebediah Figura <zfigura at codeweavers.com>
Date:   Thu Jul  7 18:40:17 2022 -0500

d3d8: Upload sysmem vertex buffers into the streaming buffer in d3d8_device_DrawPrimitive().

Bloodrayne: Terminal Cut (and Bloodrayne 2: Terminal Cut, and probably other
games in the series) streams from a SYSTEMMEM index buffer, updating it and
drawing from it every frame. This is currently slow on Wine, since each map
needs to wait for the previous upload (on the CS) to complete.

There are a few ways to avoid waiting, but this patch takes the approach of
effectively uploading from the SYSTEMMEM buffer on the client side, while using
a dynamic buffer to avoid client/CS synchronization. This brings performance
from 20-30 FPS to a (locked) 60, on NVidia GL drivers.

---

 dlls/d3d8/buffer.c       | 29 ++++-----------------
 dlls/d3d8/d3d8_private.h |  2 +-
 dlls/d3d8/device.c       | 65 ++++++++++++++++++++++++++++--------------------
 3 files changed, 44 insertions(+), 52 deletions(-)

diff --git a/dlls/d3d8/buffer.c b/dlls/d3d8/buffer.c
index 0692dbde6e7..463ea93e17c 100644
--- a/dlls/d3d8/buffer.c
+++ b/dlls/d3d8/buffer.c
@@ -377,10 +377,7 @@ static ULONG WINAPI d3d8_indexbuffer_AddRef(IDirect3DIndexBuffer8 *iface)
     if (refcount == 1)
     {
         IDirect3DDevice8_AddRef(buffer->parent_device);
-        if (buffer->draw_buffer)
-            wined3d_buffer_incref(buffer->draw_buffer);
-        else
-            wined3d_buffer_incref(buffer->wined3d_buffer);
+        wined3d_buffer_incref(buffer->wined3d_buffer);
     }
 
     return refcount;
@@ -395,13 +392,9 @@ static ULONG WINAPI d3d8_indexbuffer_Release(IDirect3DIndexBuffer8 *iface)
 
     if (!refcount)
     {
-        struct wined3d_buffer *draw_buffer = buffer->draw_buffer;
         IDirect3DDevice8 *device = buffer->parent_device;
 
-        if (draw_buffer)
-            wined3d_buffer_decref(draw_buffer);
-        else
-            wined3d_buffer_decref(buffer->wined3d_buffer);
+        wined3d_buffer_decref(buffer->wined3d_buffer);
 
         /* Release the device last, as it may cause the device to be destroyed. */
         IDirect3DDevice8_Release(device);
@@ -584,8 +577,6 @@ static void STDMETHODCALLTYPE d3d8_indexbuffer_wined3d_object_destroyed(void *pa
 {
     struct d3d8_indexbuffer *buffer = parent;
 
-    if (buffer->draw_buffer)
-        wined3d_buffer_decref(buffer->wined3d_buffer);
     d3d8_resource_cleanup(&buffer->resource);
     heap_free(buffer);
 }
@@ -598,7 +589,6 @@ static const struct wined3d_parent_ops d3d8_indexbuffer_wined3d_parent_ops =
 HRESULT indexbuffer_init(struct d3d8_indexbuffer *buffer, struct d3d8_device *device,
         UINT size, DWORD usage, D3DFORMAT format, D3DPOOL pool)
 {
-    const struct wined3d_parent_ops *parent_ops = &d3d8_null_wined3d_parent_ops;
     struct wined3d_buffer_desc desc;
     HRESULT hr;
 
@@ -620,26 +610,17 @@ HRESULT indexbuffer_init(struct d3d8_indexbuffer *buffer, struct d3d8_device *de
     desc.structure_byte_stride = 0;
 
     if (desc.access & WINED3D_RESOURCE_ACCESS_GPU)
-    {
         desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
-        parent_ops = &d3d8_indexbuffer_wined3d_parent_ops;
-    }
 
     buffer->IDirect3DIndexBuffer8_iface.lpVtbl = &d3d8_indexbuffer_vtbl;
     d3d8_resource_init(&buffer->resource);
     buffer->format = wined3dformat_from_d3dformat(format);
     buffer->usage = usage;
+    buffer->sysmem = !(desc.access & WINED3D_RESOURCE_ACCESS_GPU);
 
     wined3d_mutex_lock();
-    hr = wined3d_buffer_create(device->wined3d_device, &desc, NULL, buffer, parent_ops, &buffer->wined3d_buffer);
-    if (SUCCEEDED(hr) && !(desc.access & WINED3D_RESOURCE_ACCESS_GPU))
-    {
-        desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
-        desc.access = WINED3D_RESOURCE_ACCESS_GPU;
-        if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc, NULL, buffer,
-                &d3d8_indexbuffer_wined3d_parent_ops, &buffer->draw_buffer)))
-            wined3d_buffer_decref(buffer->wined3d_buffer);
-    }
+    hr = wined3d_buffer_create(device->wined3d_device, &desc, NULL, buffer,
+            &d3d8_indexbuffer_wined3d_parent_ops, &buffer->wined3d_buffer);
     wined3d_mutex_unlock();
     if (FAILED(hr))
     {
diff --git a/dlls/d3d8/d3d8_private.h b/dlls/d3d8/d3d8_private.h
index 33238e19b1a..da701a2a8d3 100644
--- a/dlls/d3d8/d3d8_private.h
+++ b/dlls/d3d8/d3d8_private.h
@@ -229,9 +229,9 @@ struct d3d8_indexbuffer
     struct d3d8_resource resource;
     struct wined3d_buffer *wined3d_buffer;
     IDirect3DDevice8 *parent_device;
-    struct wined3d_buffer *draw_buffer;
     enum wined3d_format_id format;
     DWORD usage;
+    bool sysmem;
 };
 
 HRESULT indexbuffer_init(struct d3d8_indexbuffer *buffer, struct d3d8_device *device,
diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c
index 269ddda17cf..068f53d8fdf 100644
--- a/dlls/d3d8/device.c
+++ b/dlls/d3d8/device.c
@@ -913,7 +913,7 @@ static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource)
         if (desc.bind_flags & WINED3D_BIND_INDEX_BUFFER)
         {
             index_buffer = wined3d_resource_get_parent(resource);
-            if (index_buffer && index_buffer->draw_buffer)
+            if (index_buffer && index_buffer->sysmem)
                 return D3D_OK;
         }
 
@@ -2452,34 +2452,41 @@ static void d3d8_device_upload_sysmem_vertex_buffers(struct d3d8_device *device,
     }
 }
 
-static void d3d8_device_upload_sysmem_index_buffer(struct d3d8_device *device,
-        unsigned int start_idx, unsigned int idx_count)
+static HRESULT d3d8_device_upload_sysmem_index_buffer(struct d3d8_device *device,
+        unsigned int *start_idx, unsigned int idx_count)
 {
     const struct wined3d_stateblock_state *state = device->stateblock_state;
-    struct wined3d_box box = {0, 0, 0, 1, 0, 1};
-    struct wined3d_resource *dst_resource;
-    struct d3d8_indexbuffer *d3d8_buffer;
-    struct wined3d_buffer *dst_buffer;
-    struct wined3d_resource_desc desc;
-    enum wined3d_format_id format;
-    unsigned int idx_size;
+    unsigned int src_offset, idx_size, buffer_size, pos;
+    struct wined3d_resource_desc resource_desc;
+    struct wined3d_resource *index_buffer;
+    struct wined3d_map_desc map_desc;
+    struct wined3d_box box;
     HRESULT hr;
 
     if (!device->sysmem_ib)
-        return;
+        return S_OK;
 
-    dst_buffer = state->index_buffer;
-    format = state->index_format;
-    d3d8_buffer = wined3d_buffer_get_parent(dst_buffer);
-    dst_resource = wined3d_buffer_get_resource(dst_buffer);
-    wined3d_resource_get_desc(dst_resource, &desc);
-    idx_size = format == WINED3DFMT_R16_UINT ? 2 : 4;
-    box.left = start_idx * idx_size;
-    box.right = min(box.left + idx_count * idx_size, desc.size);
-    if (FAILED(hr = wined3d_device_context_copy_sub_resource_region(device->immediate_context,
-            dst_resource, 0, box.left, 0, 0,
-            wined3d_buffer_get_resource(d3d8_buffer->wined3d_buffer), 0, &box, 0)))
-        ERR("Failed to update buffer.\n");
+    index_buffer = wined3d_buffer_get_resource(state->index_buffer);
+    wined3d_resource_get_desc(index_buffer, &resource_desc);
+    idx_size = (state->index_format == WINED3DFMT_R16_UINT) ? 2 : 4;
+
+    src_offset = (*start_idx) * idx_size;
+    buffer_size = min(idx_count * idx_size, resource_desc.size - src_offset);
+
+    wined3d_box_set(&box, src_offset, 0, buffer_size, 1, 0, 1);
+    if (FAILED(hr = wined3d_resource_map(index_buffer, 0, &map_desc, &box, WINED3D_MAP_READ)))
+    {
+        wined3d_mutex_unlock();
+        return hr;
+    }
+    wined3d_streaming_buffer_upload(device->wined3d_device, &device->index_buffer,
+            map_desc.data, buffer_size, idx_size, &pos);
+    wined3d_resource_unmap(index_buffer, 0);
+
+    wined3d_device_context_set_index_buffer(device->immediate_context,
+            device->index_buffer.buffer, state->index_format, pos);
+    *start_idx = 0;
+    return S_OK;
 }
 
 static HRESULT WINAPI d3d8_device_DrawPrimitive(IDirect3DDevice8 *iface,
@@ -2510,6 +2517,7 @@ static HRESULT WINAPI d3d8_device_DrawIndexedPrimitive(IDirect3DDevice8 *iface,
     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
     unsigned int index_count;
     int base_vertex_index;
+    HRESULT hr;
 
     TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, start_idx %u, primitive_count %u.\n",
             iface, primitive_type, min_vertex_idx, vertex_count, start_idx, primitive_count);
@@ -2524,11 +2532,16 @@ static HRESULT WINAPI d3d8_device_DrawIndexedPrimitive(IDirect3DDevice8 *iface,
     }
     base_vertex_index = device->stateblock_state->base_vertex_index;
     d3d8_device_upload_sysmem_vertex_buffers(device, base_vertex_index + min_vertex_idx, vertex_count);
-    d3d8_device_upload_sysmem_index_buffer(device, start_idx, index_count);
     wined3d_device_context_set_primitive_type(device->immediate_context,
             wined3d_primitive_type_from_d3d(primitive_type), 0);
     wined3d_device_apply_stateblock(device->wined3d_device, device->state);
+    if (FAILED(hr = d3d8_device_upload_sysmem_index_buffer(device, &start_idx, index_count)))
+    {
+        wined3d_mutex_unlock();
+        return hr;
+    }
     wined3d_device_context_draw_indexed(device->immediate_context, base_vertex_index, start_idx, index_count, 0, 0);
+
     wined3d_mutex_unlock();
 
     return D3D_OK;
@@ -3022,8 +3035,6 @@ static HRESULT WINAPI d3d8_device_SetIndices(IDirect3DDevice8 *iface,
 
     if (!ib)
         wined3d_buffer = NULL;
-    else if (ib->draw_buffer)
-        wined3d_buffer = ib->draw_buffer;
     else
         wined3d_buffer = ib->wined3d_buffer;
 
@@ -3037,7 +3048,7 @@ static HRESULT WINAPI d3d8_device_SetIndices(IDirect3DDevice8 *iface,
     wined3d_stateblock_set_base_vertex_index(device->update_state, base_vertex_idx);
     wined3d_stateblock_set_index_buffer(device->update_state, wined3d_buffer, ib ? ib->format : WINED3DFMT_UNKNOWN);
     if (!device->recording)
-        device->sysmem_ib = ib && ib->draw_buffer;
+        device->sysmem_ib = ib && ib->sysmem;
     wined3d_mutex_unlock();
 
     return D3D_OK;




More information about the wine-cvs mailing list