From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/d3dx9_36/tests/d3dx9_test_images.h | 43 +++++ dlls/d3dx9_36/tests/surface.c | 237 ++++++++++++++++++++++-- 2 files changed, 266 insertions(+), 14 deletions(-) diff --git a/dlls/d3dx9_36/tests/d3dx9_test_images.h b/dlls/d3dx9_36/tests/d3dx9_test_images.h index 49fa4135ca6..c6e59ef0efc 100644 --- a/dlls/d3dx9_36/tests/d3dx9_test_images.h +++ b/dlls/d3dx9_36/tests/d3dx9_test_images.h @@ -95,6 +95,24 @@ test_filter_values[] = { 0xff800001, D3DERR_INVALIDCALL }, }; +static inline const char *debug_d3dx_filter(uint32_t filter_flags) +{ + static const char *filter_types[] = { "", "D3DX_FILTER_NONE", "D3DX_FILTER_POINT", "D3DX_FILTER_LINEAR", + "D3DX_FILTER_TRIANGLE", "D3DX_FILTER_BOX", "", "" }; + static const char *srgb_types[] = { "", "|D3DX_FILTER_SRGB_IN", "|D3DX_FILTER_SRGB_OUT", "|D3DX_FILTER_SRGB" }; + static const char *dither_types[] = { "", "|D3DX_FILTER_DITHER", "|D3DX_FILTER_DITHER_DIFFUSION", ""}; + static const char *mirror_types[] = { "", "|D3DX_FILTER_MIRROR_U", "|D3DX_FILTER_MIRROR_V", + "|D3DX_FILTER_MIRROR_U|D3DX_FILTER_MIRROR_V", "|D3DX_FILTER_MIRROR_W", + "|D3DX_FILTER_MIRROR_U|D3DX_FILTER_MIRROR_W", + "|D3DX_FILTER_MIRROR_V|D3DX_FILTER_MIRROR_W", "|D3DX_FILTER_MIRROR", }; + const uint8_t mirror = ((filter_flags >> 16) & 0x7); + const uint8_t dither = ((filter_flags >> 19) & 0x3); + const uint8_t srgb = ((filter_flags >> 21) & 0x3); + const uint8_t filter = (filter_flags & 0x7); + + return wine_dbg_sprintf("%s%s%s%s", filter_types[filter], mirror_types[mirror], dither_types[dither], srgb_types[srgb]); +} + static const PALETTEENTRY test_palette[256] = { {0x00,0x00,0x00,0x00}, {0x00,0x00,0x80,0x01}, {0x00,0x80,0x00,0x02}, {0x00,0x80,0x80,0x03}, @@ -1972,6 +1990,19 @@ static inline BOOL compare_uint(uint32_t x, uint32_t y, uint32_t max_diff) return diff <= max_diff; } +static inline BOOL compare_float(float f, float g, uint32_t ulps) +{ + int32_t x = *(int32_t *)&f; + int32_t y = *(int32_t *)&g; + + if (x < 0) + x = INT_MIN - x; + if (y < 0) + y = INT_MIN - y; + + return compare_uint(x, y, ulps); +} + static inline BOOL compare_color_4bpp(uint32_t c1, uint32_t c2, uint8_t max_diff) { return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) @@ -2008,6 +2039,15 @@ static inline BOOL check_readback_pixel_4bpp_rgba(const void *got, const void *e return compare_color_4bpp(*a, *b, max_diff); } +static inline BOOL check_readback_pixel_float4_rgba(const void *got, const void *expected, uint32_t max_diff) +{ + const float *a = got; + const float *b = expected; + + return (compare_float(a[0], b[0], max_diff) && compare_float(a[1], b[1], max_diff) + && compare_float(a[2], b[2], max_diff) && compare_float(a[3], b[3], max_diff)); +} + typedef BOOL (*check_readback_pixel_func)(const void *, const void *, uint32_t); static inline check_readback_pixel_func get_readback_pixel_func_for_d3dformat(D3DFORMAT format) { @@ -2017,6 +2057,9 @@ static inline check_readback_pixel_func get_readback_pixel_func_for_d3dformat(D3 case D3DFMT_A8R8G8B8: return check_readback_pixel_4bpp_rgba; + case D3DFMT_A32B32G32R32F: + return check_readback_pixel_float4_rgba; + default: assert(0 && "Need to add format to get_readback_pixel_func_for_d3dformat()."); return 0; diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 1f2596e1cac..99a6af38ae8 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -26,19 +26,6 @@ #include <stdint.h> #include "d3dx9_test_images.h" -static BOOL compare_float(float f, float g, uint32_t ulps) -{ - int32_t x = *(int32_t *)&f; - int32_t y = *(int32_t *)&g; - - if (x < 0) - x = INT_MIN - x; - if (y < 0) - y = INT_MIN - y; - - return compare_uint(x, y, ulps); -} - #define check_release(obj, exp) _check_release(__LINE__, obj, exp) static inline void _check_release(unsigned int line, IUnknown *obj, int exp) { @@ -1252,6 +1239,28 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) { 0x22,0xcc,0x86,0xc6,0xe6,0x86,0xc6,0xe6,0x10,0x84,0x10,0x84,0x00,0x00,0x00,0x00, }; + static const uint8_t dxt2_block_srgb[] = + { + 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x86,0x31,0x04,0x21,0x11,0x11,0x11,0x11, + }; + static const uint8_t dxt4_block_srgb[] = + { + 0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x31,0x04,0x21,0x11,0x11,0x11,0x11, + }; + static const uint8_t dxt_srgb_in_expected[] = + { + 0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88,0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88, + 0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88,0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88, + 0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88,0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88, + 0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88,0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88, + }; + static const uint8_t dxt_srgb_out_expected[] = + { + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + }; static const uint32_t test_compress_pixels[] = { 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, @@ -1269,9 +1278,10 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) { D3DFMT_DXT4, D3DFMT_DXT5, dxt5_block, "DXT4 / DXT5" }, }; static const RECT src_rect = { 0, 0, 4, 4 }; - IDirect3DSurface9 *decomp_surf; + IDirect3DSurface9 *decomp_surf, *comp_surf; D3DLOCKED_RECT lock_rect; uint32_t i, x, y; + uint8_t tmp[16]; HRESULT hr; hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &decomp_surf, NULL); @@ -1374,6 +1384,71 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) IDirect3DTexture9_Release(tex); winetest_pop_context(); } + + /* + * DXT2/DXT4 combined with SRGB filter flags. Premultiplied alpha is + * undone prior to undoing the SRGB conversion, and vice versa. + */ + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, dxt2_block_srgb, D3DFMT_DXT2, 16, NULL, &src_rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_in_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 1); + IDirect3DSurface9_UnlockRect(decomp_surf); + + /* DXT4, SRGB in. */ + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, dxt4_block_srgb, D3DFMT_DXT4, 16, NULL, &src_rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_in_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 1); + IDirect3DSurface9_UnlockRect(decomp_surf); + + /* + * DXT2, SRGB out. SRGB conversion is done first, and then premultiplied + * by alpha. + */ + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_DXT2, D3DPOOL_SCRATCH, &comp_surf, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(comp_surf, NULL, NULL, dxt_srgb_in_expected, D3DFMT_A8R8G8B8, 16, NULL, &src_rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(comp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + memcpy(tmp, lock_rect.pBits, 16); + IDirect3DSurface9_UnlockRect(comp_surf); + IDirect3DSurface9_Release(comp_surf); + + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, tmp, D3DFMT_DXT3, 16, NULL, &src_rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_out_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 0); + IDirect3DSurface9_UnlockRect(decomp_surf); + + /* DXT4, SRGB out. */ + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_DXT4, D3DPOOL_SCRATCH, &comp_surf, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(comp_surf, NULL, NULL, dxt_srgb_in_expected, D3DFMT_A8R8G8B8, 16, NULL, &src_rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(comp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + memcpy(tmp, lock_rect.pBits, 16); + IDirect3DSurface9_UnlockRect(comp_surf); + IDirect3DSurface9_Release(comp_surf); + + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, tmp, D3DFMT_DXT5, 16, NULL, &src_rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_out_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 0); + IDirect3DSurface9_UnlockRect(decomp_surf); + IDirect3DSurface9_Release(decomp_surf); } @@ -5281,6 +5356,139 @@ static void test_image_filters(void) DestroyWindow(hwnd); } +static void test_srgb_filter_flags(void) +{ + static const float test_float4_srgb_in[] = + { + 0.0900000f, 0.1000000f, 0.2000000f, 1.0f, + 0.3000000f, 0.4000000f, 0.5000000f, 2.0f, + 0.6000000f, 0.7000000f, 0.8000000f, 3.0f, + 0.9000000f, 1.5000000f, -1.0000000f, 4.0f, + }; + static const float test_float4_srgb_in_expected[] = + { + 5.00732847e-003, 6.32313965e-003, 2.89932229e-002, 1.00000000e+000, + 7.07411841e-002, 1.33209527e-001, 2.17638373e-001, 2.00000000e+000, + 3.25037479e-001, 4.56263810e-001, 6.12065971e-001, 3.00000000e+000, + 7.93110251e-001, 1.54501167e-009, 1.00000000e+000, 4.00000000e+000, + }; + static const float test_float4_srgb_in_expected_32[] = + { + 5.00732800e-003, 6.32313825e-003, 2.89932154e-002, 1.00000000e+000, + 7.07411841e-002, 1.33209497e-001, 2.17638358e-001, 2.00000000e+000, + 3.25037479e-001, 4.56263781e-001, 6.12065852e-001, 3.00000000e+000, + /* + * On 32-bit d3dx9, an input value of 1.5f being converted from SRGB + * to linear produces quite a few different values depending on the + * SDK version. Presumably it's reading beyond the end of a LUT. + */ +#if D3DX_SDK_VERSION <= 36 + 7.93110192e-001, 7.85714269e-001, 1.00000000e+000, 4.00000000e+000, +#else + 7.93110192e-001, 4.68750000e-001, 1.00000000e+000, 4.00000000e+000, +#endif + }; + static const float test_float4_srgb_out[] = + { + 0.0010000f, 0.1000000f, 0.2000000f, 1.0f, + 0.3000000f, 0.4000000f, 0.5000000f, 2.0f, + 0.6000000f, 0.7000000f, 0.8000000f, 3.0f, + 0.9000000f, 1.5000000f, -1.0000000f, 4.0f, + }; + static const float test_float4_srgb_out_expected[] = + { + 4.32867892e-002, 3.51118684e-001, 4.81156141e-001, 1.00000000e+000, + 5.78532457e-001, 6.59353077e-001, 7.29739845e-001, 2.00000000e+000, + 7.92792618e-001, 8.50334764e-001, 9.03545380e-001, 3.00000000e+000, + 9.53237534e-001, 1.86132386e-001, -NAN, 4.00000000e+000, + }; + static const float test_float4_srgb_out_expected_32[] = + { + 4.32868116e-002, 3.51118803e-001, 4.81156349e-001, 1.00000000e+000, + 5.78532696e-001, 6.59353256e-001, 7.29739845e-001, 2.00000000e+000, + 7.92793036e-001, 8.50335181e-001, 9.03545737e-001, 3.00000000e+000, + 9.53237772e-001, 1.86132386e-001, -INFINITY, 4.00000000e+000, + + }; + static const uint32_t test_a8r8g8b8[] = { 0x00102030, 0x40506070, 0x8090a0b0, 0xc0d0e0ff }; + static const uint32_t test_a8r8g8b8_srgb_in_expected[] = { 0x00010306, 0x40141e2a, 0x80495b71, 0xc0a3c0ff }; + static const uint32_t test_a8r8g8b8_srgb_out_expected[] = { 0x00486377, 0x4097a4af, 0x80c5ced7, 0xc0e8f0ff }; + static const struct + { + const RECT src_rect; + const void *src_data; + D3DFORMAT format; + DWORD flags; + + const void *expected_dst_data; + const void *expected_dst_data_32; + BOOL todo; + } tests[] = + { + /* Both IN and OUT flags, nothing changes. */ + { + { 0, 0, 2, 2 }, test_a8r8g8b8, D3DFMT_A8R8G8B8, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN | D3DX_FILTER_SRGB_OUT, + test_a8r8g8b8 + }, + { + { 0, 0, 2, 2 }, test_a8r8g8b8, D3DFMT_A8R8G8B8, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, + test_a8r8g8b8_srgb_in_expected, .todo = TRUE + }, + { + { 0, 0, 2, 2 }, test_a8r8g8b8, D3DFMT_A8R8G8B8, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, + test_a8r8g8b8_srgb_out_expected, .todo = TRUE + }, + { + { 0, 0, 2, 2 }, test_float4_srgb_in, D3DFMT_A32B32G32R32F, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, + test_float4_srgb_in_expected, test_float4_srgb_in_expected_32, .todo = TRUE + }, + { + { 0, 0, 2, 2 }, test_float4_srgb_out, D3DFMT_A32B32G32R32F, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, + test_float4_srgb_out_expected, test_float4_srgb_out_expected_32, .todo = TRUE + }, + }; + const BOOL is_32 = (sizeof(void *) == 4); + IDirect3DDevice9 *device; + D3DLOCKED_RECT lock_rect; + IDirect3DSurface9 *surf; + unsigned int i; + HRESULT hr; + HWND hwnd; + + if (!(device = create_device(&hwnd))) + return; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + const unsigned int fmt_bpp = get_bpp_for_d3dformat(tests[i].format); + unsigned int width = tests[i].src_rect.right - tests[i].src_rect.left; + unsigned int height = tests[i].src_rect.bottom- tests[i].src_rect.top; + unsigned int src_pitch = fmt_bpp * width; + const uint8_t *expected_dst; + + winetest_push_context("Test %u (%s)", i, debug_d3dx_filter(tests[i].flags)); + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, tests[i].format, D3DPOOL_SCRATCH, + &surf, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, tests[i].src_data, tests[i].format, + src_pitch, NULL, &tests[i].src_rect, tests[i].flags, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + expected_dst = (is_32 && tests[i].expected_dst_data_32) ? tests[i].expected_dst_data_32 : tests[i].expected_dst_data; + IDirect3DSurface9_LockRect(surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine_if(tests[i].todo) check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, expected_dst, width, + height, 1, tests[i].format, 0); + IDirect3DSurface9_UnlockRect(surf); + + winetest_pop_context(); + } + + check_release((IUnknown *)surf, 0); + winetest_pop_context(); +} + START_TEST(surface) { HWND wnd; @@ -5324,4 +5532,5 @@ START_TEST(surface) test_color_key(); test_image_filters(); + test_srgb_filter_flags(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10513