[PATCH 6/7] ddraw/tests: Test blocked texture creation restrictions

Stefan Dösinger stefan at codeweavers.com
Thu Sep 5 17:11:15 CDT 2013


No ddraw1 and ddraw2 tests because those versions do not enumerate DXTn
formats. On Windows they also refuse to create non-sysmem DXTn surfaces.
Wine implements the enumeration restriction, but not the creation
restriction.
---
 dlls/ddraw/ddraw.c        |  20 ++++-
 dlls/ddraw/surface.c      |  10 +++
 dlls/ddraw/tests/ddraw4.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++
 dlls/ddraw/tests/ddraw7.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 464 insertions(+), 4 deletions(-)

diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index a7f29b5..c31146d 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -2899,13 +2899,25 @@ static HRESULT CreateSurface(struct ddraw *ddraw, DDSURFACEDESC2 *DDSD,
         }
     }
 
+    if (desc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE)
+    {
+        hr = ddraw_surface_create_texture(object, flags);
+        if (FAILED(hr))
+        {
+            if (version == 7)
+                IDirectDrawSurface7_Release(&object->IDirectDrawSurface7_iface);
+            else if (version == 4)
+                IDirectDrawSurface4_Release(&object->IDirectDrawSurface4_iface);
+            else
+                IDirectDrawSurface_Release(&object->IDirectDrawSurface_iface);
+
+            return hr;
+        }
+    }
+
     if (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
         ddraw->primary = object;
 
-    /* Create a WineD3DTexture if a texture was requested */
-    if (desc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE)
-        ddraw_surface_create_texture(object, flags);
-
     return hr;
 }
 
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index 8627a84..ad67da0 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -5651,6 +5651,16 @@ HRESULT ddraw_surface_create_texture(struct ddraw_surface *surface, DWORD surfac
     if (FAILED(hr))
     {
         WARN("Failed to create wined3d texture, hr %#x.\n", hr);
+        switch (hr)
+        {
+            case WINED3DERR_INVALIDCALL:
+                hr = DDERR_INVALIDPARAMS;
+                break;
+
+            default:
+                FIXME("Unexpected wined3d error %#x.\n", hr);
+                break;
+        }
         return hr;
     }
 
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index b0e014d..1b260fe 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -3914,6 +3914,224 @@ static void test_texturemanage(void)
     IDirectDraw4_Release(ddraw);
 }
 
+#define SUPPORT_DXT1    0x01
+#define SUPPORT_DXT2    0x02
+#define SUPPORT_DXT3    0x04
+#define SUPPORT_DXT4    0x08
+#define SUPPORT_DXT5    0x10
+#define SUPPORT_YUY2    0x20
+#define SUPPORT_UYVY    0x40
+
+static HRESULT WINAPI test_block_formats_creation_cb(DDPIXELFORMAT *fmt, void *ctx)
+{
+    DWORD *supported_fmts = ctx;
+
+    if (!(fmt->dwFlags & DDPF_FOURCC))
+        return DDENUMRET_OK;
+
+    switch (fmt->dwFourCC)
+    {
+        case MAKEFOURCC('D','X','T','1'):
+            *supported_fmts |= SUPPORT_DXT1;
+            break;
+        case MAKEFOURCC('D','X','T','2'):
+            *supported_fmts |= SUPPORT_DXT2;
+            break;
+        case MAKEFOURCC('D','X','T','3'):
+            *supported_fmts |= SUPPORT_DXT3;
+            break;
+        case MAKEFOURCC('D','X','T','4'):
+            *supported_fmts |= SUPPORT_DXT4;
+            break;
+        case MAKEFOURCC('D','X','T','5'):
+            *supported_fmts |= SUPPORT_DXT5;
+            break;
+        case MAKEFOURCC('Y','U','Y','2'):
+            *supported_fmts |= SUPPORT_YUY2;
+            break;
+        case MAKEFOURCC('U','Y','V','Y'):
+            *supported_fmts |= SUPPORT_UYVY;
+            break;
+        default:
+            break;
+    }
+
+    return DDENUMRET_OK;
+}
+
+static void test_block_formats_creation(void)
+{
+    HRESULT hr, expect_hr;
+    unsigned int i, j, w, h;
+    HWND window;
+    IDirectDraw4 *ddraw;
+    IDirect3D3 *d3d;
+    IDirect3DDevice3 *device;
+    IDirectDrawSurface4 *surface;
+    DWORD supported_fmts = 0, supported_overlay_fmts = 0;
+    DWORD num_fourcc_codes = 0, *fourcc_codes;
+    DDSURFACEDESC2 ddsd;
+    static const struct
+    {
+        DWORD fourcc;
+        const char *name;
+        DWORD support_flag;
+        unsigned int block_width;
+        unsigned int block_height;
+        BOOL create_size_checked, overlay;
+    }
+    formats[] =
+    {
+        {MAKEFOURCC('D','X','T','1'), "D3DFMT_DXT1", SUPPORT_DXT1, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('D','X','T','2'), "D3DFMT_DXT2", SUPPORT_DXT2, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('D','X','T','3'), "D3DFMT_DXT3", SUPPORT_DXT3, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('D','X','T','4'), "D3DFMT_DXT4", SUPPORT_DXT4, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('D','X','T','5'), "D3DFMT_DXT5", SUPPORT_DXT5, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('Y','U','Y','2'), "D3DFMT_YUY2", SUPPORT_YUY2, 2, 1, FALSE, TRUE },
+        {MAKEFOURCC('U','Y','V','Y'), "D3DFMT_UYVY", SUPPORT_UYVY, 2, 1, FALSE, TRUE },
+    };
+    const struct
+    {
+        DWORD caps, caps2;
+        const char *name;
+        BOOL overlay;
+    }
+    types[] =
+    {
+        /* DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY fails to create any fourcc
+         * surface with DDERR_INVALIDPIXELFORMAT. Don't care about it for now.
+         *
+         * Nvidia returns E_FAIL on DXTN DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY.
+         * Other hw / drivers successfully create those surfaces. Ignore them, this
+         * suggests that no game uses this, otherwise Nvidia would support it. */
+        {
+            DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE, 0,
+            "videomemory texture", FALSE
+        },
+        {
+            DDSCAPS_VIDEOMEMORY | DDSCAPS_OVERLAY, 0,
+            "videomemory overlay", TRUE
+        },
+        {
+            DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE, 0,
+            "systemmemory texture", FALSE
+        },
+        {
+            DDSCAPS_TEXTURE, DDSCAPS2_TEXTUREMANAGE,
+            "managed texture", FALSE
+        }
+    };
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+
+    if (!(device = create_device(window, DDSCL_NORMAL)))
+    {
+        skip("Failed to create D3D device, skipping test.\n");
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
+    ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
+    hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **) &ddraw);
+    ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
+    IDirect3D3_Release(d3d);
+
+    hr = IDirect3DDevice3_EnumTextureFormats(device, test_block_formats_creation_cb,
+            &supported_fmts);
+    ok(SUCCEEDED(hr), "Failed to enumerate texture formats %#x.\n", hr);
+
+    hr = IDirectDraw4_GetFourCCCodes(ddraw, &num_fourcc_codes, NULL);
+    ok(SUCCEEDED(hr), "Failed to get fourcc codes %#x.\n", hr);
+    fourcc_codes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+            num_fourcc_codes * sizeof(*fourcc_codes));
+    if (!fourcc_codes)
+        goto cleanup;
+    hr = IDirectDraw4_GetFourCCCodes(ddraw, &num_fourcc_codes, fourcc_codes);
+    ok(SUCCEEDED(hr), "Failed to get fourcc codes %#x.\n", hr);
+    for (i = 0; i < num_fourcc_codes; i++)
+    {
+        for (j = 0; j < sizeof(formats) / sizeof(*formats); j++)
+        {
+            if (fourcc_codes[i] == formats[j].fourcc)
+                supported_overlay_fmts |= formats[j].support_flag;
+        }
+    }
+    HeapFree(GetProcessHeap(), 0, fourcc_codes);
+
+    for (i = 0; i < sizeof(formats) / sizeof(*formats); i++)
+    {
+        for (j = 0; j < sizeof(types) / sizeof(*types); j++)
+        {
+            BOOL support;
+            if (formats[i].overlay != types[j].overlay)
+                continue;
+
+            if (formats[i].overlay)
+                support = supported_overlay_fmts & formats[i].support_flag;
+            else
+                support = supported_fmts & formats[i].support_flag;
+
+            for (w = 1; w <= 8; w++)
+            {
+                for (h = 1; h <= 8; h++)
+                {
+                    BOOL block_aligned = TRUE;
+                    BOOL todo = FALSE;
+
+                    if (w & (formats[i].block_width - 1) || h & (formats[i].block_height - 1))
+                        block_aligned = FALSE;
+
+                    memset(&ddsd, 0, sizeof(ddsd));
+                    ddsd.dwSize = sizeof(ddsd);
+                    ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
+                    ddsd.ddsCaps.dwCaps = types[j].caps;
+                    ddsd.ddsCaps.dwCaps2 = types[j].caps2;
+                    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
+                    ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
+                    ddsd.ddpfPixelFormat.dwFourCC = formats[i].fourcc;
+                    ddsd.dwWidth = w;
+                    ddsd.dwHeight = h;
+
+                    /* TODO: Handle power of two limitations. I cannot test the pow2
+                     * behavior on windows because I have no hardware that doesn't at
+                     * least support np2_conditional. There's probably no HW that
+                     * supports DXTN textures but no conditional np2 textures. */
+                    if (!support && !(types[j].caps & DDSCAPS_SYSTEMMEMORY))
+                        expect_hr = DDERR_INVALIDPARAMS;
+                    else if (formats[i].create_size_checked && !block_aligned)
+                    {
+                        expect_hr = DDERR_INVALIDPARAMS;
+                        if (!(types[j].caps & DDSCAPS_TEXTURE))
+                            todo = TRUE;
+                    }
+                    else
+                        expect_hr = D3D_OK;
+
+                    hr = IDirectDraw4_CreateSurface(ddraw, &ddsd, &surface, NULL);
+                    if (todo)
+                        todo_wine ok(hr == expect_hr,
+                                "Got unexpected hr %#x for format %s, resource type %s, size %ux%u, expected %#x.\n",
+                                hr, formats[i].name, types[j].name, w, h, expect_hr);
+                    else
+                        ok(hr == expect_hr,
+                                "Got unexpected hr %#x for format %s, resource type %s, size %ux%u, expected %#x.\n",
+                                hr, formats[i].name, types[j].name, w, h, expect_hr);
+
+                    if (SUCCEEDED(hr))
+                        IDirectDrawSurface4_Release(surface);
+                }
+            }
+        }
+    }
+
+cleanup:
+    IDirectDraw4_Release(ddraw);
+    IDirect3DDevice3_Release(device);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw4)
 {
     test_process_vertices();
@@ -3945,4 +4163,5 @@ START_TEST(ddraw4)
     test_lighting_interface_versions();
     test_coop_level_activateapp();
     test_texturemanage();
+    test_block_formats_creation();
 }
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 5197ccea..09f4094 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -3728,6 +3728,224 @@ static void test_texturemanage(void)
     IDirectDraw7_Release(ddraw);
 }
 
+#define SUPPORT_DXT1    0x01
+#define SUPPORT_DXT2    0x02
+#define SUPPORT_DXT3    0x04
+#define SUPPORT_DXT4    0x08
+#define SUPPORT_DXT5    0x10
+#define SUPPORT_YUY2    0x20
+#define SUPPORT_UYVY    0x40
+
+static HRESULT WINAPI test_block_formats_creation_cb(DDPIXELFORMAT *fmt, void *ctx)
+{
+    DWORD *supported_fmts = ctx;
+
+    if (!(fmt->dwFlags & DDPF_FOURCC))
+        return DDENUMRET_OK;
+
+    switch (fmt->dwFourCC)
+    {
+        case MAKEFOURCC('D','X','T','1'):
+            *supported_fmts |= SUPPORT_DXT1;
+            break;
+        case MAKEFOURCC('D','X','T','2'):
+            *supported_fmts |= SUPPORT_DXT2;
+            break;
+        case MAKEFOURCC('D','X','T','3'):
+            *supported_fmts |= SUPPORT_DXT3;
+            break;
+        case MAKEFOURCC('D','X','T','4'):
+            *supported_fmts |= SUPPORT_DXT4;
+            break;
+        case MAKEFOURCC('D','X','T','5'):
+            *supported_fmts |= SUPPORT_DXT5;
+            break;
+        case MAKEFOURCC('Y','U','Y','2'):
+            *supported_fmts |= SUPPORT_YUY2;
+            break;
+        case MAKEFOURCC('U','Y','V','Y'):
+            *supported_fmts |= SUPPORT_UYVY;
+            break;
+        default:
+            break;
+    }
+
+    return DDENUMRET_OK;
+}
+
+static void test_block_formats_creation(void)
+{
+    HRESULT hr, expect_hr;
+    unsigned int i, j, w, h;
+    HWND window;
+    IDirectDraw7 *ddraw;
+    IDirect3D7 *d3d;
+    IDirect3DDevice7 *device;
+    IDirectDrawSurface7 *surface;
+    DWORD supported_fmts = 0, supported_overlay_fmts = 0;
+    DWORD num_fourcc_codes = 0, *fourcc_codes;
+    DDSURFACEDESC2 ddsd;
+    static const struct
+    {
+        DWORD fourcc;
+        const char *name;
+        DWORD support_flag;
+        unsigned int block_width;
+        unsigned int block_height;
+        BOOL create_size_checked, overlay;
+    }
+    formats[] =
+    {
+        {MAKEFOURCC('D','X','T','1'), "D3DFMT_DXT1", SUPPORT_DXT1, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('D','X','T','2'), "D3DFMT_DXT2", SUPPORT_DXT2, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('D','X','T','3'), "D3DFMT_DXT3", SUPPORT_DXT3, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('D','X','T','4'), "D3DFMT_DXT4", SUPPORT_DXT4, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('D','X','T','5'), "D3DFMT_DXT5", SUPPORT_DXT5, 4, 4, TRUE,  FALSE},
+        {MAKEFOURCC('Y','U','Y','2'), "D3DFMT_YUY2", SUPPORT_YUY2, 2, 1, FALSE, TRUE },
+        {MAKEFOURCC('U','Y','V','Y'), "D3DFMT_UYVY", SUPPORT_UYVY, 2, 1, FALSE, TRUE },
+    };
+    const struct
+    {
+        DWORD caps, caps2;
+        const char *name;
+        BOOL overlay;
+    }
+    types[] =
+    {
+        /* DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY fails to create any fourcc
+         * surface with DDERR_INVALIDPIXELFORMAT. Don't care about it for now.
+         *
+         * Nvidia returns E_FAIL on DXTN DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY.
+         * Other hw / drivers successfully create those surfaces. Ignore them, this
+         * suggests that no game uses this, otherwise Nvidia would support it. */
+        {
+            DDSCAPS_VIDEOMEMORY | DDSCAPS_TEXTURE, 0,
+            "videomemory texture", FALSE
+        },
+        {
+            DDSCAPS_VIDEOMEMORY | DDSCAPS_OVERLAY, 0,
+            "videomemory overlay", TRUE
+        },
+        {
+            DDSCAPS_SYSTEMMEMORY | DDSCAPS_TEXTURE, 0,
+            "systemmemory texture", FALSE
+        },
+        {
+            DDSCAPS_TEXTURE, DDSCAPS2_TEXTUREMANAGE,
+            "managed texture", FALSE
+        }
+    };
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+
+    if (!(device = create_device(window, DDSCL_NORMAL)))
+    {
+        skip("Failed to create D3D device, skipping test.\n");
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
+    ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
+    hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **) &ddraw);
+    ok(SUCCEEDED(hr), "Failed to get ddraw interface, hr %#x.\n", hr);
+    IDirect3D7_Release(d3d);
+
+    hr = IDirect3DDevice7_EnumTextureFormats(device, test_block_formats_creation_cb,
+            &supported_fmts);
+    ok(SUCCEEDED(hr), "Failed to enumerate texture formats %#x.\n", hr);
+
+    hr = IDirectDraw7_GetFourCCCodes(ddraw, &num_fourcc_codes, NULL);
+    ok(SUCCEEDED(hr), "Failed to get fourcc codes %#x.\n", hr);
+    fourcc_codes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+            num_fourcc_codes * sizeof(*fourcc_codes));
+    if (!fourcc_codes)
+        goto cleanup;
+    hr = IDirectDraw7_GetFourCCCodes(ddraw, &num_fourcc_codes, fourcc_codes);
+    ok(SUCCEEDED(hr), "Failed to get fourcc codes %#x.\n", hr);
+    for (i = 0; i < num_fourcc_codes; i++)
+    {
+        for (j = 0; j < sizeof(formats) / sizeof(*formats); j++)
+        {
+            if (fourcc_codes[i] == formats[j].fourcc)
+                supported_overlay_fmts |= formats[j].support_flag;
+        }
+    }
+    HeapFree(GetProcessHeap(), 0, fourcc_codes);
+
+    for (i = 0; i < sizeof(formats) / sizeof(*formats); i++)
+    {
+        for (j = 0; j < sizeof(types) / sizeof(*types); j++)
+        {
+            BOOL support;
+            if (formats[i].overlay != types[j].overlay)
+                continue;
+
+            if (formats[i].overlay)
+                support = supported_overlay_fmts & formats[i].support_flag;
+            else
+                support = supported_fmts & formats[i].support_flag;
+
+            for (w = 1; w <= 8; w++)
+            {
+                for (h = 1; h <= 8; h++)
+                {
+                    BOOL block_aligned = TRUE;
+                    BOOL todo = FALSE;
+
+                    if (w & (formats[i].block_width - 1) || h & (formats[i].block_height - 1))
+                        block_aligned = FALSE;
+
+                    memset(&ddsd, 0, sizeof(ddsd));
+                    ddsd.dwSize = sizeof(ddsd);
+                    ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
+                    ddsd.ddsCaps.dwCaps = types[j].caps;
+                    ddsd.ddsCaps.dwCaps2 = types[j].caps2;
+                    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
+                    ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
+                    ddsd.ddpfPixelFormat.dwFourCC = formats[i].fourcc;
+                    ddsd.dwWidth = w;
+                    ddsd.dwHeight = h;
+
+                    /* TODO: Handle power of two limitations. I cannot test the pow2
+                     * behavior on windows because I have no hardware that doesn't at
+                     * least support np2_conditional. There's probably no HW that
+                     * supports DXTN textures but no conditional np2 textures. */
+                    if (!support && !(types[j].caps & DDSCAPS_SYSTEMMEMORY))
+                        expect_hr = DDERR_INVALIDPARAMS;
+                    else if (formats[i].create_size_checked && !block_aligned)
+                    {
+                        expect_hr = DDERR_INVALIDPARAMS;
+                        if (!(types[j].caps & DDSCAPS_TEXTURE))
+                            todo = TRUE;
+                    }
+                    else
+                        expect_hr = D3D_OK;
+
+                    hr = IDirectDraw7_CreateSurface(ddraw, &ddsd, &surface, NULL);
+                    if (todo)
+                        todo_wine ok(hr == expect_hr,
+                                "Got unexpected hr %#x for format %s, resource type %s, size %ux%u, expected %#x.\n",
+                                hr, formats[i].name, types[j].name, w, h, expect_hr);
+                    else
+                        ok(hr == expect_hr,
+                                "Got unexpected hr %#x for format %s, resource type %s, size %ux%u, expected %#x.\n",
+                                hr, formats[i].name, types[j].name, w, h, expect_hr);
+
+                    if (SUCCEEDED(hr))
+                        IDirectDrawSurface7_Release(surface);
+                }
+            }
+        }
+    }
+
+cleanup:
+    IDirectDraw7_Release(ddraw);
+    IDirect3DDevice7_Release(device);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw7)
 {
     HMODULE module = GetModuleHandleA("ddraw.dll");
@@ -3767,4 +3985,5 @@ START_TEST(ddraw7)
     test_lighting_interface_versions();
     test_coop_level_activateapp();
     test_texturemanage();
+    test_block_formats_creation();
 }
-- 
1.8.1.5




More information about the wine-patches mailing list