[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