[PATCH 4/7] d3d9/tests: Test blocked texture creation restrictions

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


---
 dlls/d3d9/device.c       |   8 ++
 dlls/d3d9/tests/device.c | 225 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 218 insertions(+), 15 deletions(-)

diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c
index f805228..17664b1 100644
--- a/dlls/d3d9/device.c
+++ b/dlls/d3d9/device.c
@@ -742,6 +742,7 @@ static HRESULT WINAPI d3d9_device_CreateTexture(IDirect3DDevice9Ex *iface,
     TRACE("iface %p, width %u, height %u, levels %u, usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
             iface, width, height, levels, usage, format, pool, texture, shared_handle);
 
+    *texture = NULL;
     if (shared_handle)
     {
         if (pool == D3DPOOL_SYSTEMMEM)
@@ -795,6 +796,7 @@ static HRESULT WINAPI d3d9_device_CreateVolumeTexture(IDirect3DDevice9Ex *iface,
     TRACE("usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
             usage, format, pool, texture, shared_handle);
 
+    *texture = NULL;
     if (shared_handle)
         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
 
@@ -827,6 +829,7 @@ static HRESULT WINAPI d3d9_device_CreateCubeTexture(IDirect3DDevice9Ex *iface,
     TRACE("iface %p, edge_length %u, levels %u, usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
             iface, edge_length, levels, usage, format, pool, texture, shared_handle);
 
+    *texture = NULL;
     if (shared_handle)
         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
 
@@ -973,6 +976,7 @@ static HRESULT WINAPI d3d9_device_CreateRenderTarget(IDirect3DDevice9Ex *iface,
             iface, width, height, format, multisample_type, multisample_quality,
             lockable, surface, shared_handle);
 
+    *surface = NULL;
     if (shared_handle)
         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
 
@@ -995,6 +999,7 @@ static HRESULT WINAPI d3d9_device_CreateDepthStencilSurface(IDirect3DDevice9Ex *
             iface, width, height, format, multisample_type, multisample_quality,
             discard, surface, shared_handle);
 
+    *surface = NULL;
     if (shared_handle)
         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
 
@@ -1191,6 +1196,7 @@ static HRESULT WINAPI d3d9_device_CreateOffscreenPlainSurface(IDirect3DDevice9Ex
     TRACE("iface %p, width %u, height %u, format %#x, pool %#x, surface %p, shared_handle %p.\n",
             iface, width, height, format, pool, surface, shared_handle);
 
+    *surface = NULL;
     if (shared_handle)
         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
 
@@ -3038,6 +3044,7 @@ static HRESULT WINAPI d3d9_device_CreateRenderTargetEx(IDirect3DDevice9Ex *iface
             iface, width, height, format, multisample_type, multisample_quality,
             lockable, surface, shared_handle, usage);
 
+    *surface = NULL;
     if (shared_handle)
         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
 
@@ -3063,6 +3070,7 @@ static HRESULT WINAPI d3d9_device_CreateDepthStencilSurfaceEx(IDirect3DDevice9Ex
             iface, width, height, format, multisample_type, multisample_quality,
             discard, surface, shared_handle, usage);
 
+    *surface = NULL;
     if (shared_handle)
         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
 
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index d705e3e..af39ffa 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -5815,7 +5815,7 @@ static void test_surface_double_unlock(void)
     DestroyWindow(window);
 }
 
-static void test_surface_lockrect_blocks(void)
+static void test_surface_blocks(void)
 {
     static const struct
     {
@@ -5824,20 +5824,21 @@ static void test_surface_lockrect_blocks(void)
         unsigned int block_width;
         unsigned int block_height;
         BOOL broken;
+        BOOL create_size_checked, core_fmt;
     }
     formats[] =
     {
-        {D3DFMT_DXT1,                 "D3DFMT_DXT1", 4, 4, FALSE},
-        {D3DFMT_DXT2,                 "D3DFMT_DXT2", 4, 4, FALSE},
-        {D3DFMT_DXT3,                 "D3DFMT_DXT3", 4, 4, FALSE},
-        {D3DFMT_DXT4,                 "D3DFMT_DXT4", 4, 4, FALSE},
-        {D3DFMT_DXT5,                 "D3DFMT_DXT5", 4, 4, FALSE},
+        {D3DFMT_DXT1,                 "D3DFMT_DXT1", 4, 4, FALSE, TRUE,  TRUE },
+        {D3DFMT_DXT2,                 "D3DFMT_DXT2", 4, 4, FALSE, TRUE,  TRUE },
+        {D3DFMT_DXT3,                 "D3DFMT_DXT3", 4, 4, FALSE, TRUE,  TRUE },
+        {D3DFMT_DXT4,                 "D3DFMT_DXT4", 4, 4, FALSE, TRUE,  TRUE },
+        {D3DFMT_DXT5,                 "D3DFMT_DXT5", 4, 4, FALSE, TRUE,  TRUE },
         /* ATI2N has 2x2 blocks on all AMD cards and Geforce 7 cards,
          * which doesn't match the format spec. On newer Nvidia cards
          * it has the correct 4x4 block size */
-        {MAKEFOURCC('A','T','I','2'), "ATI2N",       4, 4, TRUE},
-        {D3DFMT_YUY2,                 "D3DFMT_YUY2", 2, 1, FALSE},
-        {D3DFMT_UYVY,                 "D3DFMT_UYVY", 2, 1, FALSE},
+        {MAKEFOURCC('A','T','I','2'), "ATI2N",       4, 4, TRUE,  FALSE, FALSE},
+        {D3DFMT_YUY2,                 "D3DFMT_YUY2", 2, 1, FALSE, FALSE, TRUE },
+        {D3DFMT_UYVY,                 "D3DFMT_UYVY", 2, 1, FALSE, FALSE, TRUE },
     };
     static const struct
     {
@@ -5854,17 +5855,45 @@ static void test_surface_lockrect_blocks(void)
         {D3DPOOL_SYSTEMMEM,     "D3DPOOL_SYSTEMMEM",TRUE},
         {D3DPOOL_MANAGED,       "D3DPOOL_MANAGED",  TRUE},
     };
+    static struct
+    {
+        D3DRESOURCETYPE rtype;
+        const char *type_name;
+        D3DPOOL pool;
+        const char *pool_name;
+        BOOL need_driver_support, need_runtime_support;
+    }
+    create_tests[] =
+    {
+        {D3DRTYPE_SURFACE,     "D3DRTYPE_SURFACE",     D3DPOOL_DEFAULT,   "D3DPOOL_DEFAULT",   TRUE,  FALSE},
+        {D3DRTYPE_SURFACE,     "D3DRTYPE_SURFACE",     D3DPOOL_SYSTEMMEM, "D3DPOOL_SYSTEMMEM", TRUE,  TRUE },
+        /* Managed offscreen plain surfaces are not supported */
+        {D3DRTYPE_SURFACE,     "D3DRTYPE_SURFACE",     D3DPOOL_SCRATCH,   "D3DPOOL_SCRATCH",   FALSE, TRUE },
+
+        {D3DRTYPE_TEXTURE,     "D3DRTYPE_TEXTURE",     D3DPOOL_DEFAULT,   "D3DPOOL_DEFAULT",   TRUE,  FALSE},
+        {D3DRTYPE_TEXTURE,     "D3DRTYPE_TEXTURE",     D3DPOOL_SYSTEMMEM, "D3DPOOL_SYSTEMMEM", TRUE,  FALSE},
+        {D3DRTYPE_TEXTURE,     "D3DRTYPE_TEXTURE",     D3DPOOL_MANAGED,   "D3DPOOL_MANAGED",   TRUE,  FALSE},
+        {D3DRTYPE_TEXTURE,     "D3DRTYPE_TEXTURE",     D3DPOOL_SCRATCH,   "D3DPOOL_SCRATCH",   FALSE, TRUE },
+
+        {D3DRTYPE_CUBETEXTURE, "D3DRTYPE_CUBETEXTURE", D3DPOOL_DEFAULT,   "D3DPOOL_DEFAULT",   TRUE,  FALSE},
+        {D3DRTYPE_CUBETEXTURE, "D3DRTYPE_CUBETEXTURE", D3DPOOL_SYSTEMMEM, "D3DPOOL_SYSTEMMEM", TRUE,  FALSE},
+        {D3DRTYPE_CUBETEXTURE, "D3DRTYPE_CUBETEXTURE", D3DPOOL_MANAGED,   "D3DPOOL_MANAGED",   TRUE,  FALSE},
+        {D3DRTYPE_CUBETEXTURE, "D3DRTYPE_CUBETEXTURE", D3DPOOL_SCRATCH,   "D3DPOOL_SCRATCH",   FALSE, TRUE },
+    };
     IDirect3DTexture9 *texture;
+    IDirect3DCubeTexture9 *cube_texture;
     IDirect3DSurface9 *surface;
     D3DLOCKED_RECT locked_rect;
     IDirect3DDevice9 *device;
-    unsigned int i, j;
+    unsigned int i, j, w, h;
     BOOL surface_only;
     IDirect3D9 *d3d;
     ULONG refcount;
     HWND window;
     HRESULT hr;
     RECT rect;
+    BOOL tex_pow2, cube_pow2;
+    D3DCAPS9 caps;
 
     if (!(d3d = pDirect3DCreate9(D3D_SDK_VERSION)))
     {
@@ -5882,14 +5911,142 @@ static void test_surface_lockrect_blocks(void)
         return;
     }
 
+    hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
+    ok(SUCCEEDED(hr), "Failed to get caps, hr %#x.\n", hr);
+    tex_pow2 = !!(caps.TextureCaps & D3DPTEXTURECAPS_POW2);
+    if (tex_pow2)
+        tex_pow2 = !(caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
+    cube_pow2 = !!(caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2);
+
     for (i = 0; i < (sizeof(formats) / sizeof(*formats)); ++i)
     {
+        BOOL tex_support, cube_support, surface_support, format_known, dynamic_tex_support;
+
+        hr = IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
+                0, D3DRTYPE_TEXTURE, formats[i].fmt);
+        tex_support = SUCCEEDED(hr);
+        hr = IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
+                0, D3DRTYPE_CUBETEXTURE, formats[i].fmt);
+        cube_support = SUCCEEDED(hr);
+        hr = IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
+                0, D3DRTYPE_SURFACE, formats[i].fmt);
+        surface_support = SUCCEEDED(hr);
+
+        /* Scratch pool in general allows texture creation even if the driver does
+         * not support the format. If the format is an extension format that is not
+         * known to the runtime, like ATI2N, some driver support is required for
+         * this to work.
+         *
+         * It is also possible that Windows Vista and Windows 7 d3d9 runtimes know
+         * about ATI2N. I cannot check this because all my Vista+ machines support
+         * ATI2N in hardware, but none of my WinXP machines do. */
+        format_known = tex_support || cube_support || surface_support;
+
+        for (w = 1; w <= 8; w++)
+        {
+            for (h = 1; h <= 8; h++)
+            {
+                BOOL block_aligned = TRUE;
+                BOOL size_is_pow2;
+
+                if (w & (formats[i].block_width - 1) || h & (formats[i].block_height - 1))
+                    block_aligned = FALSE;
+
+                size_is_pow2 = !(w & (w - 1) || h & (h - 1));
+
+                for (j = 0; j < sizeof(create_tests) / sizeof(*create_tests); j++)
+                {
+                    BOOL support, pow2;
+                    HRESULT expect_hr;
+                    BOOL may_succeed = FALSE;
+                    IUnknown **check_null;
+
+                    if (!formats[i].core_fmt)
+                    {
+                        /* AMD warns against creating ATI2N textures smaller than
+                         * the block size because the runtime cannot calculate the
+                         * correct texture size. Generalize this for all extension
+                         * formats. */
+                        if (w < formats[i].block_width || h < formats[i].block_height)
+                            continue;
+                    }
+
+                    texture = (IDirect3DTexture9 *)0xdeadbeef;
+                    cube_texture = (IDirect3DCubeTexture9 *)0xdeadbeef;
+                    surface = (IDirect3DSurface9 *)0xdeadbeef;
+
+                    switch (create_tests[j].rtype)
+                    {
+                        case D3DRTYPE_TEXTURE:
+                            check_null = (IUnknown **)&texture;
+                            hr = IDirect3DDevice9_CreateTexture(device, w, h, 1, 0,
+                                    formats[i].fmt, create_tests[j].pool, &texture, NULL);
+                            support = tex_support;
+                            pow2 = tex_pow2;
+                            break;
+
+                        case D3DRTYPE_CUBETEXTURE:
+                            if (w != h)
+                                continue;
+                            check_null = (IUnknown **)&cube_texture;
+                            hr = IDirect3DDevice9_CreateCubeTexture(device, w, 1, 0,
+                                    formats[i].fmt, create_tests[j].pool, &cube_texture, NULL);
+                            support = cube_support;
+                            pow2 = cube_pow2;
+                            break;
+
+                        case D3DRTYPE_SURFACE:
+                            check_null = (IUnknown **)&surface;
+                            hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, w, h,
+                                    formats[i].fmt, create_tests[j].pool, &surface, NULL);
+                            support = surface_support;
+                            pow2 = FALSE;
+                            break;
+
+                        default:
+                            check_null = NULL;
+                            pow2 = FALSE;
+                            support = FALSE;
+                            break;
+                    }
+
+                    if (create_tests[j].need_driver_support && !support)
+                        expect_hr = D3DERR_INVALIDCALL;
+                    else if (create_tests[j].need_runtime_support && !formats[i].core_fmt && !format_known)
+                        expect_hr = D3DERR_INVALIDCALL;
+                    else if (formats[i].create_size_checked && !block_aligned)
+                        expect_hr = D3DERR_INVALIDCALL;
+                    else if (pow2 && !size_is_pow2 && create_tests[j].need_driver_support)
+                        expect_hr = D3DERR_INVALIDCALL;
+                    else
+                        expect_hr = D3D_OK;
+
+                    /* Wine knows about ATI2N and happily creates a scratch resource even if GL
+                     * does not support it. Accept scratch creation of extension formats on
+                     * Windows as well if it occurs. We don't really care if e.g. a Windows 7
+                     * on an r200 GPU creates scratch ATI2N texture even though the card doesn't
+                     * support it. */
+                    if (!formats[i].core_fmt && !format_known && FAILED(expect_hr))
+                        may_succeed = TRUE;
+
+                    ok(hr == expect_hr || ((SUCCEEDED(hr) && may_succeed)),
+                            "Got unexpected hr %#x for format %s, pool %s, type %s, size %ux%u.\n",
+                            hr, formats[i].name, create_tests[j].pool_name, create_tests[j].type_name, w, h);
+                    if (FAILED(hr))
+                        ok(*check_null == NULL, "Got object ptr %p, expected NULL.\n", *check_null);
+                    else
+                        IUnknown_Release(*check_null);
+                }
+            }
+        }
+
         surface_only = FALSE;
-        if (FAILED(IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
-                D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, formats[i].fmt)))
+        hr = IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
+                D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, formats[i].fmt);
+        dynamic_tex_support = SUCCEEDED(hr);;
+        if (!dynamic_tex_support)
         {
-            if (FAILED(IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8,
-                    0, D3DRTYPE_SURFACE, formats[i].fmt)))
+            if (!surface_support)
             {
                 skip("Format %s not supported, skipping lockrect offset tests.\n", formats[i].name);
                 continue;
@@ -5997,6 +6154,44 @@ static void test_surface_lockrect_blocks(void)
 
             IDirect3DSurface9_Release(surface);
         }
+
+        if (!dynamic_tex_support)
+        {
+            skip("Dynamic %s textures not supported, skipping mipmap test.\n", formats[i].name);
+            continue;
+        }
+
+        if (formats[i].block_width == 1 && formats[i].block_height == 1)
+            continue;
+        if (!formats[i].core_fmt)
+            continue;
+
+        hr = IDirect3DDevice9_CreateTexture(device, formats[i].block_width, formats[i].block_height, 2,
+                D3DUSAGE_DYNAMIC, formats[i].fmt, D3DPOOL_DEFAULT, &texture, NULL);
+        ok(SUCCEEDED(hr), "Failed to create texture, hr %#x, format %s.\n", hr, formats[i].name);
+
+        hr = IDirect3DTexture9_LockRect(texture, 1, &locked_rect, NULL, 0);
+        ok(SUCCEEDED(hr), "Failed lock texture, hr %#x.\n", hr);
+        hr = IDirect3DTexture9_UnlockRect(texture, 1);
+        ok(SUCCEEDED(hr), "Failed lock texture, hr %#x.\n", hr);
+
+        rect.left = 0;
+        rect.top = 0;
+        rect.right = formats[i].block_width == 1 ? 1 : formats[i].block_width >> 1;
+        rect.bottom = formats[i].block_height == 1 ? 1 : formats[i].block_height >> 1;
+        hr = IDirect3DTexture9_LockRect(texture, 1, &locked_rect, &rect, 0);
+        ok(SUCCEEDED(hr), "Failed lock texture, hr %#x.\n", hr);
+        hr = IDirect3DTexture9_UnlockRect(texture, 1);
+        ok(SUCCEEDED(hr), "Failed lock texture, hr %#x.\n", hr);
+
+        rect.right = formats[i].block_width;
+        rect.bottom = formats[i].block_height;
+        hr = IDirect3DTexture9_LockRect(texture, 1, &locked_rect, &rect, 0);
+        todo_wine ok(hr == D3DERR_INVALIDCALL, "Got unexpected hr %#x.\n", hr);
+        if (SUCCEEDED(hr))
+            IDirect3DTexture9_UnlockRect(texture, 1);
+
+        IDirect3DTexture9_Release(texture);
     }
 
     refcount = IDirect3DDevice9_Release(device);
@@ -6779,7 +6974,7 @@ START_TEST(device)
         test_surface_dimensions();
         test_surface_format_null();
         test_surface_double_unlock();
-        test_surface_lockrect_blocks();
+        test_surface_blocks();
         test_set_palette();
         test_swvp_buffer();
         test_rtpatch();
-- 
1.8.1.5




More information about the wine-patches mailing list