[RESEND] [ddraw] Mipmap creation with DDSCAPS_COMPLEX, DDSCAPS_MIPMAP, and no mipmap count

Antoine Chavasse a.chavasse at gmail.com
Sun May 29 14:15:06 CDT 2005


Resend of http://www.winehq.org/hypermail/wine-patches/2005/05/0655.html

With this suggestion from Lionel Ulmer:

> The only (minor) gripe I would have with this patch is the use of the 'log()
> / log()' to compute the mipmap count (I usually dislike floating point match
> - it's maybe my background in embedded programming where FPU are inexistant
> :-) )... I would have found it simpler to just have a 'while (min > 0) { min
> >>= 1; count += 1 }'.


ChangeLog:
 - Implemented the implicit creation of mipmaps for surfaces that have
DDSCAPS_COMPLEX, DDSCAPS_MIPMAP and for which the mipmap count is not
specified.
 - Implemented test cases for mipmap textures creation.

Index: dlls/ddraw/ddraw/main.c
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/ddraw/main.c,v
retrieving revision 1.60
diff -u -p -r1.60 main.c
--- dlls/ddraw/ddraw/main.c	27 May 2005 20:17:36 -0000	1.60
+++ dlls/ddraw/ddraw/main.c	29 May 2005 18:54:43 -0000
@@ -430,12 +430,31 @@ create_texture(IDirectDrawImpl* This, co
 	ddsd.dwFlags |= DDSD_PITCH;
     }
 
-    /* Check also for the MIPMAP / MIPMAPCOUNT flags.
-       As checked on Windows, this is the right behaviour. No mipmaps
seem to be generated. */
-    if (((ddsd.dwFlags & DDSD_MIPMAPCOUNT) == 0) &&
-	((ddsd.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != 0)) {
+    if((ddsd.ddsCaps.dwCaps & DDSCAPS_MIPMAP) &&
+        !(ddsd.dwFlags & DDSD_MIPMAPCOUNT))
+    {
+        if(ddsd.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
+        {
+            /* Undocumented feature: if DDSCAPS_MIPMAP and DDSCAPS_COMPLEX are
+             * both set, but mipmap count isn't given, as many mipmap levels
+             * as necessary are created to get down to a size where either
+             * the width or the height of the texture is 1.
+             *
+             * This is needed by Anarchy Online. */
+            DWORD min = ddsd.dwWidth < ddsd.dwHeight ?
+                        ddsd.dwWidth : ddsd.dwHeight;
+            ddsd.u2.dwMipMapCount = 0;
+            while( min )
+            {
+                ddsd.u2.dwMipMapCount++;
+                min >>= 1;
+            }
+        }
+        else
+            /* Create a single mipmap. */
+            ddsd.u2.dwMipMapCount = 1;
+ 
         ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
-	ddsd.u2.dwMipMapCount = 1;
     }
     
     ddsd.dwFlags |= DDSD_PIXELFORMAT;
Index: dlls/ddraw/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/tests/Makefile.in,v
retrieving revision 1.3
diff -u -p -r1.3 Makefile.in
--- dlls/ddraw/tests/Makefile.in	16 Feb 2004 22:18:59 -0000	1.3
+++ dlls/ddraw/tests/Makefile.in	29 May 2005 18:54:43 -0000
@@ -6,7 +6,8 @@ TESTDLL   = ddraw.dll
 IMPORTS   = ddraw user32 gdi32 kernel32
 
 CTESTS = \
-	ddrawmodes.c
+	ddrawmodes.c \
+	dsurface.c
 
 @MAKE_TEST_RULES@
 
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ dlls/ddraw/tests/dsurface.c	2005-05-29 18:48:48.554096960 +0200
@@ -0,0 +1,162 @@
+/*
+ * Unit tests for (a few) ddraw surface functions
+ *
+ * Copyright (C) 2005 Antoine Chavasse (a.chavasse at gmail.com)
+ *
+ * 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 LPDIRECTDRAW lpDD = NULL;
+
+static void CreateDirectDraw()
+{
+    HRESULT rc;
+
+    rc = DirectDrawCreate(NULL, &lpDD, NULL);
+    ok(rc==DD_OK,"DirectDrawCreate returned: %lx\n",rc);
+
+    rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_NORMAL);
+    ok(rc==DD_OK,"SetCooperativeLevel returned: %lx\n",rc);
+}
+
+
+static void ReleaseDirectDraw()
+{
+    if( lpDD != NULL )
+    {
+        IDirectDraw_Release(lpDD);
+        lpDD = NULL;
+    }
+}
+
+static void MipMapCreationTest()
+{
+    LPDIRECTDRAWSURFACE lpDDSMipMapTest;
+    DDSURFACEDESC ddsd;
+    HRESULT rc;
+
+    /* First mipmap creation test: create a surface with DDSCAPS_COMPLEX,
+       DDSCAPS_MIPMAP, and DDSD_MIPMAPCOUNT. This create the number of
+        requested mipmap levels. */
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+    ddsd.dwMipMapCount = 3;
+    ddsd.dwWidth = 128;
+    ddsd.dwHeight = 32;
+    rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSMipMapTest, NULL);
+    ok(rc==DD_OK,"CreateSurface returned: %lx\n",rc);
+
+    /* Check the number of created mipmaps */
+    memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+    ddsd.dwSize = sizeof(ddsd);
+    rc = IDirectDrawSurface_GetSurfaceDesc(lpDDSMipMapTest, &ddsd);
+    ok(rc==DD_OK,"GetSurfaceDesc returned: %lx\n",rc);
+    ok(ddsd.dwFlags & DDSD_MIPMAPCOUNT,
+        "GetSurfaceDesc returned no mipmapcount.\n");
+    ok(ddsd.dwMipMapCount == 3, "Incorrect mipmap count: %ld.\n",
+        ddsd.dwMipMapCount);
+
+    /* Destroy the surface. */
+    IDirectDrawSurface_Release(lpDDSMipMapTest);
+
+
+    /* Second mipmap creation test: create a surface without a mipmap
+       count, with DDSCAPS_MIPMAP and without DDSCAPS_COMPLEX.
+       This creates a single mipmap level. */
+    memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
+    ddsd.dwWidth = 128;
+    ddsd.dwHeight = 32;
+    rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSMipMapTest, NULL);
+    ok(rc==DD_OK,"CreateSurface returned: %lx\n",rc);
+
+    /* Check the number of created mipmaps */
+    memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+    ddsd.dwSize = sizeof(ddsd);
+    rc = IDirectDrawSurface_GetSurfaceDesc(lpDDSMipMapTest, &ddsd);
+    ok(rc==DD_OK,"GetSurfaceDesc returned: %lx\n",rc);
+    ok(ddsd.dwFlags & DDSD_MIPMAPCOUNT,
+        "GetSurfaceDesc returned no mipmapcount.\n");
+    ok(ddsd.dwMipMapCount == 1, "Incorrect mipmap count: %ld.\n",
+        ddsd.dwMipMapCount);
+
+
+    /* Third mipmap creation test: create a surface with DDSCAPS_MIPMAP,
+        DDSCAPS_COMPLEX and without DDSD_MIPMAPCOUNT.
+       It's an undocumented features where a chain of mipmaps, starting from
+       he specified size and down to the smallest size, is automatically
+       created.
+       Anarchy Online needs this feature to work. */
+    memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+    ddsd.dwWidth = 128;
+    ddsd.dwHeight = 32;
+    rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSMipMapTest, NULL);
+    ok(rc==DD_OK,"CreateSurface returned: %lx\n",rc);
+
+    /* Check the number of created mipmaps */
+    memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+    ddsd.dwSize = sizeof(ddsd);
+    rc = IDirectDrawSurface_GetSurfaceDesc(lpDDSMipMapTest, &ddsd);
+    ok(rc==DD_OK,"GetSurfaceDesc returned: %lx\n",rc);
+    ok(ddsd.dwFlags & DDSD_MIPMAPCOUNT,
+        "GetSurfaceDesc returned no mipmapcount.\n");
+    ok(ddsd.dwMipMapCount == 6, "Incorrect mipmap count: %ld.\n",
+        ddsd.dwMipMapCount);
+
+
+    /* Fourth mipmap creation test: same as above with a different texture
+       size.
+       The purpose is to verify that the number of generated mipmaps is
+       dependant on the smallest dimension. */
+    memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+    ddsd.dwWidth = 32;
+    ddsd.dwHeight = 64;
+    rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSMipMapTest, NULL);
+    ok(rc==DD_OK,"CreateSurface returned: %lx\n",rc);
+
+    /* Check the number of created mipmaps */
+    memset(&ddsd, 0, sizeof(DDSURFACEDESC));
+    ddsd.dwSize = sizeof(ddsd);
+    rc = IDirectDrawSurface_GetSurfaceDesc(lpDDSMipMapTest, &ddsd);
+    ok(rc==DD_OK,"GetSurfaceDesc returned: %lx\n",rc);
+    ok(ddsd.dwFlags & DDSD_MIPMAPCOUNT,
+        "GetSurfaceDesc returned no mipmapcount.\n");
+    ok(ddsd.dwMipMapCount == 6, "Incorrect mipmap count: %ld.\n",
+        ddsd.dwMipMapCount);
+
+    /* Destroy the surface. */
+    IDirectDrawSurface_Release(lpDDSMipMapTest);
+}
+
+
+START_TEST(dsurface)
+{
+    CreateDirectDraw();
+    MipMapCreationTest();
+    ReleaseDirectDraw();
+}




More information about the wine-patches mailing list