[PATCH 3/6] ddraw: Keep a ddraw object reference in d3d7 vertex buffers.

Matteo Bruni mbruni at codeweavers.com
Tue Feb 7 15:08:41 CST 2017


Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
---
For bug 38307. With this it doesn't crash anymore for me but it still
fails with a "Runtime Error : ERROR 10. " messagebox a bit later.

 dlls/ddraw/ddraw.c        |  1 +
 dlls/ddraw/tests/ddraw4.c | 51 ++++++++++++++++++++++++++++++++++++++++
 dlls/ddraw/tests/ddraw7.c | 50 +++++++++++++++++++++++++++++++++++++++
 dlls/ddraw/vertexbuffer.c | 60 ++++++++++++++++++++++++-----------------------
 4 files changed, 133 insertions(+), 29 deletions(-)

diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index a0865c0..84ece18 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -4253,6 +4253,7 @@ static HRESULT WINAPI d3d7_CreateVertexBuffer(IDirect3D7 *iface, D3DVERTEXBUFFER
     {
         TRACE("Created vertex buffer %p.\n", object);
         *vertex_buffer = &object->IDirect3DVertexBuffer7_iface;
+        IDirectDraw7_AddRef(&ddraw->IDirectDraw7_iface);
     }
     else
         WARN("Failed to create vertex buffer, hr %#x.\n", hr);
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 0693dbc..32298c6 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -12772,6 +12772,56 @@ static void test_surface_desc_size(void)
     ok(!refcount, "DirectDraw has %u references left.\n", refcount);
 }
 
+static void test_vb_refcount(void)
+{
+    ULONG prev_d3d_refcount, prev_device_refcount;
+    ULONG cur_d3d_refcount, cur_device_refcount;
+    D3DVERTEXBUFFERDESC vb_desc;
+    IDirect3DVertexBuffer *vb;
+    IDirect3DDevice3 *device;
+    IDirect3D3 *d3d;
+    HWND window;
+    HRESULT hr;
+
+    window = CreateWindowA("static", "d3d3_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    if (!(device = create_device(window, DDSCL_NORMAL)))
+    {
+        skip("Failed to create a 3D device, skipping test.\n");
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
+    ok(SUCCEEDED(hr), "Failed to get Direct3D3 interface, hr %#x.\n", hr);
+
+    IDirect3D3_AddRef(d3d);
+    prev_d3d_refcount = IDirect3D3_Release(d3d);
+    IDirect3DDevice3_AddRef(device);
+    prev_device_refcount = IDirect3DDevice3_Release(device);
+
+    memset(&vb_desc, 0, sizeof(vb_desc));
+    vb_desc.dwSize = sizeof(vb_desc);
+    vb_desc.dwFVF = D3DFVF_XYZ;
+    vb_desc.dwNumVertices = 4;
+    hr = IDirect3D3_CreateVertexBuffer(d3d, &vb_desc, &vb, 0, NULL);
+    ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
+
+    IDirect3D3_AddRef(d3d);
+    cur_d3d_refcount = IDirect3D3_Release(d3d);
+    IDirect3DDevice3_AddRef(device);
+    cur_device_refcount = IDirect3DDevice3_Release(device);
+    ok(cur_d3d_refcount == prev_d3d_refcount, "D3D object refcount changed from %u to %u.\n",
+            prev_d3d_refcount, cur_d3d_refcount);
+    ok(cur_device_refcount == prev_device_refcount, "D3D device refcount changed from %u to %u.\n",
+            prev_device_refcount, cur_device_refcount);
+
+    IDirect3DVertexBuffer_Release(vb);
+    IDirect3D3_Release(d3d);
+    IDirect3DDevice3_Release(device);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw4)
 {
     IDirectDraw4 *ddraw;
@@ -12874,4 +12924,5 @@ START_TEST(ddraw4)
     test_transform_vertices();
     test_display_mode_surface_pixel_format();
     test_surface_desc_size();
+    test_vb_refcount();
 }
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 0f44d3c..aa20703 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -12445,6 +12445,55 @@ static void test_surface_desc_size(void)
     ok(!refcount, "DirectDraw has %u references left.\n", refcount);
 }
 
+static void test_vb_refcount(void)
+{
+    ULONG prev_d3d_refcount, prev_device_refcount;
+    ULONG cur_d3d_refcount, cur_device_refcount;
+    D3DVERTEXBUFFERDESC vb_desc;
+    IDirect3DVertexBuffer7 *vb;
+    IDirect3DDevice7 *device;
+    IDirect3D7 *d3d;
+    HWND window;
+    HRESULT hr;
+
+    window = CreateWindowA("static", "d3d7_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    if (!(device = create_device(window, DDSCL_NORMAL)))
+    {
+        skip("Failed to create a 3D device, skipping test.\n");
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
+    ok(SUCCEEDED(hr), "Failed to get Direct3D7 interface, hr %#x.\n", hr);
+
+    IDirect3D7_AddRef(d3d);
+    prev_d3d_refcount = IDirect3D7_Release(d3d);
+    IDirect3DDevice7_AddRef(device);
+    prev_device_refcount = IDirect3DDevice7_Release(device);
+
+    memset(&vb_desc, 0, sizeof(vb_desc));
+    vb_desc.dwSize = sizeof(vb_desc);
+    vb_desc.dwFVF = D3DFVF_XYZ;
+    vb_desc.dwNumVertices = 4;
+    hr = IDirect3D7_CreateVertexBuffer(d3d, &vb_desc, &vb, 0);
+    ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#x.\n", hr);
+
+    IDirect3D7_AddRef(d3d);
+    cur_d3d_refcount = IDirect3D7_Release(d3d);
+    IDirect3DDevice7_AddRef(device);
+    cur_device_refcount = IDirect3DDevice7_Release(device);
+    ok(cur_d3d_refcount > prev_d3d_refcount, "D3D object refcount didn't change from %u.\n", prev_d3d_refcount);
+    ok(cur_device_refcount == prev_device_refcount, "D3D device refcount changed from %u to %u.\n",
+            prev_device_refcount, cur_device_refcount);
+
+    IDirect3DVertexBuffer7_Release(vb);
+    IDirect3D7_Release(d3d);
+    IDirect3DDevice7_Release(device);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw7)
 {
     HMODULE module = GetModuleHandleA("ddraw.dll");
@@ -12557,4 +12606,5 @@ START_TEST(ddraw7)
     test_edge_antialiasing_blending();
     test_display_mode_surface_pixel_format();
     test_surface_desc_size();
+    test_vb_refcount();
 }
diff --git a/dlls/ddraw/vertexbuffer.c b/dlls/ddraw/vertexbuffer.c
index 797afe2..7914805e 100644
--- a/dlls/ddraw/vertexbuffer.c
+++ b/dlls/ddraw/vertexbuffer.c
@@ -126,16 +126,26 @@ static ULONG WINAPI d3d_vertex_buffer1_AddRef(IDirect3DVertexBuffer *iface)
     return d3d_vertex_buffer7_AddRef(&buffer->IDirect3DVertexBuffer7_iface);
 }
 
+static void d3d_vertex_buffer_destroy(struct d3d_vertex_buffer *buffer)
+{
+    struct wined3d_buffer *vb = NULL;
+    UINT offset, stride;
+
+    /* D3D7 vertex buffers don't stay bound in the device, they are passed
+     * as a parameter to DrawPrimitiveVB. DrawPrimitiveVB sets them as the
+     * stream source in wined3d and they should get unset there before
+     * they are destroyed. */
+    wined3d_mutex_lock();
+    wined3d_device_get_stream_source(buffer->ddraw->wined3d_device,
+            0, &vb, &offset, &stride);
+    if (vb == buffer->wined3d_buffer)
+        wined3d_device_set_stream_source(buffer->ddraw->wined3d_device, 0, NULL, 0, 0);
+
+    wined3d_vertex_declaration_decref(buffer->wined3d_declaration);
+    wined3d_buffer_decref(buffer->wined3d_buffer);
+    wined3d_mutex_unlock();
+}
 
-/*****************************************************************************
- * IDirect3DVertexBuffer7::Release
- *
- * Release for Vertex Buffers
- *
- * Returns:
- *  The new refcount
- *
- *****************************************************************************/
 static ULONG WINAPI d3d_vertex_buffer7_Release(IDirect3DVertexBuffer7 *iface)
 {
     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer7(iface);
@@ -143,38 +153,30 @@ static ULONG WINAPI d3d_vertex_buffer7_Release(IDirect3DVertexBuffer7 *iface)
 
     TRACE("%p decreasing refcount to %u.\n", buffer, ref);
 
-    if (ref == 0)
+    if (!ref)
     {
-        struct wined3d_buffer *curVB = NULL;
-        UINT offset, stride;
-
-        /* D3D7 Vertex buffers don't stay bound in the device, they are passed
-         * as a parameter to drawPrimitiveVB. DrawPrimitiveVB sets them as the
-         * stream source in wined3d, and they should get unset there before
-         * they are destroyed. */
-        wined3d_mutex_lock();
-        wined3d_device_get_stream_source(buffer->ddraw->wined3d_device,
-                0, &curVB, &offset, &stride);
-        if (curVB == buffer->wined3d_buffer)
-            wined3d_device_set_stream_source(buffer->ddraw->wined3d_device, 0, NULL, 0, 0);
-
-        wined3d_vertex_declaration_decref(buffer->wined3d_declaration);
-        wined3d_buffer_decref(buffer->wined3d_buffer);
-        wined3d_mutex_unlock();
+        d3d_vertex_buffer_destroy(buffer);
+        IDirectDraw7_Release(&buffer->ddraw->IDirectDraw7_iface);
 
         HeapFree(GetProcessHeap(), 0, buffer);
     }
-
     return ref;
 }
 
 static ULONG WINAPI d3d_vertex_buffer1_Release(IDirect3DVertexBuffer *iface)
 {
     struct d3d_vertex_buffer *buffer = impl_from_IDirect3DVertexBuffer(iface);
+    ULONG ref = InterlockedDecrement(&buffer->ref);
 
-    TRACE("iface %p.\n", iface);
+    TRACE("%p decreasing refcount to %u.\n", buffer, ref);
 
-    return d3d_vertex_buffer7_Release(&buffer->IDirect3DVertexBuffer7_iface);
+    if (!ref)
+    {
+        d3d_vertex_buffer_destroy(buffer);
+
+        HeapFree(GetProcessHeap(), 0, buffer);
+    }
+    return ref;
 }
 
 /*****************************************************************************
-- 
2.10.2




More information about the wine-patches mailing list