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`.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/surface.c | 602 ++++++++++++++++++++++++++++++++++ 1 file changed, 602 insertions(+)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index fdc573c3e55..b8e84389b93 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -26,6 +26,11 @@ #include <stdint.h> #include "d3dx9_test_images.h"
+static inline BOOL compare_float(float expected, float got, float allowed_error) +{ + return fabs(expected - got) <= allowed_error; +} + #define check_release(obj, exp) _check_release(__LINE__, obj, exp) static inline void _check_release(unsigned int line, IUnknown *obj, int exp) { @@ -755,6 +760,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, todo) \ + _check_pixel_float4(__LINE__, lockrect, x, y, fx, fy, fz, fw, 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, 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], 0.0001f) + && compare_float(fy, ptr[1], 0.0001f) + && compare_float(fz, ptr[2], 0.0001f) + && compare_float(fw, ptr[3], 0.0001f), + "Expected (%f, %f, %f, %f), got (%f, %f, %f, %f)\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 +784,272 @@ 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_pix_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_pix_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 +1066,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, 0.2f, 0.3f, 1.0f, 1.1f, 1.2f, 1.3f, + -0.1f, -0.2f, -0.3f, -0.4f, -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 +1491,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); + check_pixel_4bpp(&lockrect, 0, 0, 0x4d001a33); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0xffffffff); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x00000000); + 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 +1744,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); + check_pixel_2bpp(&lockrect, 0, 0, 0x4d16); + todo_wine check_pixel_2bpp(&lockrect, 1, 0, 0xffff); + todo_wine check_pixel_2bpp(&lockrect, 0, 1, 0x0000); + 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 +1995,259 @@ 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], FALSE); + check_pixel_float4(&lockrect, 1, 0, pixdata_a32b32g32r32f[4], pixdata_a32b32g32r32f[5], + pixdata_a32b32g32r32f[6], pixdata_a32b32g32r32f[7], FALSE); + check_pixel_float4(&lockrect, 0, 1, pixdata_a32b32g32r32f[8], pixdata_a32b32g32r32f[9], + pixdata_a32b32g32r32f[10], pixdata_a32b32g32r32f[11], FALSE); + check_pixel_float4(&lockrect, 1, 1, pixdata_a32b32g32r32f[12], pixdata_a32b32g32r32f[13], + pixdata_a32b32g32r32f[14], pixdata_a32b32g32r32f[15], 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.0f, 0.125984f, 0.251969f, 0.377953f, TRUE); + check_pixel_float4(&lockrect, 1, 0, 0.503937f, 0.629921f, 0.755906f, 1.0f, TRUE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, -0.755906f, -0.629921f, TRUE); + check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.377953f, -0.251969f, -0.007874f, 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.0f, 0.062745f, 0.125490f, 0.188235f, FALSE); + check_pixel_float4(&lockrect, 1, 0, 0.250980f, 0.313726f, 0.376471f, 0.439216f, FALSE); + check_pixel_float4(&lockrect, 0, 1, 0.501961f, 0.564706f, 0.627451f, 0.690196f, FALSE); + check_pixel_float4(&lockrect, 1, 1, 0.752941f, 0.815686f, 0.878431f, 1.0f, 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.0f, 0.377953f, 1.0f, 1.0f, TRUE); + check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 1.0f, TRUE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 1.0f, TRUE); + check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.007874f, 1.0f, 1.0f, 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, 0.181996f, 0.363992f, 0.0f, TRUE); + check_pixel_float4(&lockrect, 1, 0, 0.545988f, 0.727984f, 1.0f, 0.333333f, TRUE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, -0.547945f, 0.666667f, TRUE); + check_pixel_float4(&lockrect, 1, 1, -0.365949f, -0.183953f, -0.001957f, 1.0f, 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); + + /* 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.0f, 0.377953f, 1.0f, 0.0f, TRUE); + check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 0.333333f, TRUE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 0.666667f, TRUE); + check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.007874f, 1.0f, 1.0f, TRUE); + 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, "D3DXLoadSurfaceFromMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + 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, 0x26190d00); + todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0x7f7f7f7f); + todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0xcedbe8f4); + 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 blue channel is empty. + */ + 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 will be copied. */ + 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); + + /* Copy the V8U8 channels. */ + 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 | 122 ++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index b8e84389b93..6b88c3e721b 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1050,6 +1050,127 @@ static void test_format_conversion(IDirect3DDevice9 *device) } }
+static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) +{ + static const uint32_t src_pixels[] = + { + 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, + 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, + }; + static const uint32_t src_pixels_expected_pma[] = + { + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, + }; + /* 4x4 block of red pixels with an alpha value of 0. */ + static const uint8_t dxt_block[] = + { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa, + }; + 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); + if (FAILED(hr)) + { + skip("Failed to create A8R8G8B8 surface, hr %#lx.\n", hr); + return; + } + + for (i = 0; i < 2; ++i) + { + const D3DFORMAT pma_dxt_fmt = !i ? D3DFMT_DXT2 : D3DFMT_DXT4; + const D3DFORMAT dxt_fmt = !i ? D3DFMT_DXT3 : D3DFMT_DXT5; + struct surface_readback surface_rb; + IDirect3DSurface9 *pma_surf, *surf; + IDirect3DTexture9 *pma_tex, *tex; + + winetest_push_context("Test %s", !i ? "DXT2/DXT3" : "DXT4/DXT5"); + hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, pma_dxt_fmt, D3DPOOL_SYSTEMMEM, &pma_tex, NULL); + if (FAILED(hr)) + { + skip("Failed to create texture for format %#x, hr %#lx.\n", pma_dxt_fmt, hr); + winetest_pop_context(); + continue; + } + + hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, dxt_fmt, D3DPOOL_SYSTEMMEM, &tex, NULL); + if (FAILED(hr)) + { + skip("Failed to create texture for format %#x, hr %#lx.\n", dxt_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); + + /* Load each DXT surface with the same data. */ + hr = D3DXLoadSurfaceFromMemory(pma_surf, NULL, NULL, src_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, src_pixels, D3DFMT_A8B8G8R8, 16, NULL, &src_rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + /* DXT surface with premultiplied alpha, colors are premultiplied by alpha on upload. */ + get_surface_decompressed_readback(device, pma_surf, &surface_rb); + for (y = 0; y < 4; ++y) + { + for (x = 0; x < 4; ++x) + check_readback_pixel_4bpp(&surface_rb, x, y, src_pixels_expected_pma[(y * 4) + x], !!(x & 0x01)); + } + release_surface_readback(&surface_rb); + + /* DXT surface without premultiplied alpha, colors match what was uploaded. */ + 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, src_pixels[(y * 4) + x], FALSE); + } + release_surface_readback(&surface_rb); + + /* + * Load the DXT block as a premultiplied alpha format. It's + * demultiplied on upload. + */ + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, dxt_block, pma_dxt_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) + todo_wine check_pixel_4bpp(&lock_rect, x, y, 0x00000000); + } + IDirect3DSurface9_UnlockRect(decomp_surf); + + /* Load the DXT block as a regular DXT format. It's uploaded as is. */ + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, dxt_block, dxt_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, 0x00ff0000); + } + 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; @@ -2247,6 +2368,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 | 11 ++++++++++- dlls/d3dx9_36/tests/surface.c | 12 ++++++------ 2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index f5d0184422b..4ef64a0a904 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1474,6 +1474,11 @@ static void get_relevant_argb_components(const struct argb_conversion_info *info } }
+static float d3dx_clamp(float value, float min_value, float max_value) +{ + return value < min_value ? min_value : value > max_value ? max_value : value; +} + /************************************************************ * make_argb_color * @@ -1550,7 +1555,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 * ((1 << 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 6b88c3e721b..867bb8006a3 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1634,9 +1634,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); check_pixel_4bpp(&lockrect, 0, 0, 0x4d001a33); - todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0xffffffff); - todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0x00000000); - todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x00000000); + check_pixel_4bpp(&lockrect, 1, 0, 0xffffffff); + check_pixel_4bpp(&lockrect, 0, 1, 0x00000000); + check_pixel_4bpp(&lockrect, 1, 1, 0x00000000); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
@@ -1886,9 +1886,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); check_pixel_2bpp(&lockrect, 0, 0, 0x4d16); - todo_wine check_pixel_2bpp(&lockrect, 1, 0, 0xffff); - todo_wine check_pixel_2bpp(&lockrect, 0, 1, 0x0000); - todo_wine check_pixel_2bpp(&lockrect, 1, 1, 0x0000); + check_pixel_2bpp(&lockrect, 1, 0, 0xffff); + check_pixel_2bpp(&lockrect, 0, 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
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 | 1 + dlls/d3dx9_36/surface.c | 2 +- dlls/d3dx9_36/texture.c | 69 +++++------------------------------ 3 files changed, 11 insertions(+), 61 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index bf16b3a7590..7ddc3b06764 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -179,6 +179,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_vec4(const struct pixel_format_desc *format, const BYTE *src, struct vec4 *dst); +void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *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 4ef64a0a904..9b24bf08e5c 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1533,7 +1533,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) +void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *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..29781ccd839 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,13 @@ 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; + 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); + format_from_vec4(format, (const struct vec4 *)&value, dst); } } if (FAILED(hr = unlock_surface(surface, NULL, temp_surface, TRUE))) @@ -1757,13 +1703,15 @@ 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; + 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); + format_from_vec4(format, (const struct vec4 *)&value, dst); } } IDirect3DCubeTexture9_UnlockRect(texture, f, m); @@ -1824,12 +1772,13 @@ 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; + 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); + format_from_vec4(format, (const struct vec4 *)&value, dst); } } }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 8 +-- dlls/d3dx9_36/surface.c | 48 +++++++++++++++--- dlls/d3dx9_36/tests/surface.c | 92 +++++++++++++++++------------------ dlls/d3dx9_36/texture.c | 6 +-- dlls/d3dx9_36/util.c | 1 + 5 files changed, 94 insertions(+), 61 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 7ddc3b06764..97db64655dc 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -76,6 +76,7 @@ enum format_type { FORMAT_ARGBF, /* float */ FORMAT_DXT, FORMAT_INDEX, + FORMAT_ARGB_SNORM, FORMAT_UNKNOWN };
@@ -157,7 +158,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; } @@ -165,7 +166,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; } @@ -179,7 +180,8 @@ 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_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, BYTE *dst); +void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, enum format_type src_type, + 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 9b24bf08e5c..d36018541d9 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1524,6 +1524,26 @@ void format_to_vec4(const struct pixel_format_desc *format, const BYTE *src, str *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 = (1 << (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; } @@ -1533,7 +1553,8 @@ void format_to_vec4(const struct pixel_format_desc *format, const BYTE *src, str }
/* It doesn't work for components bigger than 32 bits. */ -void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, BYTE *dst) +void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 *src, enum format_type src_type, + BYTE *dst) { DWORD v, mask32; unsigned int c, i; @@ -1554,11 +1575,24 @@ void format_from_vec4(const struct pixel_format_desc *format, const struct vec4 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 = (1 << (format->bits[c] - 1)) - 1; + float val = src_component; + + if (src_type == FORMAT_ARGB) + 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_type == FORMAT_ARGB_SNORM) + val = (val + 1.0f) / 2.0f;
- v = val * ((1 << format->bits[c]) - 1) + 0.5f; + v = d3dx_clamp(val, 0.0f, 1.0f) * ((1 << format->bits[c]) - 1) + 0.5f; }
for (i = format->shift[c] / 8 * 8; i < format->shift[c] + format->bits[c]; i += 8) @@ -1691,7 +1725,7 @@ void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pit { DWORD ck_pixel;
- format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel); + format_from_vec4(ck_format, &tmp, src_format->type, (BYTE *)&ck_pixel); if (ck_pixel == color_key) tmp.w = 0.0f; } @@ -1701,7 +1735,7 @@ void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pit else color = tmp;
- format_from_vec4(dst_format, &color, dst_ptr); + format_from_vec4(dst_format, &color, src_format->type, dst_ptr); }
src_ptr += src_format->bytes_per_pixel; @@ -1799,7 +1833,7 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic { DWORD ck_pixel;
- format_from_vec4(ck_format, &tmp, (BYTE *)&ck_pixel); + format_from_vec4(ck_format, &tmp, src_format->type, (BYTE *)&ck_pixel); if (ck_pixel == color_key) tmp.w = 0.0f; } @@ -1809,7 +1843,7 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic else color = tmp;
- format_from_vec4(dst_format, &color, dst_ptr); + format_from_vec4(dst_format, &color, src_format->type, dst_ptr); }
dst_ptr += dst_format->bytes_per_pixel; diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 867bb8006a3..9bc067f1222 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1615,18 +1615,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); @@ -1867,18 +1865,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); @@ -2143,14 +2139,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.0f, 0.125984f, 0.251969f, 0.377953f, TRUE); - check_pixel_float4(&lockrect, 1, 0, 0.503937f, 0.629921f, 0.755906f, 1.0f, TRUE); - check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, -0.755906f, -0.629921f, TRUE); - check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.377953f, -0.251969f, -0.007874f, TRUE); + check_pixel_float4(&lockrect, 0, 0, 0.0f, 0.125984f, 0.251969f, 0.377953f, FALSE); + check_pixel_float4(&lockrect, 1, 0, 0.503937f, 0.629921f, 0.755906f, 1.0f, FALSE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, -0.755906f, -0.629921f, FALSE); + check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.377953f, -0.251969f, -0.007874f, FALSE); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
@@ -2226,53 +2222,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, "D3DXLoadSurfaceFromMemory returned %#lx, expected %#lx\n", hr, D3D_OK); + ok(hr == D3D_OK, "D3DXLoadSurfaceFromMemory returned %#lx, expected %#lx\n", hr, D3D_OK); 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, 0x26190d00); - todo_wine check_pixel_4bpp(&lockrect, 1, 0, 0x7f7f7f7f); - todo_wine check_pixel_4bpp(&lockrect, 0, 1, 0xcedbe8f4); - todo_wine check_pixel_4bpp(&lockrect, 1, 1, 0x82828282); + check_pixel_4bpp(&lockrect, 0, 0, 0x26190d00); + check_pixel_4bpp(&lockrect, 1, 0, 0x7f7f7f7f); + check_pixel_4bpp(&lockrect, 0, 1, 0xcedbe8f4); + 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/texture.c b/dlls/d3dx9_36/texture.c index 29781ccd839..ce87feefe0b 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -1320,7 +1320,7 @@ HRESULT WINAPI D3DXFillTexture(struct IDirect3DTexture9 *texture, LPD3DXFILL2D f
function(&value, &coord, &size, funcdata);
- format_from_vec4(format, (const struct vec4 *)&value, dst); + format_from_vec4(format, (const struct vec4 *)&value, FORMAT_ARGBF, dst); } } if (FAILED(hr = unlock_surface(surface, NULL, temp_surface, TRUE))) @@ -1711,7 +1711,7 @@ HRESULT WINAPI D3DXFillCubeTexture(struct IDirect3DCubeTexture9 *texture, LPD3DX
function(&value, &coord, &size, funcdata);
- format_from_vec4(format, (const struct vec4 *)&value, dst); + format_from_vec4(format, (const struct vec4 *)&value, FORMAT_ARGBF, dst); } } IDirect3DCubeTexture9_UnlockRect(texture, f, m); @@ -1778,7 +1778,7 @@ HRESULT WINAPI D3DXFillVolumeTexture(struct IDirect3DVolumeTexture9 *texture, LP
function(&value, &coord, &size, funcdata);
- format_from_vec4(format, (const struct vec4 *)&value, dst); + format_from_vec4(format, (const struct vec4 *)&value, FORMAT_ARGBF, dst); } } } 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 | 57 ++++++++++++++++++++--------------- dlls/d3dx9_36/util.c | 1 + 2 files changed, 33 insertions(+), 25 deletions(-)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 9bc067f1222..7ce70bcba4d 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -722,7 +722,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);
@@ -978,7 +978,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 }, }; @@ -2167,14 +2167,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.0f, 0.377953f, 1.0f, 1.0f, TRUE); - check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 1.0f, TRUE); - check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 1.0f, TRUE); - check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.007874f, 1.0f, 1.0f, TRUE); + check_pixel_float4(&lockrect, 0, 0, 0.0f, 0.377953f, 1.0f, 1.0f, FALSE); + check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 1.0f, FALSE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 1.0f, FALSE); + check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.007874f, 1.0f, 1.0f, FALSE); hr = IDirect3DSurface9_UnlockRect(surf); ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
@@ -2196,16 +2196,18 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) 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); - - /* 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.0f, 0.377953f, 1.0f, 0.0f, TRUE); - check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 0.333333f, TRUE); - check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 0.666667f, TRUE); - check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.007874f, 1.0f, 1.0f, TRUE); - hr = IDirect3DSurface9_UnlockRect(surf); - ok(hr == D3D_OK, "Failed to unlock surface, 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.0f, 0.377953f, 1.0f, 0.0f, TRUE); + check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 0.333333f, TRUE); + check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 0.666667f, TRUE); + check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.007874f, 1.0f, 1.0f, TRUE); + hr = IDirect3DSurface9_UnlockRect(surf); + ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr); + }
check_release((IUnknown*)surf, 0); } @@ -2334,26 +2336,31 @@ 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);
/* Copy the V8U8 channels. */ 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 }, };
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
#include <stdint.h> #include "d3dx9_test_images.h"
+static inline BOOL compare_float(float expected, float got, float allowed_error) +{
- return fabs(expected - got) <= allowed_error;
+}
It would be preferable to check for relative error, like e.g. in d3dx9_36/tests/{effect.c,math.c} or d3d9/tests/visual.c, if that works out alright.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
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_pix_data;
Absolute nitpick, but this could be just `src_data` (also given `expected_dst_data` below.)
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
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},
Just a very mild suggestion that you can take or not at your pleasure. Maybe add an empty line every 4, splitting entries in groups of 16?
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
}
- 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],
Double whitespaces here.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
check_pixel_float4(&lockrect, 1, 1, pixdata_a32b32g32r32f[12], pixdata_a32b32g32r32f[13],
pixdata_a32b32g32r32f[14], pixdata_a32b32g32r32f[15], 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.0f, 0.125984f, 0.251969f, 0.377953f, TRUE);
check_pixel_float4(&lockrect, 1, 0, 0.503937f, 0.629921f, 0.755906f, 1.0f, TRUE);
check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, -0.755906f, -0.629921f, TRUE);
check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.377953f, -0.251969f, -0.007874f, TRUE);
Good test, showing the two encodings for -1.0f and exact 0.0f for SNORM.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
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, 0.2f, 0.3f, 1.0f, 1.1f, 1.2f, 1.3f,
-0.1f, -0.2f, -0.3f, -0.4f, -1.0f, -1.1f, -1.2f, -1.3f };
We might want to test some more exotic values as well, like +-Inf or NaN.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
- 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 blue channel is empty.
I guess, technically, it's the `X` channel to be set to 0.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
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 will be copied. */
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);
Interesting.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
/* 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);
/* Copy the V8U8 channels. */
"Copy" here is a bit misleading given that 0x80 and 0x81 values are both nudged to 0x82.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
- if (FAILED(hr))
- {
skip("Failed to create A8R8G8B8 surface, hr %#lx.\n", hr);
return;
- }
- for (i = 0; i < 2; ++i)
- {
const D3DFORMAT pma_dxt_fmt = !i ? D3DFMT_DXT2 : D3DFMT_DXT4;
const D3DFORMAT dxt_fmt = !i ? D3DFMT_DXT3 : D3DFMT_DXT5;
struct surface_readback surface_rb;
IDirect3DSurface9 *pma_surf, *surf;
IDirect3DTexture9 *pma_tex, *tex;
winetest_push_context("Test %s", !i ? "DXT2/DXT3" : "DXT4/DXT5");
hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, pma_dxt_fmt, D3DPOOL_SYSTEMMEM, &pma_tex, NULL);
It seems nicer to make the test table-based, even if it's just for 2 entries, like: ``` static const struct test { D3DFORMAT pma_fmt; D3DFORMAT nonpma_fmt; const char *name; } tests[] = { { D3DFMT_DXT2, D3DFMT_DXT3, "DXT2 / DXT3" }, { D3DFMT_DXT4, D3DFMT_DXT5, "DXT4 / DXT5" }, }; ```
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
- };
- /* 4x4 block of red pixels with an alpha value of 0. */
- static const uint8_t dxt_block[] =
- {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0xf8,0xaa,0xaa,0xaa,0xaa,
- };
- 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);
- if (FAILED(hr))
I think we don't need to handle the failure case here (i.e. so many existing tests would fail if we can't create that kind of surface.)
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
}
release_surface_readback(&surface_rb);
/* DXT surface without premultiplied alpha, colors match what was uploaded. */
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, src_pixels[(y * 4) + x], FALSE);
}
release_surface_readback(&surface_rb);
/*
* Load the DXT block as a premultiplied alpha format. It's
* demultiplied on upload.
*/
Another one of those nitpicks, sorry... "Demultiplied" is a bit of an awkward word (admittedly undoing the premultiplied alpha is an awkward operation in the first place, nothing we can do about that though). I don't have any great suggestion, maybe just spelling out the whole "reversing the premultiplication" in some way is fine (while pushing the naming issue to whenever it's time to implement it :sweat_smile:).
I guess the comment could mention explicitly that we're uploading the premultiplied alpha data into an uncompressed format surface.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
for (x = 0; x < 4; ++x)
check_readback_pixel_4bpp(&surface_rb, x, y, src_pixels[(y * 4) + x], FALSE);
}
release_surface_readback(&surface_rb);
/*
* Load the DXT block as a premultiplied alpha format. It's
* demultiplied on upload.
*/
hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, dxt_block, pma_dxt_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)
todo_wine check_pixel_4bpp(&lock_rect, x, y, 0x00000000);
Can we use a more interesting test image so that we get non-black output here? I realize this means using two different test images and / or expected results for the two tests.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
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, "D3DXLoadSurfaceFromMemory returned %#lx, expected %#lx\n", hr, D3D_OK);
```suggestion:-0+0 todo_wine ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); ```
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/d3dx9_private.h:
FORMAT_ARGBF, /* float */ FORMAT_DXT, FORMAT_INDEX,
- FORMAT_ARGB_SNORM,
Since we don't need to preserve the existing values, we could use alphabetic order for the enum.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
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 = (1 << (format->bits[c] - 1)) - 1;
float val = src_component;
if (src_type == FORMAT_ARGB)
val = (val * 2.0f) - 1.0f;
This works, but I think it would be better if we stored the "range" (e.g. UNORM, SNORM, full range) as a property of the value itself (or, specifically, of each component) instead of having to bring around the source type as separate, additional data. So perhaps something like ``` struct d3dx_color { vec4 value; enum range range[4]; }; ``` which `format_to_vec4()` generates and `format_from_vec4()` consumes.
I haven't really thought it through, so this might be all kinds of ugly or impractical.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 0.666667f, TRUE);
check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.007874f, 1.0f, 1.0f, TRUE);
hr = IDirect3DSurface9_UnlockRect(surf);
ok(hr == D3D_OK, "Failed to unlock surface, 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.0f, 0.377953f, 1.0f, 0.0f, TRUE);
check_pixel_float4(&lockrect, 1, 0, 0.503937f, 1.0f, 1.0f, 0.333333f, TRUE);
check_pixel_float4(&lockrect, 0, 1, -1.0f, -1.0f, 1.0f, 0.666667f, TRUE);
check_pixel_float4(&lockrect, 1, 1, -0.503937f, -0.007874f, 1.0f, 1.0f, TRUE);
hr = IDirect3DSurface9_UnlockRect(surf);
ok(hr == D3D_OK, "Failed to unlock surface, hr %#lx.\n", hr);
}
Is the `if (SUCCEEDED(hr)){}` to avoid spurious successes from the last working `D3DXLoadSurfaceFromMemory()` call? Instead I think I'd either update the last argument of those `check_pixel_float4()` calls as necessary (even if they only pass by chance) or put the `if (SUCCEEDED(hr)){}` in the patch originally introducing the test.
I left a lot of comments but I think it's mostly fluff...
Special thanks for 4/6, getting rid of redundant code is always great :grin:
I happened to have some WIP patches for SNORM formats from a long time ago which I never was very happy with. So thanks for taking care of that as well. In my notes I have bugs 41996 and 42054 as needing SNORM (there are probably more), I guess we can ping those once the patches are in.