Hello,
This patch increases the reference count of a DirectDraw object when a Surface 
is created, like Windows does. It also adds a test which tests this 
functionality.

This time with the !FAILED() -> SUCCEEDED() suggestion from  
Robert Shearman. I kept adding a secound refcount in case of DDSCAPS_TEXTURE 
surfaces to achieve more compatiblity with Windows.

Stefan
Index: dlls/ddraw/ddraw_main.c
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/ddraw_main.c,v
retrieving revision 1.9
diff -u -r1.9 ddraw_main.c
--- dlls/ddraw/ddraw_main.c	12 Sep 2005 14:12:47 -0000	1.9
+++ dlls/ddraw/ddraw_main.c	19 Sep 2005 12:57:07 -0000
@@ -697,8 +697,10 @@
     }
     else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
     {
-	/* create texture */
+	/* create texture. This increases the DD refcount by 2 */
 	hr = create_texture(This, pDDSD, ppSurf, pUnkOuter);
+	if(SUCCEEDED(hr))
+		IDirectDraw7_AddRef(iface); /* Plus the increase at the end of the function */
     }
     else if ( (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) &&
 	     !(pDDSD->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN)) /* Support DDSCAPS_SYSTEMMEMORY */
@@ -724,6 +726,9 @@
 	return hr;
     }
 
+    /* Finally, increase the reference count of the DD interface */
+    IDirectDraw7_AddRef(iface);
+
     return DD_OK;
 }
 
Index: dlls/ddraw/surface_main.c
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/surface_main.c,v
retrieving revision 1.5
diff -u -r1.5 surface_main.c
--- dlls/ddraw/surface_main.c	12 Sep 2005 14:12:47 -0000	1.5
+++ dlls/ddraw/surface_main.c	19 Sep 2005 12:57:10 -0000
@@ -124,6 +124,8 @@
 {
     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
     ULONG ref = InterlockedDecrement(&This->ref);
+    LPDIRECTDRAW7 lpDD = (LPDIRECTDRAW7) This->ddraw_owner;
+    DWORD dwCaps = This->surface_desc.ddsCaps.dwCaps;
 
     TRACE("(%p)->(): decreasing from %ld\n", This, ref + 1);
     
@@ -133,6 +135,12 @@
 	    This->aux_release(This->aux_ctx, This->aux_data);
 	Main_DirectDrawSurface_Destroy(This);
 
+        /* Release the DirectDraw owner */
+        IDirectDraw7_Release(lpDD);
+        /* A secound release for DDSCAPS_TEXTURE surfaces */
+        if(dwCaps & DDSCAPS_TEXTURE)
+            IDirectDraw7_Release(lpDD);
+
 	TRACE("released surface %p\n", This);
 	
 	return 0;
Index: dlls/ddraw/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/tests/Makefile.in,v
retrieving revision 1.5
diff -u -r1.5 Makefile.in
--- dlls/ddraw/tests/Makefile.in	7 Jun 2005 21:34:59 -0000	1.5
+++ dlls/ddraw/tests/Makefile.in	19 Sep 2005 12:57:10 -0000
@@ -9,7 +9,8 @@
 CTESTS = \
 	d3d.c \
 	ddrawmodes.c \
-	dsurface.c
+	dsurface.c \
+	refcount.c
 
 @MAKE_TEST_RULES@
 
--- /dev/null	2005-09-01 15:22:32.000000000 +0200
+++ dlls/ddraw/tests/refcount.c	2005-09-18 21:57:52.000000000 +0200
@@ -0,0 +1,197 @@
+/*
+ * Unit tests for DirectDraw refcounts
+ *
+ * Copyright (C) 2005 Stefan Dösinger
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <assert.h>
+#include "wine/test.h"
+#include "ddraw.h"
+
+static LPDIRECTDRAW7 lpDD = NULL;
+static WNDCLASS wc;
+static HWND hwnd;
+
+static void CreateDirectDraw(void)
+{
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.lpfnWndProc = DefWindowProcA;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(0);
+    wc.hIcon = LoadIconA(wc.hInstance, IDI_APPLICATION);
+    wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
+    wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = "TestWindowClass";
+    if(!RegisterClassA(&wc))
+        assert(0);
+    
+    hwnd = CreateWindowExA(0, "TestWindowClass", "TestWindowClass",
+        WS_POPUP, 0, 0,
+        GetSystemMetrics(SM_CXSCREEN),
+        GetSystemMetrics(SM_CYSCREEN),
+        NULL, NULL, GetModuleHandleA(0), NULL);
+    assert(hwnd != NULL);
+    
+    ShowWindow(hwnd, SW_HIDE);
+    UpdateWindow(hwnd);
+    SetFocus(hwnd);
+
+    HRESULT rc;
+
+    rc = DirectDrawCreateEx(NULL, (LPVOID *) &lpDD, &IID_IDirectDraw7, NULL);
+    ok(rc==DD_OK,"DirectDrawCreateEx returned: %lx\n",rc);
+
+    rc = IDirectDraw7_SetCooperativeLevel(lpDD, hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+    ok(rc==DD_OK,"SetCooperativeLevel returned: %lx\n",rc);
+
+    rc = IDirectDraw7_SetDisplayMode(lpDD, 640,480,32,0,0);
+    ok(rc == DD_OK, "SetDisplayMode returned %lx\n", rc);
+}
+
+
+static void ReleaseDirectDraw(void)
+{
+    if( lpDD != NULL )
+    {
+        IDirectDraw_Release(lpDD);
+        lpDD = NULL;
+    }
+}
+
+static void SurfaceTest(void)
+{
+    LPDIRECTDRAWSURFACE7 lpDDS;
+    DDSURFACEDESC2 ddsd;
+    HRESULT rc;
+    int newref;
+    int oldref;
+
+    newref = IDirectDraw_AddRef(lpDD) - 1;
+    IDirectDraw_Release(lpDD);
+    ok(newref == 1, "Initial reference count = %d\n", newref);
+    oldref = newref;
+
+    /* Test a complex surface with one back buffer. Should increase the refcount by 1 */
+    memset(&ddsd, 0, sizeof(ddsd));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+    ddsd.dwBackBufferCount = 1;
+
+    rc = IDirectDraw7_CreateSurface( lpDD, &ddsd, &lpDDS, NULL );
+    ok(rc == DD_OK, "CreateSurface for a COMPLEX surface returned %lx\n", rc);
+    if(rc == DD_OK)
+    {
+        newref = IDirectDraw_AddRef(lpDD) - 1;
+        IDirectDraw_Release(lpDD);
+        ok( (newref - oldref) == 1, "DD reference count increased by %d during creation of a complex surface\n", newref - oldref);
+        oldref = newref;
+
+        newref = IDirectDrawSurface_AddRef(lpDDS) - 1;
+        IDirectDrawSurface_Release(lpDDS);
+        ok(newref == 1, "Initial surface reference count of a complex surface is %d\n", newref);
+
+        IDirectDrawSurface_Release(lpDDS);
+
+        /* Release the surface */
+        newref = IDirectDraw_AddRef(lpDD) - 1;
+        IDirectDraw_Release(lpDD);
+        ok( (newref - oldref) == -1, "DD reference count decreased by %d during releasing a complex surface\n", newref - oldref);
+        oldref = newref;
+
+    }
+
+    /* Test a offscreen surface. Should also add 1 to the refcount*/
+    memset(&ddsd, 0, sizeof(ddsd));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    ddsd.dwHeight = 16;
+    ddsd.dwWidth = 16;
+    ddsd.dwBackBufferCount = 0;
+    
+    rc = IDirectDraw7_CreateSurface( lpDD, &ddsd, &lpDDS, NULL );
+    ok(rc == DD_OK, "CreateSurface for a offscreen surface returned %lx\n", rc);
+    if(rc == DD_OK)
+    {
+        newref = IDirectDraw_AddRef(lpDD) - 1;
+        IDirectDraw_Release(lpDD);
+        ok( (newref - oldref) == 1, "DD reference count increased by %d during creation of a offscreen surface\n", newref - oldref);
+        oldref = newref;
+
+        newref = IDirectDrawSurface_AddRef(lpDDS) - 1;
+        IDirectDrawSurface_Release(lpDDS);
+        ok(newref == 1, "Initial surface reference count of a offscreen surface is %d\n", newref);
+    
+        /* Release the surface */
+        IDirectDrawSurface_Release(lpDDS);
+
+        newref = IDirectDraw_AddRef(lpDD) - 1;
+        IDirectDraw_Release(lpDD);
+        ok( (newref - oldref) == -1, "DD reference count decreased by %d during releasing a offscreen surface\n", newref - oldref);
+        oldref = newref;
+    }
+
+    /* Create a Texture. Increases the refcount by 2!!!*/
+    memset(&ddsd, 0, sizeof(ddsd));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+    ddsd.dwHeight = 128;
+    ddsd.dwWidth = 128;
+    ddsd.dwMipMapCount = 8;
+    ddsd.dwBackBufferCount = 0;
+    
+    ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+    ddsd.ddpfPixelFormat.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB;
+    ddsd.ddpfPixelFormat.dwRGBBitCount = 32;
+    ddsd.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
+    ddsd.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
+    ddsd.ddpfPixelFormat.dwBBitMask = 0x000000ff;
+    ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
+
+    rc = IDirectDraw7_CreateSurface( lpDD, &ddsd, &lpDDS, NULL );
+    ok(rc == DD_OK, "CreateSurface for a mipmap surface returned %lx\n", rc);
+    if(rc == DD_OK)
+    {
+        newref = IDirectDraw_AddRef(lpDD) - 1;
+        IDirectDraw_Release(lpDD);
+        ok( (newref - oldref) == 2, "DD reference count increased by %d during creation of a mipmap surface\n", newref - oldref);
+        oldref = newref;
+
+        newref = IDirectDrawSurface_AddRef(lpDDS) - 1;
+        IDirectDrawSurface_Release(lpDDS);
+        ok(newref == 1, "Initial surface reference count of a mipmap surface is %d\n", newref);
+    
+        /* Release the surface */
+        IDirectDrawSurface_Release(lpDDS);
+
+        newref = IDirectDraw_AddRef(lpDD) - 1;
+        IDirectDraw_Release(lpDD);
+        ok( (newref - oldref) == -2, "DD reference count decreased by %d during releasing a mipmap surface\n", newref - oldref);
+    }
+
+}
+
+START_TEST(refcount)
+{
+    CreateDirectDraw();
+    SurfaceTest();
+    ReleaseDirectDraw();
+}


Reply via email to