This is the initial set of patches for handling new pixel format types. I've pushed a branch [here](https://gitlab.winehq.org/cmcadams/wine/-/commits/WIP/d3dx-shared-source-v13) containing the rest of my current patches if additional context would be useful, the new format handling patches end with `ed7022a0838b346f4fa2b229ce7e8e6b8ebc2244`.
-- v5: d3dx9: Use format_from_d3dx_color() instead of fill_texture(). d3dx9: Add support for D3DFMT_V8U8. d3dx9: Add support for D3DFMT_Q8W8V8U8. d3dx9: Store pixel value range alongside pixel values when reading pixels. d3dx9: Clamp source components to unorm range. d3dx9/tests: Add format conversion tests for premultiplied alpha DXTn formats. d3dx9/tests: Add more d3d format conversion tests.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/surface.c | 642 ++++++++++++++++++++++++++++++++++ 1 file changed, 642 insertions(+)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index fdc573c3e55..ca10054fe2e 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -26,6 +26,26 @@ #include <stdint.h> #include "d3dx9_test_images.h"
+static BOOL compare_uint(uint32_t x, uint32_t y, uint32_t max_diff) +{ + uint32_t diff = x > y ? x - y : y - x; + + return diff <= max_diff; +} + +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) { @@ -755,6 +775,22 @@ static inline void _check_pixel_4bpp(unsigned int line, const D3DLOCKED_RECT *lo ok_(__FILE__, line)(color == expected_color, "Got color 0x%08lx, expected 0x%08lx\n", color, expected_color); }
+#define check_pixel_float4(lockrect, x, y, fx, fy, fz, fw, ulps, todo) \ + _check_pixel_float4(__LINE__, lockrect, x, y, fx, fy, fz, fw, ulps, todo) +static inline void _check_pixel_float4(uint32_t line, const D3DLOCKED_RECT *lockrect, uint32_t x, uint32_t y, + float fx, float fy, float fz, float fw, uint32_t ulps, BOOL todo) +{ + float *ptr = (float *)(((BYTE *)lockrect->pBits) + (y * lockrect->Pitch) + (x * sizeof(float) * 4)); + + todo_wine_if(todo) ok_(__FILE__, line)(compare_float(fx, ptr[0], ulps) + && compare_float(fy, ptr[1], ulps) + && compare_float(fz, ptr[2], ulps) + && compare_float(fw, ptr[3], ulps), + "Expected (%.8e, %.8e, %.8e, %.8e), got (%.8e, %.8e, %.8e, %.8e)\n", + fx, fy, fz, fw, + ptr[0], ptr[1], ptr[2], ptr[3]); +} + #define check_readback_pixel_4bpp(rb, x, y, color, todo) _check_readback_pixel_4bpp(__LINE__, rb, x, y, color, todo) static inline void _check_readback_pixel_4bpp(unsigned int line, struct surface_readback *rb, uint32_t x, uint32_t y, uint32_t expected_color, BOOL todo) @@ -763,6 +799,287 @@ static inline void _check_readback_pixel_4bpp(unsigned int line, struct surface_ todo_wine_if(todo) ok_(__FILE__, line)(color == expected_color, "Got color 0x%08x, expected 0x%08x.\n", color, expected_color); }
+static const PALETTEENTRY test_palette[256] = +{ + {0x00,0x00,0x00,0x00}, {0x00,0x00,0x80,0x01}, {0x00,0x80,0x00,0x02}, {0x00,0x80,0x80,0x03}, + {0x80,0x00,0x00,0x04}, {0x80,0x00,0x80,0x05}, {0x80,0x80,0x00,0x06}, {0xc0,0xc0,0xc0,0x07}, + {0xc0,0xdc,0xc0,0x08}, {0xf0,0xca,0xa6,0x09}, {0x00,0x20,0x40,0x0a}, {0x00,0x20,0x60,0x0b}, + {0x00,0x20,0x80,0x0c}, {0x00,0x20,0xa0,0x0d}, {0x00,0x20,0xc0,0x0e}, {0x00,0x20,0xe0,0x0f}, + + {0x00,0x40,0x00,0x10}, {0x00,0x40,0x20,0x11}, {0x00,0x40,0x40,0x12}, {0x00,0x40,0x60,0x13}, + {0x00,0x40,0x80,0x14}, {0x00,0x40,0xa0,0x15}, {0x00,0x40,0xc0,0x16}, {0x00,0x40,0xe0,0x17}, + {0x00,0x60,0x00,0x18}, {0x00,0x60,0x20,0x19}, {0x00,0x60,0x40,0x1a}, {0x00,0x60,0x60,0x1b}, + {0x00,0x60,0x80,0x1c}, {0x00,0x60,0xa0,0x1d}, {0x00,0x60,0xc0,0x1e}, {0x00,0x60,0xe0,0x1f}, + + {0x00,0x80,0x00,0x20}, {0x00,0x80,0x20,0x21}, {0x00,0x80,0x40,0x22}, {0x00,0x80,0x60,0x23}, + {0x00,0x80,0x80,0x24}, {0x00,0x80,0xa0,0x25}, {0x00,0x80,0xc0,0x26}, {0x00,0x80,0xe0,0x27}, + {0x00,0xa0,0x00,0x28}, {0x00,0xa0,0x20,0x29}, {0x00,0xa0,0x40,0x2a}, {0x00,0xa0,0x60,0x2b}, + {0x00,0xa0,0x80,0x2c}, {0x00,0xa0,0xa0,0x2d}, {0x00,0xa0,0xc0,0x2e}, {0x00,0xa0,0xe0,0x2f}, + + {0x00,0xc0,0x00,0x30}, {0x00,0xc0,0x20,0x31}, {0x00,0xc0,0x40,0x32}, {0x00,0xc0,0x60,0x33}, + {0x00,0xc0,0x80,0x34}, {0x00,0xc0,0xa0,0x35}, {0x00,0xc0,0xc0,0x36}, {0x00,0xc0,0xe0,0x37}, + {0x00,0xe0,0x00,0x38}, {0x00,0xe0,0x20,0x39}, {0x00,0xe0,0x40,0x3a}, {0x00,0xe0,0x60,0x3b}, + {0x00,0xe0,0x80,0x3c}, {0x00,0xe0,0xa0,0x3d}, {0x00,0xe0,0xc0,0x3e}, {0x00,0xe0,0xe0,0x3f}, + + {0x40,0x00,0x00,0x40}, {0x40,0x00,0x20,0x41}, {0x40,0x00,0x40,0x42}, {0x40,0x00,0x60,0x43}, + {0x40,0x00,0x80,0x44}, {0x40,0x00,0xa0,0x45}, {0x40,0x00,0xc0,0x46}, {0x40,0x00,0xe0,0x47}, + {0x40,0x20,0x00,0x48}, {0x40,0x20,0x20,0x49}, {0x40,0x20,0x40,0x4a}, {0x40,0x20,0x60,0x4b}, + {0x40,0x20,0x80,0x4c}, {0x40,0x20,0xa0,0x4d}, {0x40,0x20,0xc0,0x4e}, {0x40,0x20,0xe0,0x4f}, + + {0x40,0x40,0x00,0x50}, {0x40,0x40,0x20,0x51}, {0x40,0x40,0x40,0x52}, {0x40,0x40,0x60,0x53}, + {0x40,0x40,0x80,0x54}, {0x40,0x40,0xa0,0x55}, {0x40,0x40,0xc0,0x56}, {0x40,0x40,0xe0,0x57}, + {0x40,0x60,0x00,0x58}, {0x40,0x60,0x20,0x59}, {0x40,0x60,0x40,0x5a}, {0x40,0x60,0x60,0x5b}, + {0x40,0x60,0x80,0x5c}, {0x40,0x60,0xa0,0x5d}, {0x40,0x60,0xc0,0x5e}, {0x40,0x60,0xe0,0x5f}, + + {0x40,0x80,0x00,0x60}, {0x40,0x80,0x20,0x61}, {0x40,0x80,0x40,0x62}, {0x40,0x80,0x60,0x63}, + {0x40,0x80,0x80,0x64}, {0x40,0x80,0xa0,0x65}, {0x40,0x80,0xc0,0x66}, {0x40,0x80,0xe0,0x67}, + {0x40,0xa0,0x00,0x68}, {0x40,0xa0,0x20,0x69}, {0x40,0xa0,0x40,0x6a}, {0x40,0xa0,0x60,0x6b}, + {0x40,0xa0,0x80,0x6c}, {0x40,0xa0,0xa0,0x6d}, {0x40,0xa0,0xc0,0x6e}, {0x40,0xa0,0xe0,0x6f}, + + {0x40,0xc0,0x00,0x70}, {0x40,0xc0,0x20,0x71}, {0x40,0xc0,0x40,0x72}, {0x40,0xc0,0x60,0x73}, + {0x40,0xc0,0x80,0x74}, {0x40,0xc0,0xa0,0x75}, {0x40,0xc0,0xc0,0x76}, {0x40,0xc0,0xe0,0x77}, + {0x40,0xe0,0x00,0x78}, {0x40,0xe0,0x20,0x79}, {0x40,0xe0,0x40,0x7a}, {0x40,0xe0,0x60,0x7b}, + {0x40,0xe0,0x80,0x7c}, {0x40,0xe0,0xa0,0x7d}, {0x40,0xe0,0xc0,0x7e}, {0x40,0xe0,0xe0,0x7f}, + + {0x80,0x00,0x00,0x80}, {0x80,0x00,0x20,0x81}, {0x80,0x00,0x40,0x82}, {0x80,0x00,0x60,0x83}, + {0x80,0x00,0x80,0x84}, {0x80,0x00,0xa0,0x85}, {0x80,0x00,0xc0,0x86}, {0x80,0x00,0xe0,0x87}, + {0x80,0x20,0x00,0x88}, {0x80,0x20,0x20,0x89}, {0x80,0x20,0x40,0x8a}, {0x80,0x20,0x60,0x8b}, + {0x80,0x20,0x80,0x8c}, {0x80,0x20,0xa0,0x8d}, {0x80,0x20,0xc0,0x8e}, {0x80,0x20,0xe0,0x8f}, + + {0x80,0x40,0x00,0x90}, {0x80,0x40,0x20,0x91}, {0x80,0x40,0x40,0x92}, {0x80,0x40,0x60,0x93}, + {0x80,0x40,0x80,0x94}, {0x80,0x40,0xa0,0x95}, {0x80,0x40,0xc0,0x96}, {0x80,0x40,0xe0,0x97}, + {0x80,0x60,0x00,0x98}, {0x80,0x60,0x20,0x99}, {0x80,0x60,0x40,0x9a}, {0x80,0x60,0x60,0x9b}, + {0x80,0x60,0x80,0x9c}, {0x80,0x60,0xa0,0x9d}, {0x80,0x60,0xc0,0x9e}, {0x80,0x60,0xe0,0x9f}, + + {0x80,0x80,0x00,0xa0}, {0x80,0x80,0x20,0xa1}, {0x80,0x80,0x40,0xa2}, {0x80,0x80,0x60,0xa3}, + {0x80,0x80,0x80,0xa4}, {0x80,0x80,0xa0,0xa5}, {0x80,0x80,0xc0,0xa6}, {0x80,0x80,0xe0,0xa7}, + {0x80,0xa0,0x00,0xa8}, {0x80,0xa0,0x20,0xa9}, {0x80,0xa0,0x40,0xaa}, {0x80,0xa0,0x60,0xab}, + {0x80,0xa0,0x80,0xac}, {0x80,0xa0,0xa0,0xad}, {0x80,0xa0,0xc0,0xae}, {0x80,0xa0,0xe0,0xaf}, + + {0x80,0xc0,0x00,0xb0}, {0x80,0xc0,0x20,0xb1}, {0x80,0xc0,0x40,0xb2}, {0x80,0xc0,0x60,0xb3}, + {0x80,0xc0,0x80,0xb4}, {0x80,0xc0,0xa0,0xb5}, {0x80,0xc0,0xc0,0xb6}, {0x80,0xc0,0xe0,0xb7}, + {0x80,0xe0,0x00,0xb8}, {0x80,0xe0,0x20,0xb9}, {0x80,0xe0,0x40,0xba}, {0x80,0xe0,0x60,0xbb}, + {0x80,0xe0,0x80,0xbc}, {0x80,0xe0,0xa0,0xbd}, {0x80,0xe0,0xc0,0xbe}, {0x80,0xe0,0xe0,0xbf}, + + {0xc0,0x00,0x00,0xc0}, {0xc0,0x00,0x20,0xc1}, {0xc0,0x00,0x40,0xc2}, {0xc0,0x00,0x60,0xc3}, + {0xc0,0x00,0x80,0xc4}, {0xc0,0x00,0xa0,0xc5}, {0xc0,0x00,0xc0,0xc6}, {0xc0,0x00,0xe0,0xc7}, + {0xc0,0x20,0x00,0xc8}, {0xc0,0x20,0x20,0xc9}, {0xc0,0x20,0x40,0xca}, {0xc0,0x20,0x60,0xcb}, + {0xc0,0x20,0x80,0xcc}, {0xc0,0x20,0xa0,0xcd}, {0xc0,0x20,0xc0,0xce}, {0xc0,0x20,0xe0,0xcf}, + + {0xc0,0x40,0x00,0xd0}, {0xc0,0x40,0x20,0xd1}, {0xc0,0x40,0x40,0xd2}, {0xc0,0x40,0x60,0xd3}, + {0xc0,0x40,0x80,0xd4}, {0xc0,0x40,0xa0,0xd5}, {0xc0,0x40,0xc0,0xd6}, {0xc0,0x40,0xe0,0xd7}, + {0xc0,0x60,0x00,0xd8}, {0xc0,0x60,0x20,0xd9}, {0xc0,0x60,0x40,0xda}, {0xc0,0x60,0x60,0xdb}, + {0xc0,0x60,0x80,0xdc}, {0xc0,0x60,0xa0,0xdd}, {0xc0,0x60,0xc0,0xde}, {0xc0,0x60,0xe0,0xdf}, + + {0xc0,0x80,0x00,0xe0}, {0xc0,0x80,0x20,0xe1}, {0xc0,0x80,0x40,0xe2}, {0xc0,0x80,0x60,0xe3}, + {0xc0,0x80,0x80,0xe4}, {0xc0,0x80,0xa0,0xe5}, {0xc0,0x80,0xc0,0xe6}, {0xc0,0x80,0xe0,0xe7}, + {0xc0,0xa0,0x00,0xe8}, {0xc0,0xa0,0x20,0xe9}, {0xc0,0xa0,0x40,0xea}, {0xc0,0xa0,0x60,0xeb}, + {0xc0,0xa0,0x80,0xec}, {0xc0,0xa0,0xa0,0xed}, {0xc0,0xa0,0xc0,0xee}, {0xc0,0xa0,0xe0,0xef}, + + {0xc0,0xc0,0x00,0xf0}, {0xc0,0xc0,0x20,0xf1}, {0xc0,0xc0,0x40,0xf2}, {0xc0,0xc0,0x60,0xf3}, + {0xc0,0xc0,0x80,0xf4}, {0xc0,0xc0,0xa0,0xf5}, {0xf0,0xfb,0xff,0xf6}, {0xa4,0xa0,0xa0,0xf7}, + {0x80,0x80,0x80,0xf8}, {0x00,0x00,0xff,0xf9}, {0x00,0xff,0x00,0xfa}, {0x00,0xff,0xff,0xfb}, + {0xff,0x00,0x00,0xfc}, {0xff,0x00,0xff,0xfd}, {0xff,0xff,0x00,0xfe}, {0xff,0xff,0xff,0xff}, +}; + +static const uint16_t v16u16_2_2[] = +{ + 0x0000, 0x3000, 0x4000, 0x7fff, 0x8000, 0x8001, 0xc000, 0xffff, +}; + +static const uint8_t v16u16_2_2_expected[] = +{ + 0x00,0x80,0x00,0xb0,0x00,0xc0,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0x3f,0xff,0x7f, +}; + +static const uint8_t v16u16_2_2_expected2[] = +{ + 0x00,0x00,0x00,0x00,0x80,0x01,0xc0,0x3e,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, + 0x00,0x01,0x00,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, + 0x00,0x01,0x00,0xbf,0x00,0x01,0x00,0xb8,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, +}; + +static const uint8_t v8u8_2_2[] = +{ + 0x00,0x30,0x40,0x7f,0x80,0x81,0xc0,0xff, +}; + +static const uint8_t v8u8_2_2_expected[] = +{ + 0x00,0x00,0x00,0x00,0x06,0x83,0xc1,0x3e,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, + 0x04,0x02,0x01,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, + 0x04,0x02,0x01,0xbf,0x04,0x02,0x01,0xbc,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, +}; + +static const uint16_t a16b16g16r16_2_2[] = +{ + 0x0000,0x1000,0x2000,0x3000,0x4000,0x5000,0x6000,0x7000, + 0x8000,0x9000,0xa000,0xb000,0xc000,0xd000,0xe000,0xffff, +}; + +static const uint8_t a16b16g16r16_2_2_expected[] = +{ + 0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x3d,0x80,0x00,0x00,0x3e,0xc0,0x00,0x40,0x3e, + 0x80,0x00,0x80,0x3e,0xa0,0x00,0xa0,0x3e,0xc0,0x00,0xc0,0x3e,0xe0,0x00,0xe0,0x3e, + 0x80,0x00,0x00,0x3f,0x90,0x00,0x10,0x3f,0xa0,0x00,0x20,0x3f,0xb0,0x00,0x30,0x3f, + 0xc0,0x00,0x40,0x3f,0xd0,0x00,0x50,0x3f,0xe0,0x00,0x60,0x3f,0x00,0x00,0x80,0x3f, +}; + +static const uint16_t q16w16v16u16_2_2[] = +{ + 0x0000,0x1000,0x2000,0x3000,0x4000,0x5000,0x6000,0x7fff, + 0x8000,0x8001,0xa000,0xb000,0xc000,0xd000,0xe000,0xffff, +}; + +static const uint8_t q16w16v16u16_2_2_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x3e,0x00,0x01,0x80,0x3e,0x80,0x01,0xc0,0x3e, + 0x00,0x01,0x00,0x3f,0x40,0x01,0x20,0x3f,0x80,0x01,0x40,0x3f,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0xbf,0x00,0x00,0x80,0xbf,0x80,0x01,0x40,0xbf,0x40,0x01,0x20,0xbf, + 0x00,0x01,0x00,0xbf,0x80,0x01,0xc0,0xbe,0x00,0x01,0x80,0xbe,0x00,0x01,0x00,0xb8, +}; + +static const uint8_t p8_2_2[] = +{ + 0x00,0x40,0x80,0xff, +}; + +static const uint8_t p8_2_2_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x00,0x80,0x80,0xff,0xff,0xff,0xff, +}; + +static const uint8_t a8p8_2_2[] = +{ + 0x00,0x10,0x40,0x20,0x80,0x30,0xff,0x40 +}; + +static const uint8_t a8p8_2_2_expected[] = +{ + 0x00,0x00,0x00,0x10,0x00,0x00,0x40,0x20,0x00,0x00,0x80,0x30,0xff,0xff,0xff,0x40, +}; + +static uint32_t get_bpp_for_d3dformat(D3DFORMAT format) +{ + switch (format) + { + case D3DFMT_A32B32G32R32F: + return 16; + + case D3DFMT_A16B16G16R16: + case D3DFMT_Q16W16V16U16: + return 8; + + case D3DFMT_A8R8G8B8: + case D3DFMT_V16U16: + case D3DFMT_G16R16: + return 4; + + case D3DFMT_V8U8: + case D3DFMT_A8P8: + return 2; + + case D3DFMT_P8: + return 1; + + default: + assert(0 && "Need to add format to get_bpp_for_d3dformat()."); + return 0; + } +} + +static void test_format_conversion(IDirect3DDevice9 *device) +{ + struct + { + D3DFORMAT src_format; + const PALETTEENTRY *src_palette; + const RECT src_rect; + const void *src_data; + + D3DFORMAT dst_format; + const void *expected_dst_data; + BOOL partial_todo; + BOOL todo; + } tests[] = { + { D3DFMT_P8, test_palette, { 0, 0, 2, 2 }, p8_2_2, D3DFMT_A8R8G8B8, p8_2_2_expected }, + { D3DFMT_A16B16G16R16, NULL, { 0, 0, 2, 2 }, a16b16g16r16_2_2, D3DFMT_A32B32G32R32F, a16b16g16r16_2_2_expected }, + { D3DFMT_V16U16, NULL, { 0, 0, 2, 2 }, v16u16_2_2, D3DFMT_G16R16, v16u16_2_2_expected, .todo = TRUE }, + { D3DFMT_V16U16, NULL, { 0, 0, 2, 2 }, v16u16_2_2, D3DFMT_A32B32G32R32F, v16u16_2_2_expected2, .todo = TRUE }, + { D3DFMT_V8U8, NULL, { 0, 0, 2, 2 }, v8u8_2_2, D3DFMT_A32B32G32R32F, v8u8_2_2_expected, .todo = TRUE }, + { D3DFMT_Q16W16V16U16, NULL, { 0, 0, 2, 2 }, q16w16v16u16_2_2, D3DFMT_A32B32G32R32F, q16w16v16u16_2_2_expected, .todo = TRUE }, + { D3DFMT_A8P8, test_palette, { 0, 0, 2, 2 }, a8p8_2_2, D3DFMT_A8R8G8B8, a8p8_2_2_expected, .todo = TRUE }, + }; + uint32_t i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + IDirect3DTexture9 *tex; + HRESULT hr; + + winetest_push_context("Test %u", i); + hr = IDirect3DDevice9_CreateTexture(device, tests[i].src_rect.right, tests[i].src_rect.bottom, 1, 0, + tests[i].dst_format, D3DPOOL_MANAGED, &tex, NULL); + if (SUCCEEDED(hr)) + { + const uint32_t src_pitch = get_bpp_for_d3dformat(tests[i].src_format) * tests[i].src_rect.right; + const uint32_t dst_pitch = get_bpp_for_d3dformat(tests[i].dst_format) * tests[i].src_rect.right; + IDirect3DSurface9 *surf; + + hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &surf); + ok(hr == D3D_OK, "Failed to get the surface, hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, tests[i].src_data, tests[i].src_format, + src_pitch, tests[i].src_palette, &tests[i].src_rect, D3DX_FILTER_NONE, 0); + todo_wine_if(tests[i].todo) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + const uint32_t dst_fmt_bpp = get_bpp_for_d3dformat(tests[i].dst_format); + uint32_t match_count, mismatch_count; + D3DLOCKED_RECT lock_rect; + uint32_t x, y; + + match_count = mismatch_count = 0; + IDirect3DSurface9_LockRect(surf, &lock_rect, NULL, D3DLOCK_READONLY); + for (y = 0; y < tests[i].src_rect.bottom; ++y) + { + const uint8_t *dst_expected_row = ((uint8_t *)tests[i].expected_dst_data) + (dst_pitch * y); + const uint8_t *dst_row = ((uint8_t *)lock_rect.pBits) + (lock_rect.Pitch * y); + + for (x = 0; x < tests[i].src_rect.right; ++x) + { + const uint8_t *dst_expected_pixel = dst_expected_row + (dst_fmt_bpp * x); + const uint8_t *dst_pixel = dst_row + (dst_fmt_bpp * x); + BOOL pixel_match = !memcmp(dst_pixel, dst_expected_pixel, dst_fmt_bpp); + + if (!pixel_match) + mismatch_count++; + else + match_count++; + + if (!pixel_match && tests[i].partial_todo) + continue; + todo_wine_if(tests[i].todo) ok(pixel_match, "Pixel mismatch at (%u,%u).\n", x, y); + } + } + + todo_wine_if(tests[i].partial_todo || tests[i].todo) ok(!mismatch_count, "%u mismatched pixels.\n", mismatch_count); + IDirect3DSurface9_UnlockRect(surf); + } + + check_release((IUnknown *)surf, 1); + check_release((IUnknown *)tex, 0); + } + else + { + skip("Failed to create texture for format %d, hr %#lx.\n", tests[i].dst_format, hr); + } + winetest_pop_context(); + } +} + static void test_D3DXLoadSurface(IDirect3DDevice9 *device) { HRESULT hr; @@ -779,6 +1096,13 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) static const DWORD pixdata_a8b8g8r8[] = { 0xc3394cf0, 0x235ae892, 0x09b197fd, 0x8dc32bf6 }; static const DWORD pixdata_a2r10g10b10[] = { 0x57395aff, 0x5b7668fd, 0xb0d856b5, 0xff2c61d6 }; static const uint32_t pixdata_a8r8g8b8[] = { 0x00102030, 0x40506070, 0x8090a0b0, 0xc0d0e0ff }; + static const uint32_t pixdata_a8b8g8r8_2[] = { 0x30201000, 0x70605040, 0xb0a09080, 0xffe0d0c0 }; + static const uint32_t pixdata_x8l8v8u8[] = { 0x00003000, 0x00557f40, 0x00aa8180, 0x00ffffc0 }; + static const uint32_t pixdata_a2w10v10u10[] = { 0x0ba17400, 0x5ff5d117, 0xae880600, 0xfffe8b45 }; + static const uint32_t pixdata_q8w8v8u8[] = { 0x30201000, 0x7f605040, 0xb0a08180, 0xffe0d0c0 }; + static const float pixdata_a32b32g32r32f[] = { 0.0f, 0.1f, NAN, INFINITY, 1.0f, 1.1f, 1.2f, 1.3f, + -0.1f, -0.2f, -NAN, -INFINITY, -1.0f, -1.1f, -1.2f, -1.3f }; + static const uint16_t pixdata_v8u8[] = { 0x3000, 0x7f40, 0x8180, 0xffc0 }; BYTE buffer[4 * 8 * 4]; uint32_t i;
@@ -1197,6 +1521,34 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DSurface9_UnlockRect(surf); ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
+ /* From a signed normalized format to an unsigned normalized format. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_4bpp(&lockrect, 0, 0, 0xb08090a0); + check_pixel_4bpp(&lockrect, 1, 0, 0xffc0d0e0); + check_pixel_4bpp(&lockrect, 0, 1, 0x2f00001f); + check_pixel_4bpp(&lockrect, 1, 1, 0x7e3f4f5f); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + } + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a32b32g32r32f, D3DFMT_A32B32G32R32F, 32, NULL, &rect, + D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0xff001aff); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0xffffffff); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x000000ff); + todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x00000000); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + /* Test D3DXLoadSurfaceFromMemory with indexed color image */ if (0) { @@ -1422,6 +1774,33 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DSurface9_UnlockRect(surf); ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
+ hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_2bpp(&lockrect, 0, 0, 0xb08d); + check_pixel_2bpp(&lockrect, 1, 0, 0xffce); + check_pixel_2bpp(&lockrect, 0, 1, 0x2f02); + check_pixel_2bpp(&lockrect, 1, 1, 0x7e4d); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + } + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a32b32g32r32f, D3DFMT_A32B32G32R32F, 32, NULL, &rect, + D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_2bpp(&lockrect, 0, 0, 0xff25); + todo_wine check_pixel_2bpp(&lockrect, 1, 0, 0xffff); + todo_wine check_pixel_2bpp(&lockrect, 0, 1, 0x0012); + todo_wine check_pixel_2bpp(&lockrect, 1, 1, 0x0000); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + check_release((IUnknown*)surf, 1); check_release((IUnknown*)tex, 0); } @@ -1646,6 +2025,269 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_release((IUnknown*)surf, 0); }
+ hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 2, 2, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &surf, NULL); + if (FAILED(hr)) + skip("Failed to create a D3DFMT_A32B32G32R32F surface, hr %#lx.\n", hr); + else + { + /* Direct copy. */ + SetRect(&rect, 0, 0, 2, 2); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a32b32g32r32f, D3DFMT_A32B32G32R32F, 32, NULL, &rect, + D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_float4(&lockrect, 0, 0, pixdata_a32b32g32r32f[0], pixdata_a32b32g32r32f[1], + pixdata_a32b32g32r32f[2], pixdata_a32b32g32r32f[3], 0, FALSE); + check_pixel_float4(&lockrect, 1, 0, pixdata_a32b32g32r32f[4], pixdata_a32b32g32r32f[5], + pixdata_a32b32g32r32f[6], pixdata_a32b32g32r32f[7], 0, FALSE); + check_pixel_float4(&lockrect, 0, 1, pixdata_a32b32g32r32f[8], pixdata_a32b32g32r32f[9], + pixdata_a32b32g32r32f[10], pixdata_a32b32g32r32f[11], 0, FALSE); + check_pixel_float4(&lockrect, 1, 1, pixdata_a32b32g32r32f[12], pixdata_a32b32g32r32f[13], + pixdata_a32b32g32r32f[14], pixdata_a32b32g32r32f[15], 0, FALSE); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* Signed normalized value to full range float. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_float4(&lockrect, 0, 0, 0.00000000e+000f, 1.25984251e-001f, 2.51968503e-001f, 3.77952754e-001f, 0, TRUE); + check_pixel_float4(&lockrect, 1, 0, 5.03937006e-001f, 6.29921257e-001f, 7.55905509e-001f, 1.00000000e+000f, 0, TRUE); + check_pixel_float4(&lockrect, 0, 1, -1.00000000e+000f, -1.00000000e+000f, -7.55905509e-001f, -6.29921257e-001f, 0, TRUE); + check_pixel_float4(&lockrect, 1, 1, -5.03937006e-001f, -3.77952754e-001f, -2.51968503e-001f, -7.87401572e-003f, 0, TRUE); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* Unsigned normalized value to full range float. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8_2, D3DFMT_A8B8G8R8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_float4(&lockrect, 0, 0, 0.00000000e+000f, 6.27451017e-002f, 1.25490203e-001f, 1.88235313e-001f, 1, FALSE); + check_pixel_float4(&lockrect, 1, 0, 2.50980407e-001f, 3.13725501e-001f, 3.76470625e-001f, 4.39215720e-001f, 1, FALSE); + check_pixel_float4(&lockrect, 0, 1, 5.01960814e-001f, 5.64705908e-001f, 6.27451003e-001f, 6.90196097e-001f, 0, FALSE); + check_pixel_float4(&lockrect, 1, 1, 7.52941251e-001f, 8.15686345e-001f, 8.78431439e-001f, 1.00000000e+000f, 1, FALSE); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* V8U8 snorm. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_v8u8, D3DFMT_V8U8, 4, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_float4(&lockrect, 0, 0, 0.00000000e+000f, 3.77952754e-001f, 1.0f, 1.0f, 0, TRUE); + check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 1.0f, 0, TRUE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 1.0f, 0, TRUE); + check_pixel_float4(&lockrect, 1, 1, -5.03937006e-001f, -7.87401572e-003f, 1.0f, 1.0f, 0, TRUE); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* A2W10V10U10 unorm/snorm. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a2w10v10u10, D3DFMT_A2W10V10U10, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_float4(&lockrect, 0, 0, 0.0f, 1.81996077e-001f, 3.63992155e-001f, 0.0f, 0, TRUE); + check_pixel_float4(&lockrect, 1, 0, 5.45988262e-001f, 7.27984309e-001f, 1.0f, 3.33333343e-001f, 0, TRUE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, -5.47945201e-001f, 6.66666687e-001f, 0, TRUE); + check_pixel_float4(&lockrect, 1, 1, -3.65949124e-001f, -1.83953032e-001f, -1.95694715e-003f, 1.0f, 0, TRUE); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* X8L8V8U8 unorm/snorm. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_x8l8v8u8, D3DFMT_X8L8V8U8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + /* The luma value goes into the alpha channel. */ + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_float4(&lockrect, 0, 0, 0.0, 3.77952754e-001f, 1.0f, 0.0f, 0, FALSE); + check_pixel_float4(&lockrect, 1, 0, 5.03937006e-001f, 1.0f, 1.0f, 3.33333343e-001, 0, FALSE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 6.66666687e-001, 0, FALSE); + check_pixel_float4(&lockrect, 1, 1, -5.03937006e-001f, -7.87401572e-003f, 1.0f, 1.0f, 0, FALSE); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + } + + check_release((IUnknown*)surf, 0); + } + + hr = IDirect3DDevice9_CreateTexture(device, 2, 2, 1, 0, D3DFMT_Q8W8V8U8, D3DPOOL_MANAGED, &tex, NULL); + if (FAILED(hr)) + skip("Failed to create D3DFMT_Q8W8V8U8 texture, hr %#lx.\n", hr); + else + { + hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &surf); + ok(hr == D3D_OK, "Failed to get the surface, hr %#lx.\n", hr); + + /* Snorm to snorm, direct copy. */ + SetRect(&rect, 0, 0, 2, 2); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_4bpp(&lockrect, 0, 0, pixdata_q8w8v8u8[0]); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, pixdata_q8w8v8u8[1]); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, pixdata_q8w8v8u8[2]); + todo_wine check_pixel_4bpp(&lockrect, 1, 1, pixdata_q8w8v8u8[3]); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* Unorm to snorm. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8, + D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0x43bbce70); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0xa5dc6812); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x8b31177d); + todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x0d43ad76); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* Full range float to snorm. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a32b32g32r32f, D3DFMT_A32B32G32R32F, 32, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0x7f7f0d00); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0x7f7f7f7f); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x827fe8f4); + todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x82828282); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* Unorm alpha and unorm luma to snorm. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8l8, D3DFMT_A8L8, 4, NULL, &rect, D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0x7f828282); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0x827f7f7f); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x7fb2b2b2); + check_pixel_4bpp(&lockrect, 1, 1, 0x00000000); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + check_release((IUnknown*)surf, 1); + check_release((IUnknown*)tex, 0); + } + + hr = IDirect3DDevice9_CreateTexture(device, 2, 2, 1, 0, D3DFMT_X8L8V8U8, D3DPOOL_MANAGED, &tex, NULL); + if (FAILED(hr)) + skip("Failed to create D3DFMT_X8L8V8U8 texture, hr %#lx.\n", hr); + else + { + hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &surf); + ok(hr == D3D_OK, "Failed to get the surface, hr %#lx.\n", hr); + + SetRect(&rect, 0, 0, 2, 2); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8_2, D3DFMT_A8B8G8R8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* + * The luma channel here doesn't do RGB->Luma conversion, it just + * copies the alpha channel directly as UNORM. V8 and U8 are snorm, + * pulled from r/g respectively. The X8 (b) channel is set to 0. + */ + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0x00309282); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0x0070d2c2); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x00b01000); + todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x00ff5040); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* + * Q8 will get converted to unorm range, v8u8, despite being in the + * same range, will not be directly copied. 0x80/0x81 are clamped to + * 0x82, and 0xd0/0xc0 end up as 0xd1/0xc1. + */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0x00b01000); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0x00ff5040); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x002f8282); + todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x007ed1c1); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + check_release((IUnknown*)surf, 1); + check_release((IUnknown*)tex, 0); + } + + hr = IDirect3DDevice9_CreateTexture(device, 2, 2, 1, 0, D3DFMT_V8U8, D3DPOOL_MANAGED, &tex, NULL); + if (FAILED(hr)) + skip("Failed to create D3DFMT_V8U8 texture, hr %#lx.\n", hr); + else + { + hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &surf); + ok(hr == D3D_OK, "Failed to get the surface, hr %#lx.\n", hr); + + /* R and G channels converted to SNORM range. */ + SetRect(&rect, 0, 0, 2, 2); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8_2, D3DFMT_A8B8G8R8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_2bpp(&lockrect, 0, 0, 0x9282); + todo_wine check_pixel_2bpp(&lockrect, 1, 0, 0xd2c2); + todo_wine check_pixel_2bpp(&lockrect, 0, 1, 0x1000); + todo_wine check_pixel_2bpp(&lockrect, 1, 1, 0x5040); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + /* + * Pull the V8U8 channels. Even though they're the same range, they're + * not directly copied over. 0x80/0x81 are clamped to 0x82, and + * 0xd0/0xc0 end up as 0xd1/0xc1. + */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, + D3DX_FILTER_NONE, 0); + todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + todo_wine check_pixel_2bpp(&lockrect, 0, 0, 0x1000); + todo_wine check_pixel_2bpp(&lockrect, 1, 0, 0x5040); + todo_wine check_pixel_2bpp(&lockrect, 0, 1, 0x8282); + todo_wine check_pixel_2bpp(&lockrect, 1, 1, 0xd1c1); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + + check_release((IUnknown*)surf, 1); + check_release((IUnknown*)tex, 0); + } + + test_format_conversion(device); + /* cleanup */ if(testdummy_ok) DeleteFileA("testdummy.bmp"); if(testbitmap_ok) DeleteFileA("testbitmap.bmp");
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/surface.c | 153 ++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index ca10054fe2e..9825fb71c45 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1080,6 +1080,158 @@ static void test_format_conversion(IDirect3DDevice9 *device) } }
+static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) +{ + static const uint32_t dxt_pma_decompressed_expected[] = + { + 0x00000000, 0x22ffffff, 0x44ffffff, 0x66ffffff, 0x88f7f3f7, 0xaac5c2c5, 0xcca5a2a5, 0xff848284, + 0x00000000, 0x22ffffff, 0x44ffffff, 0x66ffffff, 0x88f7f3f7, 0xaac5c2c5, 0xcca5a2a5, 0xff848284, + }; + static const uint32_t dxt_decompressed_expected[] = + { + 0x00848284, 0x22848284, 0x44848284, 0x66848284, 0x88848284, 0xaa848284, 0xcc848284, 0xff848284, + 0x00848284, 0x22848284, 0x44848284, 0x66848284, 0x88848284, 0xaa848284, 0xcc848284, 0xff848284, + }; + static const uint8_t dxt3_block[] = + { + 0x20,0x64,0xa8,0xfc,0x20,0x64,0xa8,0xfc,0x10,0x84,0x10,0x84,0x00,0x00,0x00,0x00, + }; + static const uint8_t dxt5_block[] = + { + 0x22,0xcc,0x86,0xc6,0xe6,0x86,0xc6,0xe6,0x10,0x84,0x10,0x84,0x00,0x00,0x00,0x00, + }; + static const uint32_t test_compress_pixels[] = + { + 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, + 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, + }; + static const struct test + { + D3DFORMAT pma_fmt; + D3DFORMAT nonpma_fmt; + const uint8_t *dxt_block; + const char *name; + } tests[] = + { + { D3DFMT_DXT2, D3DFMT_DXT3, dxt3_block, "DXT2 / DXT3" }, + { D3DFMT_DXT4, D3DFMT_DXT5, dxt5_block, "DXT4 / DXT5" }, + }; + static const RECT src_rect = { 0, 0, 4, 4 }; + IDirect3DSurface9 *decomp_surf; + D3DLOCKED_RECT lock_rect; + uint32_t i, x, y; + HRESULT hr; + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &decomp_surf, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + struct surface_readback surface_rb; + IDirect3DSurface9 *pma_surf, *surf; + IDirect3DTexture9 *pma_tex, *tex; + + winetest_push_context("Test %s", tests[i].name); + hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, tests[i].pma_fmt, D3DPOOL_SYSTEMMEM, &pma_tex, NULL); + if (FAILED(hr)) + { + skip("Failed to create texture for format %#x, hr %#lx.\n", tests[i].pma_fmt, hr); + winetest_pop_context(); + continue; + } + + hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, tests[i].nonpma_fmt, D3DPOOL_SYSTEMMEM, &tex, NULL); + if (FAILED(hr)) + { + skip("Failed to create texture for format %#x, hr %#lx.\n", tests[i].nonpma_fmt, hr); + IDirect3DTexture9_Release(pma_tex); + winetest_pop_context(); + continue; + } + + hr = IDirect3DTexture9_GetSurfaceLevel(pma_tex, 0, &pma_surf); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &surf); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* Compress and load the same image onto each DXT surface. */ + hr = D3DXLoadSurfaceFromMemory(pma_surf, NULL, NULL, test_compress_pixels, D3DFMT_A8B8G8R8, 16, NULL, &src_rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, test_compress_pixels, D3DFMT_A8B8G8R8, 16, NULL, &src_rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* + * For DXT2/DXT4, the source image has all of its color channels + * premultiplied by the alpha value prior to compression. If the + * alpha channel's value is 0, then the color channel values are + * lost. + */ + get_surface_decompressed_readback(device, pma_surf, &surface_rb); + for (y = 0; y < 4; ++y) + { + for (x = 0; x < 4; ++x) + { + const uint32_t expected_pixel = !(x & 0x01) ? 0xffffffff : 0x00000000; + + check_readback_pixel_4bpp(&surface_rb, x, y, expected_pixel, !expected_pixel); + } + } + release_surface_readback(&surface_rb); + + /* For DXT3/DXT5, no premultiplication by the alpha channel value is done. */ + get_surface_decompressed_readback(device, surf, &surface_rb); + for (y = 0; y < 4; ++y) + { + for (x = 0; x < 4; ++x) + check_readback_pixel_4bpp(&surface_rb, x, y, test_compress_pixels[(y * 4) + x], FALSE); + } + release_surface_readback(&surface_rb); + + /* + * Load our test DXT block with the premultiplied alpha DXT format. + * The block is decompressed, and then the premultiplied alpha + * operation is undone prior to being copied to the destination + * surface. + */ + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, tests[i].dxt_block, tests[i].pma_fmt, 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); + for (y = 0; y < 4; ++y) + { + for (x = 0; x < 4; ++x) + { + const uint32_t expected_pixel = dxt_pma_decompressed_expected[(y * 4) + x]; + const BOOL todo = ((expected_pixel >> 24) & 0xff) != 0xff; + + todo_wine_if(todo) check_pixel_4bpp(&lock_rect, x, y, expected_pixel); + } + } + IDirect3DSurface9_UnlockRect(decomp_surf); + + /* + * Load our test DXT block as a non-premultiplied alpha DXT format. + * The block is decompressed, and the data is copied over directly. + */ + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, tests[i].dxt_block, tests[i].nonpma_fmt, 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); + for (y = 0; y < 4; ++y) + { + for (x = 0; x < 4; ++x) + check_pixel_4bpp(&lock_rect, x, y, dxt_decompressed_expected[(y * 4) + x]); + } + IDirect3DSurface9_UnlockRect(decomp_surf); + + IDirect3DSurface9_Release(pma_surf); + IDirect3DTexture9_Release(pma_tex); + IDirect3DSurface9_Release(surf); + IDirect3DTexture9_Release(tex); + winetest_pop_context(); + } + IDirect3DSurface9_Release(decomp_surf); +} + static void test_D3DXLoadSurface(IDirect3DDevice9 *device) { HRESULT hr; @@ -2287,6 +2439,7 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) }
test_format_conversion(device); + test_dxt_premultiplied_alpha(device);
/* cleanup */ if(testdummy_ok) DeleteFileA("testdummy.bmp");
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 13 ++++++++++++- dlls/d3dx9_36/tests/surface.c | 12 ++++++------ 2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index f5d0184422b..25e7e81e6d6 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1474,6 +1474,13 @@ static void get_relevant_argb_components(const struct argb_conversion_info *info } }
+static float d3dx_clamp(float value, float min_value, float max_value) +{ + if (isnan(value)) + return max_value; + return value < min_value ? min_value : value > max_value ? max_value : value; +} + /************************************************************ * make_argb_color * @@ -1550,7 +1557,11 @@ static void format_from_vec4(const struct pixel_format_desc *format, const struc else if (format->type == FORMAT_ARGBF) v = *(DWORD *)&src_component; else - v = (DWORD)(src_component * ((1 << format->bits[c]) - 1) + 0.5f); + { + float val = d3dx_clamp(src_component, 0.0f, 1.0f); + + v = val * ((1u << format->bits[c]) - 1) + 0.5f; + }
for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8) { diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 9825fb71c45..74c67b71581 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1694,10 +1694,10 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0xff001aff); - todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0xffffffff); - todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x000000ff); - todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x00000000); + check_pixel_4bpp(&lockrect, 0, 0, 0xff001aff); + check_pixel_4bpp(&lockrect, 1, 0, 0xffffffff); + check_pixel_4bpp(&lockrect, 0, 1, 0x000000ff); + check_pixel_4bpp(&lockrect, 1, 1, 0x00000000); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
@@ -1947,9 +1947,9 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); todo_wine check_pixel_2bpp(&lockrect, 0, 0, 0xff25); - todo_wine check_pixel_2bpp(&lockrect, 1, 0, 0xffff); + check_pixel_2bpp(&lockrect, 1, 0, 0xffff); todo_wine check_pixel_2bpp(&lockrect, 0, 1, 0x0012); - todo_wine check_pixel_2bpp(&lockrect, 1, 1, 0x0000); + check_pixel_2bpp(&lockrect, 1, 1, 0x0000); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 13 +++++++- dlls/d3dx9_36/math.c | 10 +++--- dlls/d3dx9_36/surface.c | 62 +++++++++++++++++++++-------------- 3 files changed, 54 insertions(+), 31 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index bf16b3a7590..5ee956f041d 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -55,6 +55,17 @@ struct vec4 float x, y, z, w; };
+enum range { + RANGE_FULL = 0, + RANGE_UNORM = 1, +}; + +struct d3dx_color +{ + struct vec4 value; + enum range range; +}; + struct volume { UINT width; @@ -178,7 +189,7 @@ HRESULT write_buffer_to_file(const WCHAR *filename, ID3DXBuffer *buffer); const struct pixel_format_desc *get_format_info(D3DFORMAT format); const struct pixel_format_desc *get_format_info_idx(int idx);
-void format_to_vec4(const struct pixel_format_desc *format, const BYTE *src, struct vec4 *dst); +void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, struct d3dx_color *dst);
void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, diff --git a/dlls/d3dx9_36/math.c b/dlls/d3dx9_36/math.c index f018f499c43..4b8f200b199 100644 --- a/dlls/d3dx9_36/math.c +++ b/dlls/d3dx9_36/math.c @@ -3052,7 +3052,7 @@ HRESULT WINAPI D3DXSHProjectCubeMap(unsigned int order, IDirect3DCubeTexture9 *t float diff_solid, x_3d, y_3d; const float u = x * S + B; const float v = y * S + B; - struct vec4 colour; + struct d3dx_color colour; D3DXVECTOR3 dir;
x_3d = (x * 2.0f + 1.0f) / desc.Width - 1.0f; @@ -3093,15 +3093,15 @@ HRESULT WINAPI D3DXSHProjectCubeMap(unsigned int order, IDirect3DCubeTexture9 *t D3DXVec3Normalize(&dir, &dir); D3DXSHEvalDirection(temp, order, &dir);
- format_to_vec4(format, &row[x * format->block_byte_count], &colour); + format_to_d3dx_color(format, &row[x * format->block_byte_count], &colour);
for (i = 0; i < order_square; ++i) { - red[i] += temp[i] * colour.x * diff_solid; + red[i] += temp[i] * colour.value.x * diff_solid; if (green) - green[i] += temp[i] * colour.y * diff_solid; + green[i] += temp[i] * colour.value.y * diff_solid; if (blue) - blue[i] += temp[i] * colour.z * diff_solid; + blue[i] += temp[i] * colour.value.z * diff_solid; } } } diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 25e7e81e6d6..1b34bdb36f8 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -26,6 +26,7 @@ #include "wincodec.h"
#include "txc_dxtn.h" +#include <assert.h>
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
@@ -1505,15 +1506,30 @@ static DWORD make_argb_color(const struct argb_conversion_info *info, const DWOR }
/* It doesn't work for components bigger than 32 bits (or somewhat smaller but unaligned). */ -void format_to_vec4(const struct pixel_format_desc *format, const BYTE *src, struct vec4 *dst) +void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, struct d3dx_color *dst) { DWORD mask, tmp; unsigned int c;
+ switch (format->type) + { + case FORMAT_ARGBF16: + case FORMAT_ARGBF: + dst->range = RANGE_FULL; + break; + case FORMAT_ARGB: + case FORMAT_INDEX: + dst->range = RANGE_UNORM; + break; + default: /* Shouldn't pass FORMAT_DXT/FORMAT_UNKNOWN into here. */ + assert(0); + break; + } + for (c = 0; c < 4; ++c) { static const unsigned int component_offsets[4] = {3, 0, 1, 2}; - float *dst_component = (float *)dst + component_offsets[c]; + float *dst_component = &dst->value.x + component_offsets[c];
if (format->bits[c]) { @@ -1535,7 +1551,7 @@ void format_to_vec4(const struct pixel_format_desc *format, const BYTE *src, str }
/* It doesn't work for components bigger than 32 bits. */ -static void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, BYTE *dst) +static void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst) { DWORD v, mask32; unsigned int c, i; @@ -1681,29 +1697,27 @@ void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pit } else { - struct vec4 color, tmp; + struct d3dx_color color, tmp;
- format_to_vec4(src_format, src_ptr, &color); + format_to_d3dx_color(src_format, src_ptr, &color); + tmp = color; if (src_format->to_rgba) - src_format->to_rgba(&color, &tmp, palette); - else - tmp = color; + src_format->to_rgba(&color.value, &tmp.value, palette);
if (ck_format) { DWORD ck_pixel;
- format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel); + format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); if (ck_pixel == color_key) - tmp.w = 0.0f; + tmp.value.w = 0.0f; }
+ color = tmp; if (dst_format->from_rgba) - dst_format->from_rgba(&tmp, &color); - else - color = tmp; + dst_format->from_rgba(&tmp.value, &color.value);
- format_from_vec4(dst_format, &color, dst_ptr); + format_from_d3dx_color(dst_format, &color, dst_ptr); }
src_ptr += src_format->bytes_per_pixel; @@ -1789,29 +1803,27 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic } else { - struct vec4 color, tmp; + struct d3dx_color color, tmp;
- format_to_vec4(src_format, src_ptr, &color); + format_to_d3dx_color(src_format, src_ptr, &color); + tmp = color; if (src_format->to_rgba) - src_format->to_rgba(&color, &tmp, palette); - else - tmp = color; + src_format->to_rgba(&color.value, &tmp.value, palette);
if (ck_format) { DWORD ck_pixel;
- format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel); + format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); if (ck_pixel == color_key) - tmp.w = 0.0f; + tmp.value.w = 0.0f; }
+ color = tmp; if (dst_format->from_rgba) - dst_format->from_rgba(&tmp, &color); - else - color = tmp; + dst_format->from_rgba(&tmp.value, &color.value);
- format_from_vec4(dst_format, &color, dst_ptr); + format_from_d3dx_color(dst_format, &color, dst_ptr); }
dst_ptr += dst_format->bytes_per_pixel;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 6 ++- dlls/d3dx9_36/surface.c | 40 ++++++++++++++- dlls/d3dx9_36/tests/surface.c | 92 +++++++++++++++++------------------ dlls/d3dx9_36/util.c | 1 + 4 files changed, 87 insertions(+), 52 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 5ee956f041d..2338909f7cc 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -58,6 +58,7 @@ struct vec4 enum range { RANGE_FULL = 0, RANGE_UNORM = 1, + RANGE_SNORM = 2, };
struct d3dx_color @@ -85,6 +86,7 @@ enum format_type { FORMAT_ARGB, /* unsigned */ FORMAT_ARGBF16,/* float 16 */ FORMAT_ARGBF, /* float */ + FORMAT_ARGB_SNORM, FORMAT_DXT, FORMAT_INDEX, FORMAT_UNKNOWN @@ -168,7 +170,7 @@ extern const struct ID3DXIncludeVtbl d3dx_include_from_file_vtbl; static inline BOOL is_conversion_from_supported(const struct pixel_format_desc *format) { if (format->type == FORMAT_ARGB || format->type == FORMAT_ARGBF16 - || format->type == FORMAT_ARGBF || format->type == FORMAT_DXT) + || format->type == FORMAT_ARGBF || format->type == FORMAT_DXT || format->type == FORMAT_ARGB_SNORM) return TRUE; return !!format->to_rgba; } @@ -176,7 +178,7 @@ static inline BOOL is_conversion_from_supported(const struct pixel_format_desc * static inline BOOL is_conversion_to_supported(const struct pixel_format_desc *format) { if (format->type == FORMAT_ARGB || format->type == FORMAT_ARGBF16 - || format->type == FORMAT_ARGBF || format->type == FORMAT_DXT) + || format->type == FORMAT_ARGBF || format->type == FORMAT_DXT || format->type == FORMAT_ARGB_SNORM) return TRUE; return !!format->from_rgba; } diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 1b34bdb36f8..bf828ddca7b 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1521,6 +1521,9 @@ void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *sr case FORMAT_INDEX: dst->range = RANGE_UNORM; break; + case FORMAT_ARGB_SNORM: + dst->range = RANGE_SNORM; + break; default: /* Shouldn't pass FORMAT_DXT/FORMAT_UNKNOWN into here. */ assert(0); break; @@ -1542,6 +1545,26 @@ void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *sr *dst_component = float_16_to_32(tmp); else if (format->type == FORMAT_ARGBF) *dst_component = *(float *)&tmp; + else if (format->type == FORMAT_ARGB_SNORM) + { + const uint32_t sign_bit = (1u << (format->bits[c] - 1)); + uint32_t tmp_extended, tmp_masked = (tmp >> format->shift[c] % 8) & mask; + + tmp_extended = tmp_masked; + if (tmp_masked & sign_bit) + { + tmp_extended |= ~(sign_bit - 1); + + /* + * In order to clamp to an even range, we need to ignore + * the maximum negative value. + */ + if (tmp_masked == sign_bit) + tmp_extended |= 1; + } + + *dst_component = (float)(((int32_t)tmp_extended)) / (sign_bit - 1); + } else *dst_component = (float)((tmp >> format->shift[c] % 8) & mask) / mask; } @@ -1572,11 +1595,24 @@ static void format_from_d3dx_color(const struct pixel_format_desc *format, const v = float_32_to_16(src_component); else if (format->type == FORMAT_ARGBF) v = *(DWORD *)&src_component; + else if (format->type == FORMAT_ARGB_SNORM) + { + const uint32_t max_value = (1u << (format->bits[c] - 1)) - 1; + float val = src_component; + + if (src->range == RANGE_UNORM) + val = (val * 2.0f) - 1.0f; + + v = d3dx_clamp(val, -1.0f, 1.0f) * max_value + 0.5f; + } else { - float val = d3dx_clamp(src_component, 0.0f, 1.0f); + float val = src_component; + + if (src->range == RANGE_SNORM) + val = (val + 1.0f) / 2.0f;
- v = val * ((1u << format->bits[c]) - 1) + 0.5f; + v = d3dx_clamp(val, 0.0f, 1.0f) * ((1u << format->bits[c]) - 1) + 0.5f; }
for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8) diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 74c67b71581..804dfd7c874 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1676,18 +1676,16 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) /* From a signed normalized format to an unsigned normalized format. */ hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - { - hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); - ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - check_pixel_4bpp(&lockrect, 0, 0, 0xb08090a0); - check_pixel_4bpp(&lockrect, 1, 0, 0xffc0d0e0); - check_pixel_4bpp(&lockrect, 0, 1, 0x2f00001f); - check_pixel_4bpp(&lockrect, 1, 1, 0x7e3f4f5f); - hr = IDirect3DSurface9_UnlockRect(surf); - ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); - } + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_4bpp(&lockrect, 0, 0, 0xb08090a0); + check_pixel_4bpp(&lockrect, 1, 0, 0xffc0d0e0); + check_pixel_4bpp(&lockrect, 0, 1, 0x2f00001f); + check_pixel_4bpp(&lockrect, 1, 1, 0x7e3f4f5f); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a32b32g32r32f, D3DFMT_A32B32G32R32F, 32, NULL, &rect, D3DX_FILTER_NONE, 0); @@ -1928,18 +1926,16 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device)
hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - { - hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); - ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - check_pixel_2bpp(&lockrect, 0, 0, 0xb08d); - check_pixel_2bpp(&lockrect, 1, 0, 0xffce); - check_pixel_2bpp(&lockrect, 0, 1, 0x2f02); - check_pixel_2bpp(&lockrect, 1, 1, 0x7e4d); - hr = IDirect3DSurface9_UnlockRect(surf); - ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); - } + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); + check_pixel_2bpp(&lockrect, 0, 0, 0xb08d); + check_pixel_2bpp(&lockrect, 1, 0, 0xffce); + check_pixel_2bpp(&lockrect, 0, 1, 0x2f02); + check_pixel_2bpp(&lockrect, 1, 1, 0x7e4d); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a32b32g32r32f, D3DFMT_A32B32G32R32F, 32, NULL, &rect, D3DX_FILTER_NONE, 0); @@ -2204,14 +2200,14 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) /* Signed normalized value to full range float. */ hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - check_pixel_float4(&lockrect, 0, 0, 0.00000000e+000f, 1.25984251e-001f, 2.51968503e-001f, 3.77952754e-001f, 0, TRUE); - check_pixel_float4(&lockrect, 1, 0, 5.03937006e-001f, 6.29921257e-001f, 7.55905509e-001f, 1.00000000e+000f, 0, TRUE); - check_pixel_float4(&lockrect, 0, 1, -1.00000000e+000f, -1.00000000e+000f, -7.55905509e-001f, -6.29921257e-001f, 0, TRUE); - check_pixel_float4(&lockrect, 1, 1, -5.03937006e-001f, -3.77952754e-001f, -2.51968503e-001f, -7.87401572e-003f, 0, TRUE); + check_pixel_float4(&lockrect, 0, 0, 0.00000000e+000f, 1.25984251e-001f, 2.51968503e-001f, 3.77952754e-001f, 0, FALSE); + check_pixel_float4(&lockrect, 1, 0, 5.03937006e-001f, 6.29921257e-001f, 7.55905509e-001f, 1.00000000e+000f, 0, FALSE); + check_pixel_float4(&lockrect, 0, 1, -1.00000000e+000f, -1.00000000e+000f, -7.55905509e-001f, -6.29921257e-001f, 0, FALSE); + check_pixel_float4(&lockrect, 1, 1, -5.03937006e-001f, -3.77952754e-001f, -2.51968503e-001f, -7.87401572e-003f, 0, FALSE); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
@@ -2289,53 +2285,53 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) SetRect(&rect, 0, 0, 2, 2); hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - todo_wine check_pixel_4bpp(&lockrect, 0, 0, pixdata_q8w8v8u8[0]); - todo_wine check_pixel_4bpp(&lockrect, 1, 0, pixdata_q8w8v8u8[1]); - todo_wine check_pixel_4bpp(&lockrect, 0, 1, pixdata_q8w8v8u8[2]); - todo_wine check_pixel_4bpp(&lockrect, 1, 1, pixdata_q8w8v8u8[3]); + check_pixel_4bpp(&lockrect, 0, 0, pixdata_q8w8v8u8[0]); + check_pixel_4bpp(&lockrect, 1, 0, pixdata_q8w8v8u8[1]); + check_pixel_4bpp(&lockrect, 0, 1, pixdata_q8w8v8u8[2]); + check_pixel_4bpp(&lockrect, 1, 1, pixdata_q8w8v8u8[3]); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
/* Unorm to snorm. */ hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8, D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0x43bbce70); - todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0xa5dc6812); - todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x8b31177d); - todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x0d43ad76); + check_pixel_4bpp(&lockrect, 0, 0, 0x43bbce70); + check_pixel_4bpp(&lockrect, 1, 0, 0xa5dc6812); + check_pixel_4bpp(&lockrect, 0, 1, 0x8b31177d); + check_pixel_4bpp(&lockrect, 1, 1, 0x0d43ad76); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
/* Full range float to snorm. */ hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a32b32g32r32f, D3DFMT_A32B32G32R32F, 32, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0x7f7f0d00); - todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0x7f7f7f7f); - todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x827fe8f4); - todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x82828282); + check_pixel_4bpp(&lockrect, 0, 0, 0x7f7f0d00); + check_pixel_4bpp(&lockrect, 1, 0, 0x7f7f7f7f); + check_pixel_4bpp(&lockrect, 0, 1, 0x827fe8f4); + check_pixel_4bpp(&lockrect, 1, 1, 0x82828282); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
/* Unorm alpha and unorm luma to snorm. */ hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8l8, D3DFMT_A8L8, 4, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - todo_wine check_pixel_4bpp(&lockrect, 0, 0, 0x7f828282); - todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0x827f7f7f); - todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x7fb2b2b2); + check_pixel_4bpp(&lockrect, 0, 0, 0x7f828282); + check_pixel_4bpp(&lockrect, 1, 0, 0x827f7f7f); + check_pixel_4bpp(&lockrect, 0, 1, 0x7fb2b2b2); check_pixel_4bpp(&lockrect, 1, 1, 0x00000000); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); diff --git a/dlls/d3dx9_36/util.c b/dlls/d3dx9_36/util.c index 419bd92884a..4519fd02f17 100644 --- a/dlls/d3dx9_36/util.c +++ b/dlls/d3dx9_36/util.c @@ -88,6 +88,7 @@ static const struct pixel_format_desc formats[] = {D3DFMT_G32R32F, { 0, 32, 32, 0}, { 0, 0, 32, 0}, 8, 1, 1, 8, FORMAT_ARGBF, NULL, NULL }, {D3DFMT_A32B32G32R32F, {32, 32, 32, 32}, {96, 0, 32, 64}, 16, 1, 1, 16, FORMAT_ARGBF, NULL, NULL }, {D3DFMT_P8, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 1, 1, 1, FORMAT_INDEX, NULL, index_to_rgba}, + {D3DFMT_Q8W8V8U8, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, FORMAT_ARGB_SNORM, NULL, NULL }, /* marks last element */ {D3DFMT_UNKNOWN, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 0, 1, 1, 0, FORMAT_UNKNOWN, NULL, NULL }, };
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/surface.c | 35 ++++++++++++++++++++--------------- dlls/d3dx9_36/util.c | 1 + 2 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 804dfd7c874..3a477616abe 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -737,7 +737,7 @@ static void test_D3DXGetImageInfo(void) check_dds_pixel_format(DDS_PF_LUMINANCE, 0, 16, 0xffff, 0, 0, 0, D3DFMT_L16); check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 16, 0x00ff, 0, 0, 0xff00, D3DFMT_A8L8); check_dds_pixel_format(DDS_PF_LUMINANCE | DDS_PF_ALPHA, 0, 8, 0x0f, 0, 0, 0xf0, D3DFMT_A4L4); - todo_wine check_dds_pixel_format(DDS_PF_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0, D3DFMT_V8U8); + check_dds_pixel_format(DDS_PF_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0, D3DFMT_V8U8); todo_wine check_dds_pixel_format(DDS_PF_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0, D3DFMT_V16U16); todo_wine check_dds_pixel_format(DDS_PF_BUMPLUMINANCE, 0, 32, 0x0000ff, 0x00ff00, 0xff0000, 0, D3DFMT_X8L8V8U8);
@@ -1008,7 +1008,7 @@ static void test_format_conversion(IDirect3DDevice9 *device) { D3DFMT_A16B16G16R16, NULL, { 0, 0, 2, 2 }, a16b16g16r16_2_2, D3DFMT_A32B32G32R32F, a16b16g16r16_2_2_expected }, { D3DFMT_V16U16, NULL, { 0, 0, 2, 2 }, v16u16_2_2, D3DFMT_G16R16, v16u16_2_2_expected, .todo = TRUE }, { D3DFMT_V16U16, NULL, { 0, 0, 2, 2 }, v16u16_2_2, D3DFMT_A32B32G32R32F, v16u16_2_2_expected2, .todo = TRUE }, - { D3DFMT_V8U8, NULL, { 0, 0, 2, 2 }, v8u8_2_2, D3DFMT_A32B32G32R32F, v8u8_2_2_expected, .todo = TRUE }, + { D3DFMT_V8U8, NULL, { 0, 0, 2, 2 }, v8u8_2_2, D3DFMT_A32B32G32R32F, v8u8_2_2_expected }, { D3DFMT_Q16W16V16U16, NULL, { 0, 0, 2, 2 }, q16w16v16u16_2_2, D3DFMT_A32B32G32R32F, q16w16v16u16_2_2_expected, .todo = TRUE }, { D3DFMT_A8P8, test_palette, { 0, 0, 2, 2 }, a8p8_2_2, D3DFMT_A8R8G8B8, a8p8_2_2_expected, .todo = TRUE }, }; @@ -2228,14 +2228,14 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) /* V8U8 snorm. */ hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_v8u8, D3DFMT_V8U8, 4, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - check_pixel_float4(&lockrect, 0, 0, 0.00000000e+000f, 3.77952754e-001f, 1.0f, 1.0f, 0, TRUE); - check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 1.0f, 0, TRUE); - check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 1.0f, 0, TRUE); - check_pixel_float4(&lockrect, 1, 1, -5.03937006e-001f, -7.87401572e-003f, 1.0f, 1.0f, 0, TRUE); + check_pixel_float4(&lockrect, 0, 0, 0.00000000e+000f, 3.77952754e-001f, 1.0f, 1.0f, 0, FALSE); + check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 1.0f, 0, FALSE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 1.0f, 0, FALSE); + check_pixel_float4(&lockrect, 1, 1, -5.03937006e-001f, -7.87401572e-003f, 1.0f, 1.0f, 0, FALSE); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
@@ -2401,14 +2401,14 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) SetRect(&rect, 0, 0, 2, 2); hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_a8b8g8r8_2, D3DFMT_A8B8G8R8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - todo_wine check_pixel_2bpp(&lockrect, 0, 0, 0x9282); - todo_wine check_pixel_2bpp(&lockrect, 1, 0, 0xd2c2); - todo_wine check_pixel_2bpp(&lockrect, 0, 1, 0x1000); - todo_wine check_pixel_2bpp(&lockrect, 1, 1, 0x5040); + check_pixel_2bpp(&lockrect, 0, 0, 0x9282); + check_pixel_2bpp(&lockrect, 1, 0, 0xd2c2); + check_pixel_2bpp(&lockrect, 0, 1, 0x1000); + check_pixel_2bpp(&lockrect, 1, 1, 0x5040); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
@@ -2419,12 +2419,17 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) */ hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, pixdata_q8w8v8u8, D3DFMT_Q8W8V8U8, 8, NULL, &rect, D3DX_FILTER_NONE, 0); - todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
hr = IDirect3DSurface9_LockRect(surf, &lockrect, NULL, D3DLOCK_READONLY); ok(hr == D3D_OK, "Failed to lock surface, hr %#lx.\n", hr); - todo_wine check_pixel_2bpp(&lockrect, 0, 0, 0x1000); - todo_wine check_pixel_2bpp(&lockrect, 1, 0, 0x5040); + check_pixel_2bpp(&lockrect, 0, 0, 0x1000); + check_pixel_2bpp(&lockrect, 1, 0, 0x5040); + /* + * Wine does direct copies from the source pixels here, but if we + * force conversion to float on the source and then convert back to + * snorm we'd match these values. + */ todo_wine check_pixel_2bpp(&lockrect, 0, 1, 0x8282); todo_wine check_pixel_2bpp(&lockrect, 1, 1, 0xd1c1); hr = IDirect3DSurface9_UnlockRect(surf); diff --git a/dlls/d3dx9_36/util.c b/dlls/d3dx9_36/util.c index 4519fd02f17..a73467f5e68 100644 --- a/dlls/d3dx9_36/util.c +++ b/dlls/d3dx9_36/util.c @@ -89,6 +89,7 @@ static const struct pixel_format_desc formats[] = {D3DFMT_A32B32G32R32F, {32, 32, 32, 32}, {96, 0, 32, 64}, 16, 1, 1, 16, FORMAT_ARGBF, NULL, NULL }, {D3DFMT_P8, { 8, 8, 8, 8}, { 0, 0, 0, 0}, 1, 1, 1, 1, FORMAT_INDEX, NULL, index_to_rgba}, {D3DFMT_Q8W8V8U8, { 8, 8, 8, 8}, {24, 0, 8, 16}, 4, 1, 1, 4, FORMAT_ARGB_SNORM, NULL, NULL }, + {D3DFMT_V8U8, { 0, 8, 8, 0}, { 0, 0, 8, 0}, 2, 1, 1, 2, FORMAT_ARGB_SNORM, NULL, NULL }, /* marks last element */ {D3DFMT_UNKNOWN, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 0, 1, 1, 0, FORMAT_UNKNOWN, NULL, NULL }, };
From: Connor McAdams cmcadams@codeweavers.com
These functions do the exact same thing, so there's no need to have two separate functions.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 7 ++++ dlls/d3dx9_36/surface.c | 2 +- dlls/d3dx9_36/texture.c | 75 +++++++---------------------------- 3 files changed, 23 insertions(+), 61 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 2338909f7cc..e46cd7389b2 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -67,6 +67,12 @@ struct d3dx_color enum range range; };
+static inline void set_d3dx_color(struct d3dx_color *color, const struct vec4 *value, enum range range) +{ + color->value = *value; + color->range = range; +} + struct volume { UINT width; @@ -192,6 +198,7 @@ const struct pixel_format_desc *get_format_info(D3DFORMAT format); const struct pixel_format_desc *get_format_info_idx(int idx);
void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *src, struct d3dx_color *dst); +void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst);
void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index bf828ddca7b..674a400d37a 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1574,7 +1574,7 @@ void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *sr }
/* It doesn't work for components bigger than 32 bits. */ -static void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst) +void format_from_d3dx_color(const struct pixel_format_desc *format, const struct d3dx_color *src, BYTE *dst) { DWORD v, mask32; unsigned int c, i; diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index 2820857230d..38a32052f99 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -1261,62 +1261,6 @@ err: return hr; }
-static inline void fill_texture(const struct pixel_format_desc *format, BYTE *pos, const D3DXVECTOR4 *value) -{ - DWORD c; - - for (c = 0; c < format->bytes_per_pixel; c++) - pos[c] = 0; - - for (c = 0; c < 4; c++) - { - float comp_value; - DWORD i, v = 0, mask32 = format->bits[c] == 32 ? ~0U : ((1 << format->bits[c]) - 1); - - switch (c) - { - case 0: /* Alpha */ - comp_value = value->w; - break; - case 1: /* Red */ - comp_value = value->x; - break; - case 2: /* Green */ - comp_value = value->y; - break; - case 3: /* Blue */ - comp_value = value->z; - break; - } - - if (format->type == FORMAT_ARGBF16) - v = float_32_to_16(comp_value); - else if (format->type == FORMAT_ARGBF) - v = *(DWORD *)&comp_value; - else if (format->type == FORMAT_ARGB) - v = max(comp_value * ((1 << format->bits[c]) - 1) + 0.5f, 0); - else - FIXME("Unhandled format type %#x\n", format->type); - - for (i = 0; i < format->bits[c] + format->shift[c]; i += 8) - { - BYTE byte, mask; - - if (format->shift[c] > i) - { - mask = mask32 << (format->shift[c] - i); - byte = (v << (format->shift[c] - i)) & mask; - } - else - { - mask = mask32 >> (i - format->shift[c]); - byte = (v >> (i - format->shift[c])) & mask; - } - pos[i / 8] |= byte; - } - } -} - HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D function, void *funcdata) { IDirect3DSurface9 *surface, *temp_surface; @@ -1370,11 +1314,15 @@ HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D f
for (x = 0; x < desc.Width; x++) { + BYTE *dst = data + y * lock_rect.Pitch + x * format->bytes_per_pixel; + struct d3dx_color color; + coord.x = (x + 0.5f) / desc.Width;
function(&value, &coord, &size, funcdata);
- fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value); + set_d3dx_color(&color, (const struct vec4 *)&value, RANGE_FULL); + format_from_d3dx_color(format, &color, dst); } } if (FAILED(hr = unlock_surface(surface, NULL, temp_surface, TRUE))) @@ -1757,13 +1705,17 @@ HRESULT WINAPI D3DXFillCubeTexture(struct IDirect3DCubeTexture9 *texture, LPD3DX { for (x = 0; x < desc.Width; x++) { + BYTE *dst = data + y * lock_rect.Pitch + x * format->bytes_per_pixel; + struct d3dx_color color; + coord.x = get_cube_coord(coordmap[f][0], x, y, desc.Width) / desc.Width * 2.0f - 1.0f; coord.y = get_cube_coord(coordmap[f][1], x, y, desc.Width) / desc.Width * 2.0f - 1.0f; coord.z = get_cube_coord(coordmap[f][2], x, y, desc.Width) / desc.Width * 2.0f - 1.0f;
function(&value, &coord, &size, funcdata);
- fill_texture(format, data + y * lock_rect.Pitch + x * format->bytes_per_pixel, &value); + set_d3dx_color(&color, (const struct vec4 *)&value, RANGE_FULL); + format_from_d3dx_color(format, &color, dst); } } IDirect3DCubeTexture9_UnlockRect(texture, f, m); @@ -1824,12 +1776,15 @@ HRESULT WINAPI D3DXFillVolumeTexture(struct IDirect3DVolumeTexture9 *texture, LP
for (x = 0; x < desc.Width; x++) { + BYTE *dst = data + z * lock_box.SlicePitch + y * lock_box.RowPitch + x * format->bytes_per_pixel; + struct d3dx_color color; + coord.x = (x + 0.5f) / desc.Width;
function(&value, &coord, &size, funcdata);
- fill_texture(format, data + z * lock_box.SlicePitch + y * lock_box.RowPitch - + x * format->bytes_per_pixel, &value); + set_d3dx_color(&color, (const struct vec4 *)&value, RANGE_FULL); + format_from_d3dx_color(format, &color, dst); } } }
On Mon Sep 23 19:37:31 2024 +0000, Connor McAdams wrote:
Ah, I saw "relative error" and the function in `d3dx9_36/tests/texture.c`:
static inline float relative_error(float expected, float got) { return expected == 0.0f ? fabs(expected - got) : fabs(1.0f - got / expected); }
came to mind. :) This should be fixed in the current revision, using the functions in `d3dx9_36/tests/math.c`. I've changed the format of the float constants in the calls to `check_pixel_float4()` to match the `%.8e` format where necessary, and kept the old format for things like `1.0f` and `0.0f`. Hopefully it's fine now.
Eh, I guess that function was named a little to well for its own good :sweat_smile:
This looks great now :slight_smile:
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
return 0;
- }
+}
+static void test_format_conversion(IDirect3DDevice9 *device) +{
- struct
- {
D3DFORMAT src_format;
const PALETTEENTRY *src_palette;
const RECT src_rect;
const void *src_data;
D3DFORMAT dst_format;
const void *expected_dst_data;
BOOL partial_todo;
Is this going to be used at some point?
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
if (SUCCEEDED(hr))
{
const uint32_t src_pitch = get_bpp_for_d3dformat(tests[i].src_format) * tests[i].src_rect.right;
const uint32_t dst_pitch = get_bpp_for_d3dformat(tests[i].dst_format) * tests[i].src_rect.right;
IDirect3DSurface9 *surf;
hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &surf);
ok(hr == D3D_OK, "Failed to get the surface, hr %#lx.\n", hr);
hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, tests[i].src_data, tests[i].src_format,
src_pitch, tests[i].src_palette, &tests[i].src_rect, D3DX_FILTER_NONE, 0);
todo_wine_if(tests[i].todo) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
if (SUCCEEDED(hr))
{
const uint32_t dst_fmt_bpp = get_bpp_for_d3dformat(tests[i].dst_format);
uint32_t match_count, mismatch_count;
Similarly for `match_count`, is there any use for it?
This merge request was approved by Matteo Bruni.
I left a couple of non-blocking comments :slight_smile: