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(); +}