diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index f805228da87..17664b16b2b 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 d705e3e7263..2514153e5d4 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) { - surface_only = FALSE; - if (FAILED(IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, - D3DUSAGE_DYNAMIC, D3DRTYPE_TEXTURE, formats[i].fmt))) + 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++) { - if (FAILED(IDirect3D9_CheckDeviceFormat(d3d, 0, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, - 0, D3DRTYPE_SURFACE, formats[i].fmt))) + 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; + 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 (!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();