-- v3: d3dx9: Don't color key compressed pixel formats on 32-bit d3dx9. d3dx9: Calculate a range of color key channel values in d3dx_load_pixels_from_pixels() if necessary. d3dx9: Set all color channels to zero when color keying. d3dx9/tests: Add some color key tests. d3dx9: Move code for format conversion of a single pixel into a common helper function. d3dx9: Make functions for pixel copying/conversion/filtering static.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 12 ------------ dlls/d3dx9_36/surface.c | 16 ++++++++++------ 2 files changed, 10 insertions(+), 18 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 0e965eb6017..dabe714f611 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -374,18 +374,6 @@ void format_to_d3dx_color(const struct pixel_format_desc *format, const BYTE *sr 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, - const struct pixel_format_desc *format); -void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, - const struct volume *src_size, const struct pixel_format_desc *src_format, - BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *dst_size, - const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette); -void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, - const struct volume *src_size, const struct pixel_format_desc *src_format, - BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *dst_size, - const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette); - HRESULT lock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, D3DLOCKED_RECT *lock, IDirect3DSurface9 **temp_surface, BOOL write); HRESULT unlock_surface(IDirect3DSurface9 *surface, const RECT *surface_rect, diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index e3bc77bd52e..decea5677e5 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1415,6 +1415,10 @@ static HRESULT d3dx_image_tga_rle_decode_row(const uint8_t **src, uint32_t src_b return D3D_OK; }
+static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, + const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, + const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, + const PALETTEENTRY *palette); static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size, struct d3dx_image *image) { @@ -2411,7 +2415,7 @@ void format_from_d3dx_color(const struct pixel_format_desc *format, const struct * Works for any pixel format. * The source and the destination must be block-aligned. */ -void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, +static 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, const struct pixel_format_desc *format) { @@ -2442,7 +2446,7 @@ void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, * any necessary format conversion and color keying. * Pixels outsize the source rect are blacked out. */ -void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, +static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette) @@ -2542,10 +2546,10 @@ void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pit * any necessary format conversion, color keying and stretching * using a point filter. */ -void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, - const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, - const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, - const PALETTEENTRY *palette) +static void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, + const struct volume *src_size, const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, + UINT dst_slice_pitch, const struct volume *dst_size, const struct pixel_format_desc *dst_format, + D3DCOLOR color_key, const PALETTEENTRY *palette) { struct argb_conversion_info conv_info, ck_conv_info; const struct pixel_format_desc *ck_format;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 144 +++++++++++++++------------------------- 1 file changed, 53 insertions(+), 91 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index decea5677e5..3a6b8b78ebf 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -2439,6 +2439,51 @@ static void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitc } }
+static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format_desc *src_fmt, + uint8_t *dst_ptr, const struct pixel_format_desc *dst_fmt, const PALETTEENTRY *palette, + struct argb_conversion_info *conv_info, D3DCOLOR color_key, const struct pixel_format_desc *ck_format, + struct argb_conversion_info *ck_conv_info) +{ + if (format_types_match(src_fmt, dst_fmt) && src_fmt->bytes_per_pixel <= 4 && dst_fmt->bytes_per_pixel <= 4) + { + DWORD channels[4]; + DWORD val; + + get_relevant_argb_components(conv_info, src_ptr, channels); + val = make_argb_color(conv_info, channels); + + if (color_key) + { + DWORD ck_pixel; + + get_relevant_argb_components(ck_conv_info, src_ptr, channels); + ck_pixel = make_argb_color(ck_conv_info, channels); + if (ck_pixel == color_key) + val &= ~conv_info->destmask[0]; + } + memcpy(dst_ptr, &val, dst_fmt->bytes_per_pixel); + } + else + { + struct d3dx_color color, tmp; + + format_to_d3dx_color(src_fmt, src_ptr, palette, &color); + tmp = color; + + if (color_key) + { + DWORD ck_pixel; + + format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); + if (ck_pixel == color_key) + tmp.value.w = 0.0f; + } + + color = tmp; + format_from_d3dx_color(dst_fmt, &color, dst_ptr); + } +} + /************************************************************ * convert_argb_pixels * @@ -2451,9 +2496,9 @@ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_sl const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette) { + /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ + const struct pixel_format_desc *ck_format = color_key ? get_format_info(D3DFMT_A8R8G8B8) : NULL; struct argb_conversion_info conv_info, ck_conv_info; - const struct pixel_format_desc *ck_format; - DWORD channels[4]; UINT min_width, min_height, min_depth; UINT x, y, z;
@@ -2462,7 +2507,6 @@ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_sl src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, dst_format, color_key, palette);
- ZeroMemory(channels, sizeof(channels)); init_argb_conversion_info(src_format, dst_format, &conv_info);
min_width = min(src_size->width, dst_size->width); @@ -2470,11 +2514,7 @@ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_sl min_depth = min(src_size->depth, dst_size->depth);
if (color_key) - { - /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ - ck_format = get_format_info(D3DFMT_A8R8G8B8); init_argb_conversion_info(src_format, ck_format, &ck_conv_info); - }
for (z = 0; z < min_depth; z++) { const BYTE *src_slice_ptr = src + z * src_slice_pitch; @@ -2485,44 +2525,8 @@ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_sl BYTE *dst_ptr = dst_slice_ptr + y * dst_row_pitch;
for (x = 0; x < min_width; x++) { - if (format_types_match(src_format, dst_format) - && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4) - { - DWORD val; - - get_relevant_argb_components(&conv_info, src_ptr, channels); - val = make_argb_color(&conv_info, channels); - - if (color_key) - { - DWORD ck_pixel; - - get_relevant_argb_components(&ck_conv_info, src_ptr, channels); - ck_pixel = make_argb_color(&ck_conv_info, channels); - if (ck_pixel == color_key) - val &= ~conv_info.destmask[0]; - } - memcpy(dst_ptr, &val, dst_format->bytes_per_pixel); - } - else - { - struct d3dx_color color, tmp; - - format_to_d3dx_color(src_format, src_ptr, palette, &color); - tmp = color; - - if (color_key) - { - DWORD ck_pixel; - - format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); - if (ck_pixel == color_key) - tmp.value.w = 0.0f; - } - - color = tmp; - format_from_d3dx_color(dst_format, &color, dst_ptr); - } + convert_argb_pixel(src_ptr, src_format, dst_ptr, dst_format, palette, + &conv_info, color_key, ck_format, &ck_conv_info);
src_ptr += src_format->bytes_per_pixel; dst_ptr += dst_format->bytes_per_pixel; @@ -2551,9 +2555,9 @@ static void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT s UINT dst_slice_pitch, const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, const PALETTEENTRY *palette) { + /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ + const struct pixel_format_desc *ck_format = color_key ? get_format_info(D3DFMT_A8R8G8B8) : NULL; struct argb_conversion_info conv_info, ck_conv_info; - const struct pixel_format_desc *ck_format; - DWORD channels[4]; UINT x, y, z;
TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " @@ -2561,15 +2565,10 @@ static void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT s src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, dst_format, color_key, palette);
- ZeroMemory(channels, sizeof(channels)); init_argb_conversion_info(src_format, dst_format, &conv_info);
if (color_key) - { - /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ - ck_format = get_format_info(D3DFMT_A8R8G8B8); init_argb_conversion_info(src_format, ck_format, &ck_conv_info); - }
for (z = 0; z < dst_size->depth; z++) { @@ -2585,45 +2584,8 @@ static void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT s { const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel;
- if (format_types_match(src_format, dst_format) - && src_format->bytes_per_pixel <= 4 && dst_format->bytes_per_pixel <= 4) - { - DWORD val; - - get_relevant_argb_components(&conv_info, src_ptr, channels); - val = make_argb_color(&conv_info, channels); - - if (color_key) - { - DWORD ck_pixel; - - get_relevant_argb_components(&ck_conv_info, src_ptr, channels); - ck_pixel = make_argb_color(&ck_conv_info, channels); - if (ck_pixel == color_key) - val &= ~conv_info.destmask[0]; - } - memcpy(dst_ptr, &val, dst_format->bytes_per_pixel); - } - else - { - struct d3dx_color color, tmp; - - format_to_d3dx_color(src_format, src_ptr, palette, &color); - tmp = color; - - if (color_key) - { - DWORD ck_pixel; - - format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); - if (ck_pixel == color_key) - tmp.value.w = 0.0f; - } - - color = tmp; - format_from_d3dx_color(dst_format, &color, dst_ptr); - } - + convert_argb_pixel(src_ptr, src_format, dst_ptr, dst_format, palette, + &conv_info, color_key, ck_format, &ck_conv_info); dst_ptr += dst_format->bytes_per_pixel; } }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/surface.c | 551 ++++++++++++++++++++++++++++++++++ 1 file changed, 551 insertions(+)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index c618ff6c48a..7d2293bcab3 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -133,6 +133,46 @@ static HRESULT create_file(const char *filename, const unsigned char *data, cons return D3DERR_INVALIDCALL; }
+static IDirect3DDevice9 *create_device(HWND *window) +{ + D3DPRESENT_PARAMETERS present_parameters = { 0 }; + IDirect3DDevice9 *device; + IDirect3D9 *d3d; + HRESULT hr; + HWND wnd; + + *window = NULL; + + if (!(wnd = CreateWindowA("static", "d3dx9_test", WS_OVERLAPPEDWINDOW, 0, 0, + 640, 480, NULL, NULL, NULL, NULL))) + { + skip("Couldn't create application window.\n"); + return NULL; + } + + if (!(d3d = Direct3DCreate9(D3D_SDK_VERSION))) + { + skip("Couldn't create IDirect3D9 object.\n"); + DestroyWindow(wnd); + return NULL; + } + + present_parameters.Windowed = TRUE; + present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + hr = IDirect3D9_CreateDevice(d3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, + &present_parameters, &device); + IDirect3D9_Release(d3d); + if (FAILED(hr)) + { + skip("Failed to create IDirect3DDevice9 object %#lx.\n", hr); + DestroyWindow(wnd); + return NULL; + } + + *window = wnd; + return device; +} + /* fills dds_header with reasonable default values */ static void fill_dds_header(struct dds_header *header) { @@ -1150,21 +1190,28 @@ static uint32_t get_bpp_for_d3dformat(D3DFORMAT format) case D3DFMT_Q16W16V16U16: return 8;
+ case D3DFMT_Q8W8V8U8: case D3DFMT_A8B8G8R8: case D3DFMT_A8R8G8B8: case D3DFMT_V16U16: case D3DFMT_G16R16: + case D3DFMT_R32F: return 4;
case D3DFMT_R8G8B8: return 3;
+ case D3DFMT_A4R4G4B4: case D3DFMT_X1R5G5B5: case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: case D3DFMT_V8U8: case D3DFMT_A8P8: return 2;
+ case D3DFMT_R3G3B2: + case D3DFMT_DXT5: + case D3DFMT_A4L4: case D3DFMT_L8: case D3DFMT_P8: return 1; @@ -2015,6 +2062,508 @@ static void test_load_surface_from_tga(IDirect3DDevice9 *device) free(tga); }
+static const uint8_t r8g8b8_4_4[] = +{ + 0xff,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0xff, + 0x00,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff, + 0x00,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0x00,0x80,0x80,0x00, +}; + +static const uint8_t r8g8b8_4_4_expected[] = +{ + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0x00,0x00,0x00,0x00, +}; + +static const uint8_t dxt5_4_4[] = +{ + 0xff,0x00,0x00,0x00,0x00,0x49,0x92,0x24,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00,0x00, +}; + +static const uint8_t dxt5_4_4_expected_32_bit[] = +{ + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff, + 0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00, + 0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00, +}; + +static const uint8_t dxt5_4_4_expected_64_bit[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00, + 0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00, +}; + +static const uint8_t dxt4_4_4[] = +{ + 0x22,0xcc,0x86,0xc6,0xe6,0x86,0xc6,0xe6,0x10,0x84,0x10,0x84,0x00,0x00,0x00,0x00, +}; + +static const uint8_t dxt4_4_4_expected_32_bit[] = +{ + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0x44,0xff,0xff,0xff,0x66, + 0xf7,0xf3,0xf7,0x88,0xc5,0xc2,0xc5,0xaa,0xa5,0xa2,0xa5,0xcc,0x84,0x82,0x84,0xff, + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x22,0xff,0xff,0xff,0x44,0xff,0xff,0xff,0x66, + 0xf7,0xf3,0xf7,0x88,0xc5,0xc2,0xc5,0xaa,0xa5,0xa2,0xa5,0xcc,0x84,0x82,0x84,0xff, +}; + +static const uint8_t dxt4_4_4_expected_64_bit[] = +{ + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x22,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x66, + 0xf7,0xf3,0xf7,0x88,0xc5,0xc2,0xc5,0xaa,0xa5,0xa2,0xa5,0xcc,0x84,0x82,0x84,0xff, + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x22,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x66, + 0xf7,0xf3,0xf7,0x88,0xc5,0xc2,0xc5,0xaa,0xa5,0xa2,0xa5,0xcc,0x84,0x82,0x84,0xff, +}; + +static const uint8_t p8_4_4[] = +{ + 0x10,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, +}; + +static const uint8_t p8_4_4_expected[] = +{ + 0x00,0x40,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t a8p8_4_4[] = +{ + 0xff,0x10,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00, + 0xf0,0x10,0xf0,0x10,0xf0,0x10,0xf0,0x10,0xf0,0x10,0xf0,0x10,0xf0,0x10,0xf0,0x10, +}; + +static const uint8_t a8p8_4_4_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0x00,0x00,0xc0,0xc0,0x00,0x00,0xc0,0xc0,0x00, + 0x00,0xc0,0xc0,0x00,0x00,0xc0,0xc0,0x00,0x00,0xc0,0xc0,0x00,0x00,0xc0,0xc0,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t a32r32g32b32_4_4[] = +{ + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t a32r32g32b32_4_4_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00, + 0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00, +}; + +static const uint8_t r32_4_4[] = +{ + 0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f,0x00,0x00,0x80,0x3f, + 0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f, + 0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x3f, +}; + +static const uint8_t r32_4_4_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xff,0xff,0x80,0xff,0xff,0xff,0x80,0xff,0xff,0xff,0x80,0xff,0xff,0xff,0x80,0xff, + 0xff,0xff,0x80,0xff,0xff,0xff,0x80,0xff,0xff,0xff,0x80,0xff,0xff,0xff,0x80,0xff, +}; + +static const uint8_t q8w8v8u8_4_4[] = +{ + 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80,0x90,0xa0,0xb0,0xc0,0xd0,0xe0,0xf0, + 0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x74,0x84,0x94,0xa4,0xb4,0xc4,0xd4,0xe4,0xf4, + 0x00,0x00,0x28,0x38,0x48,0x58,0x68,0x78,0x88,0x98,0xa8,0xb8,0xc8,0xd8,0xe8,0xf8, + 0x0c,0x1c,0x2c,0x3c,0x4c,0x5c,0x6c,0x7c,0x8c,0x9c,0xac,0xbc,0xcc,0xdc,0xec,0xfc, +}; + +static const uint8_t q8w8v8u8_4_4_expected[] = +{ + 0xa0,0x90,0x80,0xb0,0xe0,0xd0,0xc0,0xf0,0x1f,0x0f,0x00,0x2f,0x5f,0x4f,0x3f,0x6f, + 0xa4,0x94,0x84,0xb4,0xe4,0xd4,0xc4,0xf4,0x23,0x13,0x03,0x33,0x63,0x53,0x43,0x73, + 0x80,0x80,0x80,0x80,0xe8,0xd8,0xc8,0xf8,0x27,0x17,0x07,0x37,0x67,0x57,0x47,0x77, + 0xac,0x9c,0x8c,0xbc,0xec,0xdc,0xcc,0xfc,0x2b,0x1b,0x0b,0x3b,0x6b,0x5b,0x4b,0x7b, +}; + +static const uint8_t a8r8g8b8_4_4[] = +{ + 0x00,0xff,0x00,0x80,0x00,0xff,0x00,0x80,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x80,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, +}; + +static const uint8_t a8r8g8b8_4_4_expected[] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x80,0x00,0x00,0xff,0xff,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, + 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff, +}; + +static const uint8_t a4r4g4b4_4_4[] = +{ + 0xff,0x00,0x0f,0x00,0x00,0xf0,0x00,0x0f,0xf0,0x00,0xf0,0x00,0xf0,0x00,0xf0,0x00, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, +}; + +static const uint8_t a4r4g4b4_4_4_expected[] = +{ + 0xff,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t a4r4g4b4_4_4_expected2[] = +{ + 0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x00, + 0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88, + 0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88,0x00,0x88, +}; + +static const uint8_t a4l4_4_4[] = +{ + 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff, +}; + +static const uint8_t a4l4_4_4_expected[] = +{ + 0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x22,0x22,0x22,0x22,0x33,0x33,0x33,0x33, + 0x44,0x44,0x44,0x44,0x55,0x55,0x55,0x55,0x66,0x66,0x66,0x66,0x77,0x77,0x77,0x77, + 0x00,0x00,0x00,0x00,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb, + 0xcc,0xcc,0xcc,0xcc,0xdd,0xdd,0xdd,0xdd,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff, +}; + +static const uint8_t a4l4_4_4_expected2[] = +{ + 0x00,0x00,0x00,0x00,0x11,0x11,0x11,0x11,0x22,0x22,0x22,0x22,0x33,0x33,0x33,0x33, + 0x44,0x44,0x44,0x44,0x55,0x55,0x55,0x55,0x66,0x66,0x66,0x66,0x77,0x77,0x77,0x77, + 0x88,0x88,0x88,0x88,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb, + 0xcc,0xcc,0xcc,0xcc,0xdd,0xdd,0xdd,0xdd,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff, +}; + +static const uint8_t a1r5g5b5_4_4[] = +{ + 0x00,0x00,0x42,0x08,0x84,0x10,0xc6,0x18,0x08,0x21,0x4a,0x29,0x8c,0x31,0xce,0x39, + 0x10,0xc2,0x52,0xca,0x94,0xd2,0xd6,0xda,0x18,0xe3,0x5a,0xeb,0x9c,0xf3,0xde,0xfb, +}; + +static const uint8_t a1r5g5b5_4_4_expected[] = +{ + 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x00,0x21,0x21,0x21,0x00,0x31,0x31,0x31,0x00, + 0x42,0x42,0x42,0x00,0x52,0x52,0x52,0x00,0x63,0x63,0x63,0x00,0x73,0x73,0x73,0x00, + 0x84,0x84,0x84,0xff,0x94,0x94,0x94,0xff,0x00,0x00,0x00,0x00,0xb5,0xb5,0xb5,0xff, + 0xc5,0xc5,0xc5,0xff,0xd6,0xd6,0xd6,0xff,0xe6,0xe6,0xe6,0xff,0xf7,0xf7,0xf7,0xff, +}; + +static const uint8_t r5g6b5_4_4[] = +{ + 0x00,0x00,0x82,0x10,0x04,0x21,0x86,0x31,0x08,0x42,0x8a,0x52,0x0c,0x63,0x8e,0x73, + 0x10,0x84,0x92,0x94,0x14,0xa5,0x96,0xb5,0x18,0xc6,0x9a,0xd6,0x1c,0xe7,0x9e,0xf7, +}; + +static const uint8_t r5g6b5_4_4_expected[] = +{ + 0x00,0x00,0x00,0xff,0x10,0x10,0x10,0xff,0x21,0x20,0x21,0xff,0x31,0x31,0x31,0xff, + 0x42,0x41,0x42,0xff,0x52,0x51,0x52,0xff,0x63,0x61,0x63,0xff,0x73,0x71,0x73,0xff, + 0x84,0x82,0x84,0xff,0x94,0x92,0x94,0xff,0x00,0x00,0x00,0x00,0xb5,0xb2,0xb5,0xff, + 0xc5,0xc2,0xc5,0xff,0xd6,0xd2,0xd6,0xff,0xe6,0xe3,0xe6,0xff,0xf7,0xf3,0xf7,0xff, +}; + +static const uint8_t r3g3b2_4_4[] = +{ + 0x00,0x00,0x24,0x24,0x49,0x49,0x6d,0x6d,0x92,0x92,0xb6,0xb6,0xdb,0xdb,0xff,0xff, +}; + +static const uint8_t r3g3b2_4_4_expected[] = +{ + 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x24,0x24,0xff,0x00,0x24,0x24,0xff, + 0x55,0x49,0x49,0xff,0x55,0x49,0x49,0xff,0x55,0x6d,0x6d,0xff,0x55,0x6d,0x6d,0xff, + 0xaa,0x92,0x92,0xff,0xaa,0x92,0x92,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xff,0xdb,0xdb,0xff,0xff,0xdb,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +}; + +static BOOL is_dxt_d3dformat(D3DFORMAT fmt); +static void test_color_key(void) +{ + static const struct + { + D3DFORMAT src_format; + const RECT src_rect; + const void *src_data; + + const void *expected_dst_data; + D3DCOLOR color_key; + BOOL todo; + } tests[] = + { + /* Color key with alpha channel unset. */ + { + D3DFMT_R8G8B8, { 0, 0, 4, 4 }, r8g8b8_4_4, r8g8b8_4_4_expected, 0x00008080, + .todo = TRUE + }, + /* Same color key as before except the alpha channel is set. */ + { + D3DFMT_R8G8B8, { 0, 0, 4, 4 }, r8g8b8_4_4, r8g8b8_4_4_expected, 0xff008080, + .todo = TRUE + }, + /* Color key on a palette. */ + { + D3DFMT_P8, { 0, 0, 4, 4 }, p8_4_4, p8_4_4_expected, 0xf0c0c000, + .todo = TRUE + }, + { + D3DFMT_A8P8, { 0, 0, 4, 4 }, a8p8_4_4, a8p8_4_4_expected, 0x10c0c000, + .todo = TRUE + }, + { + D3DFMT_A32B32G32R32F, { 0, 0, 4, 4 }, a32r32g32b32_4_4, a32r32g32b32_4_4_expected, 0xffff0000, + .todo = TRUE + }, + /* 5. */ + /* + * Only channels that exist in the source format matter for the color + * key, other channels can be set to any value and are ignored. + */ + { + D3DFMT_R32F, { 0, 0, 4, 4 }, r32_4_4, r32_4_4_expected, 0xffff3080, + .todo = TRUE + }, + /* + * Both 0x7f and 0x80 channel values in the color key map to 0x00 in + * 8-bit SNORM. + */ + { + D3DFMT_Q8W8V8U8, { 0, 0, 4, 4 }, q8w8v8u8_4_4, q8w8v8u8_4_4_expected, 0xb87f80a8, + .todo = TRUE + }, + /* Alpha channel factors into the color key check. */ + { + D3DFMT_A8R8G8B8, { 0, 0, 4, 4 }, a8r8g8b8_4_4, a8r8g8b8_4_4_expected, 0x8000ff00, + .todo = TRUE + }, + { + D3DFMT_A8R8G8B8, { 0, 0, 4, 4 }, a8r8g8b8_4_4, a8r8g8b8_4_4, 0x0000ff00, + }, + /* + * 0x80-0x90 color key channel values all match 0x8 in the source + * format. + */ + { + D3DFMT_A4R4G4B4, { 0, 0, 4, 4 }, a4r4g4b4_4_4, a4r4g4b4_4_4_expected, 0x80009000, + .todo = TRUE + }, + /* 10. */ + /* 0xf7-0xff match 0xf in the source format. */ + { + D3DFMT_A4R4G4B4, { 0, 0, 4, 4 }, a4r4g4b4_4_4, a4r4g4b4_4_4_expected2, 0x0000f7ff, + .todo = TRUE + }, + { + D3DFMT_A4L4, { 0, 0, 4, 4 }, a4l4_4_4, a4l4_4_4_expected, 0x88818283, + .todo = TRUE + }, + { + D3DFMT_A4L4, { 0, 0, 4, 4 }, a4l4_4_4, a4l4_4_4_expected2, 0x88818200, + }, + { + D3DFMT_A1R5G5B5, { 0, 0, 4, 4 }, a1r5g5b5_4_4, a1r5g5b5_4_4_expected, 0x80a1a8a4, + .todo = TRUE + }, + { + D3DFMT_R5G6B5, { 0, 0, 4, 4 }, r5g6b5_4_4, r5g6b5_4_4_expected, 0x81a1a0a8, + .todo = TRUE + }, + /* 15. */ + { + D3DFMT_R3G3B2, { 0, 0, 4, 4 }, r3g3b2_4_4, r3g3b2_4_4_expected, 0x81a4c8bf, + .todo = TRUE + }, + }; + unsigned int i, x, y, mismatch_count; + PALETTEENTRY tmp_palette[256]; + const uint8_t *expected_dst; + IDirect3DDevice9 *device; + D3DLOCKED_RECT lock_rect; + IDirect3DSurface9 *surf; + uint32_t src_pitch; + RECT rect; + HRESULT hr; + HWND hwnd; + + if (!(device = create_device(&hwnd))) + return; + + memcpy(tmp_palette, test_palette, sizeof(test_palette)); + /* Set palette entries 0xf1-0xff to the same value. */ + for (i = 0; i < 0xf; ++i) + tmp_palette[0xf1 + i] = tmp_palette[0xf0]; + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surf, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("Test %u", i); + + mismatch_count = 0; + src_pitch = get_bpp_for_d3dformat(tests[i].src_format) * tests[i].src_rect.right; + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, tests[i].src_data, tests[i].src_format, + src_pitch, tmp_palette, &tests[i].src_rect, D3DX_FILTER_NONE, tests[i].color_key); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(surf, &lock_rect, NULL, D3DLOCK_READONLY); + for (y = 0; y < 4; ++y) + { + const uint8_t *dst_expected_row = ((const uint8_t *)tests[i].expected_dst_data) + (sizeof(uint32_t) * 4 * y); + const uint8_t *dst_row = ((const uint8_t *)lock_rect.pBits) + (lock_rect.Pitch * y); + + for (x = 0; x < 4; ++x) + { + const uint32_t dst_expected_color = ((const uint32_t *)dst_expected_row)[x]; + const uint32_t dst_color = ((const uint32_t *)dst_row)[x]; + + if (!compare_color_4bpp(dst_color, dst_expected_color, 0)) + mismatch_count++; + } + } + IDirect3DSurface9_UnlockRect(surf); + + todo_wine_if(tests[i].todo) ok(!mismatch_count, "Unexpected number of mismatched pixels %u.\n", mismatch_count); + winetest_pop_context(); + } + + /* + * Test color key handling for compressed formats. On 64-bit the color key + * is used, but on 32-bit it is ignored. + */ + SetRect(&rect, 0, 0, 4, 4); + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, dxt5_4_4, D3DFMT_DXT5, 16, NULL, &rect, D3DX_FILTER_NONE, + 0xffff0000); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + mismatch_count = 0; + expected_dst = (sizeof(void *) == 8) ? dxt5_4_4_expected_64_bit : dxt5_4_4_expected_32_bit; + IDirect3DSurface9_LockRect(surf, &lock_rect, NULL, D3DLOCK_READONLY); + for (y = 0; y < 4; ++y) + { + const uint8_t *dst_expected_row = ((const uint8_t *)expected_dst) + (sizeof(uint32_t) * 4 * y); + const uint8_t *dst_row = ((const uint8_t *)lock_rect.pBits) + (lock_rect.Pitch * y); + + if (memcmp(dst_row, dst_expected_row, sizeof(uint32_t) * 4)) + mismatch_count++; + } + IDirect3DSurface9_UnlockRect(surf); + + todo_wine ok(!mismatch_count, "Unexpected number of mismatched lines %u.\n", mismatch_count); + + /* + * Test premultiplied alpha handling with a color key - color key applies + * to the value after the premultiplied alpha transformation is undone. + */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, dxt4_4_4, D3DFMT_DXT4, 16, NULL, &rect, D3DX_FILTER_NONE, + 0x44ffffff); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + mismatch_count = 0; + expected_dst = (sizeof(void *) == 8) ? dxt4_4_4_expected_64_bit : dxt4_4_4_expected_32_bit; + IDirect3DSurface9_LockRect(surf, &lock_rect, NULL, D3DLOCK_READONLY); + for (y = 0; y < 4; ++y) + { + const uint8_t *dst_expected_row = ((const uint8_t *)expected_dst) + (sizeof(uint32_t) * 4 * y); + const uint8_t *dst_row = ((const uint8_t *)lock_rect.pBits) + (lock_rect.Pitch * y); + + if (memcmp(dst_row, dst_expected_row, sizeof(uint32_t) * 4)) + mismatch_count++; + } + IDirect3DSurface9_UnlockRect(surf); + + todo_wine ok(!mismatch_count, "Unexpected number of mismatched lines %u.\n", mismatch_count); + + /* + * Color key also has the same range of values as R5G6B5 for the color + * channels. + */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, dxt4_4_4, D3DFMT_DXT4, 16, NULL, &rect, D3DX_FILTER_NONE, + 0x44fbfdfb); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + mismatch_count = 0; + expected_dst = (sizeof(void *) == 8) ? dxt4_4_4_expected_64_bit : dxt4_4_4_expected_32_bit; + IDirect3DSurface9_LockRect(surf, &lock_rect, NULL, D3DLOCK_READONLY); + for (y = 0; y < 4; ++y) + { + const uint8_t *dst_expected_row = ((const uint8_t *)expected_dst) + (sizeof(uint32_t) * 4 * y); + const uint8_t *dst_row = ((const uint8_t *)lock_rect.pBits) + (lock_rect.Pitch * y); + + if (memcmp(dst_row, dst_expected_row, sizeof(uint32_t) * 4)) + mismatch_count++; + } + IDirect3DSurface9_UnlockRect(surf); + + todo_wine ok(!mismatch_count, "Unexpected number of mismatched lines %u.\n", mismatch_count); + + /* Values out of range for R5G6B5, won't be color keyed. */ + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, dxt4_4_4, D3DFMT_DXT4, 16, NULL, &rect, D3DX_FILTER_NONE, + 0x44fafcfa); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + mismatch_count = 0; + expected_dst = dxt4_4_4_expected_32_bit; + IDirect3DSurface9_LockRect(surf, &lock_rect, NULL, D3DLOCK_READONLY); + for (y = 0; y < 4; ++y) + { + const uint8_t *dst_expected_row = ((const uint8_t *)expected_dst) + (sizeof(uint32_t) * 4 * y); + const uint8_t *dst_row = ((const uint8_t *)lock_rect.pBits) + (lock_rect.Pitch * y); + + if (memcmp(dst_row, dst_expected_row, sizeof(uint32_t) * 4)) + mismatch_count++; + } + IDirect3DSurface9_UnlockRect(surf); + + todo_wine ok(!mismatch_count, "Unexpected number of mismatched lines %u.\n", mismatch_count); + + /* + * Trying to use D3DX_FILTER_SRGB_IN with a color key results in + * STATUS_ACCESS_VIOLATION on native. + */ + if (0) + { + const uint32_t src_pitch = get_bpp_for_d3dformat(tests[0].src_format) * tests[0].src_rect.right; + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, tests[0].src_data, tests[0].src_format, + src_pitch, NULL, &tests[0].src_rect, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, + tests[0].color_key); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + } + + check_release((IUnknown *)surf, 0); + check_release((IUnknown *)device, 0); + DestroyWindow(hwnd); +} + static void test_D3DXLoadSurface(IDirect3DDevice9 *device) { HRESULT hr; @@ -4651,4 +5200,6 @@ START_TEST(surface) check_release((IUnknown*)device, 0); check_release((IUnknown*)d3d, 0); DestroyWindow(wnd); + + test_color_key(); }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 4 ++-- dlls/d3dx9_36/tests/surface.c | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 3a6b8b78ebf..4786b29bfe3 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -2459,7 +2459,7 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format get_relevant_argb_components(ck_conv_info, src_ptr, channels); ck_pixel = make_argb_color(ck_conv_info, channels); if (ck_pixel == color_key) - val &= ~conv_info->destmask[0]; + val = 0; } memcpy(dst_ptr, &val, dst_fmt->bytes_per_pixel); } @@ -2476,7 +2476,7 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format
format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); if (ck_pixel == color_key) - tmp.value.w = 0.0f; + tmp.value.x = tmp.value.y = tmp.value.z = tmp.value.w = 0.0f; }
color = tmp; diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 7d2293bcab3..081227fdc88 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -2328,20 +2328,16 @@ static void test_color_key(void) /* Same color key as before except the alpha channel is set. */ { D3DFMT_R8G8B8, { 0, 0, 4, 4 }, r8g8b8_4_4, r8g8b8_4_4_expected, 0xff008080, - .todo = TRUE }, /* Color key on a palette. */ { D3DFMT_P8, { 0, 0, 4, 4 }, p8_4_4, p8_4_4_expected, 0xf0c0c000, - .todo = TRUE }, { D3DFMT_A8P8, { 0, 0, 4, 4 }, a8p8_4_4, a8p8_4_4_expected, 0x10c0c000, - .todo = TRUE }, { D3DFMT_A32B32G32R32F, { 0, 0, 4, 4 }, a32r32g32b32_4_4, a32r32g32b32_4_4_expected, 0xffff0000, - .todo = TRUE }, /* 5. */ /* @@ -2363,7 +2359,6 @@ static void test_color_key(void) /* Alpha channel factors into the color key check. */ { D3DFMT_A8R8G8B8, { 0, 0, 4, 4 }, a8r8g8b8_4_4, a8r8g8b8_4_4_expected, 0x8000ff00, - .todo = TRUE }, { D3DFMT_A8R8G8B8, { 0, 0, 4, 4 }, a8r8g8b8_4_4, a8r8g8b8_4_4, 0x0000ff00, @@ -2477,7 +2472,7 @@ static void test_color_key(void) } IDirect3DSurface9_UnlockRect(surf);
- todo_wine ok(!mismatch_count, "Unexpected number of mismatched lines %u.\n", mismatch_count); + todo_wine_if(sizeof(void *) == 4) ok(!mismatch_count, "Unexpected number of mismatched lines %u.\n", mismatch_count);
/* * Test premultiplied alpha handling with a color key - color key applies
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 109 ++++++++++++++++++++++++++++++---- dlls/d3dx9_36/tests/surface.c | 19 ++---- 2 files changed, 101 insertions(+), 27 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 4786b29bfe3..1651c837bde 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1415,9 +1415,10 @@ static HRESULT d3dx_image_tga_rle_decode_row(const uint8_t **src, uint32_t src_b return D3D_OK; }
+struct d3dx_color_key; static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, - const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, + const struct volume *dst_size, const struct pixel_format_desc *dst_format, const struct d3dx_color_key *color_key, const PALETTEENTRY *palette); static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size, struct d3dx_image *image) @@ -1463,7 +1464,7 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz dst_desc = get_format_info(D3DFMT_A8B8G8R8); d3dx_calculate_pixels_size(dst_desc->format, 256, 1, &dst_row_pitch, &dst_slice_pitch); convert_argb_pixels(src_palette, src_row_pitch, src_slice_pitch, &image_map_size, src_desc, (BYTE *)palette, - dst_row_pitch, dst_slice_pitch, &image_map_size, dst_desc, 0, NULL); + dst_row_pitch, dst_slice_pitch, &image_map_size, dst_desc, NULL, NULL);
/* Initialize unused palette entries to 0xff. */ if (header->color_map_length < 256) @@ -2408,6 +2409,64 @@ void format_from_d3dx_color(const struct pixel_format_desc *format, const struct } }
+struct d3dx_color_key +{ + uint8_t color_key_min[4]; + uint8_t color_key_max[4]; +}; + +static void d3dx_init_color_key(const struct pixel_format_desc *src_fmt, uint32_t color_key, + struct d3dx_color_key *color_key_out) +{ + unsigned int i; + + for (i = 0; i < 4; ++i) + { + const enum component_type src_ctype = !i ? src_fmt->a_type : src_fmt->rgb_type; + const uint8_t channel_bits = (src_ctype == CTYPE_LUMA) ? src_fmt->bits[1] : src_fmt->bits[i]; + const uint8_t ck_channel = (color_key >> (24 - (i * 8))) & 0xff; + float slop, channel_conv, unique_values; + + if (!channel_bits) + { + color_key_out->color_key_min[i] = color_key_out->color_key_max[i] = 0xff; + continue; + } + + /* + * If the source format channel can represent all unique channel + * values in the color key, no extra processing is necessary. + */ + if (src_ctype == CTYPE_FLOAT || (src_ctype == CTYPE_SNORM && channel_bits > 8) + || (src_ctype != CTYPE_SNORM && channel_bits >= 8)) + { + color_key_out->color_key_min[i] = color_key_out->color_key_max[i] = ck_channel; + continue; + } + + channel_conv = ((float)ck_channel) / 255.0f; + if (src_ctype == CTYPE_SNORM) + { + const uint32_t max_value = (1u << (channel_bits - 1)) - 1; + + unique_values = (1u << channel_bits) - 2; + channel_conv = (channel_conv * 2.0f) - 1.0f; + channel_conv = ((int8_t)(channel_conv * max_value + 0.5f)) / (float)max_value; + channel_conv = (channel_conv + 1.0f) / 2.0f; + } + else + { + unique_values = (1u << channel_bits) - 1; + channel_conv = ((uint8_t)(channel_conv * unique_values + 0.5f)) / unique_values; + } + + channel_conv = channel_conv * 255.0f + 0.5f; + slop = ((255.0f - unique_values) / unique_values) / 2.0f; + color_key_out->color_key_min[i] = d3dx_clamp(channel_conv - slop, 0.0f, 255.0f); + color_key_out->color_key_max[i] = d3dx_clamp(channel_conv + slop, 0.0f, 255.0f); + } +} + /************************************************************ * copy_pixels * @@ -2441,9 +2500,11 @@ static void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitc
static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format_desc *src_fmt, uint8_t *dst_ptr, const struct pixel_format_desc *dst_fmt, const PALETTEENTRY *palette, - struct argb_conversion_info *conv_info, D3DCOLOR color_key, const struct pixel_format_desc *ck_format, - struct argb_conversion_info *ck_conv_info) + struct argb_conversion_info *conv_info, const struct d3dx_color_key *color_key, + const struct pixel_format_desc *ck_format, struct argb_conversion_info *ck_conv_info) { + unsigned int i; + if (format_types_match(src_fmt, dst_fmt) && src_fmt->bytes_per_pixel <= 4 && dst_fmt->bytes_per_pixel <= 4) { DWORD channels[4]; @@ -2458,7 +2519,14 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format
get_relevant_argb_components(ck_conv_info, src_ptr, channels); ck_pixel = make_argb_color(ck_conv_info, channels); - if (ck_pixel == color_key) + for (i = 0; i < 4; ++i) + { + const uint8_t ck_channel = (ck_pixel >> (24 - (i * 8))) & 0xff; + + if ((ck_channel >= color_key->color_key_min[i]) != (ck_channel <= color_key->color_key_max[i])) + break; + } + if (i == 4) val = 0; } memcpy(dst_ptr, &val, dst_fmt->bytes_per_pixel); @@ -2472,10 +2540,17 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format
if (color_key) { - DWORD ck_pixel; + DWORD ck_pixel = 0;
format_from_d3dx_color(ck_format, &tmp, (BYTE *)&ck_pixel); - if (ck_pixel == color_key) + for (i = 0; i < 4; ++i) + { + const uint8_t ck_channel = (ck_pixel >> (24 - (i * 8))) & 0xff; + + if ((ck_channel >= color_key->color_key_min[i]) != (ck_channel <= color_key->color_key_max[i])) + break; + } + if (i == 4) tmp.value.x = tmp.value.y = tmp.value.z = tmp.value.w = 0.0f; }
@@ -2493,7 +2568,7 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format */ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, - const struct volume *dst_size, const struct pixel_format_desc *dst_format, D3DCOLOR color_key, + const struct volume *dst_size, const struct pixel_format_desc *dst_format, const struct d3dx_color_key *color_key, const PALETTEENTRY *palette) { /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ @@ -2503,7 +2578,7 @@ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_sl UINT x, y, z;
TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " - "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key 0x%08lx, palette %p.\n", + "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key %p, palette %p.\n", src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, dst_format, color_key, palette);
@@ -2553,7 +2628,7 @@ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_sl static void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, const struct volume *src_size, const struct pixel_format_desc *src_format, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *dst_size, const struct pixel_format_desc *dst_format, - D3DCOLOR color_key, const PALETTEENTRY *palette) + const struct d3dx_color_key *color_key, const PALETTEENTRY *palette) { /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ const struct pixel_format_desc *ck_format = color_key ? get_format_info(D3DFMT_A8R8G8B8) : NULL; @@ -2561,7 +2636,7 @@ static void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT s UINT x, y, z;
TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, " - "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key 0x%08lx, palette %p.\n", + "dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key %p, palette %p.\n", src, src_row_pitch, src_slice_pitch, src_size, src_format, dst, dst_row_pitch, dst_slice_pitch, dst_size, dst_format, color_key, palette);
@@ -2733,6 +2808,8 @@ HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, const struct pixel_format_desc *src_desc, uint32_t filter_flags, uint32_t color_key) { struct volume src_size, dst_size, dst_size_aligned; + const struct d3dx_color_key *d3dx_ck = NULL; + struct d3dx_color_key d3dx_color_key; HRESULT hr = S_OK;
TRACE("dst_pixels %s, dst_desc %p, src_pixels %s, src_desc %p, filter_flags %#x, color_key %#x.\n", @@ -2860,11 +2937,17 @@ HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, goto exit; }
+ if (color_key) + { + d3dx_init_color_key(src_desc, color_key, &d3dx_color_key); + d3dx_ck = (const struct d3dx_color_key *)&d3dx_color_key; + } + if ((filter_flags & 0xf) == D3DX_FILTER_NONE) { convert_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, src_desc, (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, dst_desc, - color_key, src_pixels->palette); + d3dx_ck, src_pixels->palette); } else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ { @@ -2875,7 +2958,7 @@ HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ point_filter_argb_pixels(src_pixels->data, src_pixels->row_pitch, src_pixels->slice_pitch, &src_size, src_desc, (BYTE *)dst_pixels->data, dst_pixels->row_pitch, dst_pixels->slice_pitch, &dst_size, - dst_desc, color_key, src_pixels->palette); + dst_desc, d3dx_ck, src_pixels->palette); }
exit: diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 081227fdc88..ca8d5d54358 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -2317,13 +2317,12 @@ static void test_color_key(void)
const void *expected_dst_data; D3DCOLOR color_key; - BOOL todo; + uint8_t max_diff; } tests[] = { /* Color key with alpha channel unset. */ { D3DFMT_R8G8B8, { 0, 0, 4, 4 }, r8g8b8_4_4, r8g8b8_4_4_expected, 0x00008080, - .todo = TRUE }, /* Same color key as before except the alpha channel is set. */ { @@ -2346,7 +2345,6 @@ static void test_color_key(void) */ { D3DFMT_R32F, { 0, 0, 4, 4 }, r32_4_4, r32_4_4_expected, 0xffff3080, - .todo = TRUE }, /* * Both 0x7f and 0x80 channel values in the color key map to 0x00 in @@ -2354,7 +2352,6 @@ static void test_color_key(void) */ { D3DFMT_Q8W8V8U8, { 0, 0, 4, 4 }, q8w8v8u8_4_4, q8w8v8u8_4_4_expected, 0xb87f80a8, - .todo = TRUE }, /* Alpha channel factors into the color key check. */ { @@ -2369,33 +2366,27 @@ static void test_color_key(void) */ { D3DFMT_A4R4G4B4, { 0, 0, 4, 4 }, a4r4g4b4_4_4, a4r4g4b4_4_4_expected, 0x80009000, - .todo = TRUE }, /* 10. */ /* 0xf7-0xff match 0xf in the source format. */ { D3DFMT_A4R4G4B4, { 0, 0, 4, 4 }, a4r4g4b4_4_4, a4r4g4b4_4_4_expected2, 0x0000f7ff, - .todo = TRUE }, { D3DFMT_A4L4, { 0, 0, 4, 4 }, a4l4_4_4, a4l4_4_4_expected, 0x88818283, - .todo = TRUE }, { D3DFMT_A4L4, { 0, 0, 4, 4 }, a4l4_4_4, a4l4_4_4_expected2, 0x88818200, }, { - D3DFMT_A1R5G5B5, { 0, 0, 4, 4 }, a1r5g5b5_4_4, a1r5g5b5_4_4_expected, 0x80a1a8a4, - .todo = TRUE + D3DFMT_A1R5G5B5, { 0, 0, 4, 4 }, a1r5g5b5_4_4, a1r5g5b5_4_4_expected, 0x80a1a8a4, 1, }, { - D3DFMT_R5G6B5, { 0, 0, 4, 4 }, r5g6b5_4_4, r5g6b5_4_4_expected, 0x81a1a0a8, - .todo = TRUE + D3DFMT_R5G6B5, { 0, 0, 4, 4 }, r5g6b5_4_4, r5g6b5_4_4_expected, 0x81a1a0a8, 1, }, /* 15. */ { D3DFMT_R3G3B2, { 0, 0, 4, 4 }, r3g3b2_4_4, r3g3b2_4_4_expected, 0x81a4c8bf, - .todo = TRUE }, }; unsigned int i, x, y, mismatch_count; @@ -2440,13 +2431,13 @@ static void test_color_key(void) const uint32_t dst_expected_color = ((const uint32_t *)dst_expected_row)[x]; const uint32_t dst_color = ((const uint32_t *)dst_row)[x];
- if (!compare_color_4bpp(dst_color, dst_expected_color, 0)) + if (!compare_color_4bpp(dst_color, dst_expected_color, tests[i].max_diff)) mismatch_count++; } } IDirect3DSurface9_UnlockRect(surf);
- todo_wine_if(tests[i].todo) ok(!mismatch_count, "Unexpected number of mismatched pixels %u.\n", mismatch_count); + ok(!mismatch_count, "Unexpected number of mismatched pixels %u.\n", mismatch_count); winetest_pop_context(); }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 5 +++++ dlls/d3dx9_36/tests/surface.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 1651c837bde..4ad27e9237a 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -2874,6 +2874,11 @@ HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, uncompressed_desc->format, 0, 0, src_pixels->size.width, src_pixels->size.height, 0, src_pixels->size.depth, &uncompressed_pixels);
+ if (sizeof(void *) == 4 && color_key) + { + TRACE("Clearing color key value on compressed source pixels.\n"); + color_key = 0; + } hr = d3dx_load_pixels_from_pixels(dst_pixels, dst_desc, &uncompressed_pixels, uncompressed_desc, filter_flags, color_key); } diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index ca8d5d54358..3f189053339 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -2463,7 +2463,7 @@ static void test_color_key(void) } IDirect3DSurface9_UnlockRect(surf);
- todo_wine_if(sizeof(void *) == 4) ok(!mismatch_count, "Unexpected number of mismatched lines %u.\n", mismatch_count); + ok(!mismatch_count, "Unexpected number of mismatched lines %u.\n", mismatch_count);
/* * Test premultiplied alpha handling with a color key - color key applies
On Fri May 2 12:03:34 2025 +0000, Connor McAdams wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/7711/diffs?diff_id=175186&start_sha=f53783959ae8bd44553a5d89031bc043eeb67e38#d49071753fdf2ab21d518dbd8c720b48c7c732fc_2286_2429)
This ended up changed back to pixel-by-pixel comparisons now due to adding new tests for lower bpc formats, our conversion to 8bpc doesn't exactly match native.
It was quite a few MRs ago, but at one point I had left code similar to this, and the idea was that it was only necessary to count while there were still existing `todo` tests. Once all tests were expected to pass, it made sense to get rid of the extra `mismatch_count` variable and just test each line directly. I've avoided doing that in the current revision and left `mismatch_count` in, even after all tests are expected to pass.
On Fri May 2 12:03:34 2025 +0000, Connor McAdams wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/7711/diffs?diff_id=175186&start_sha=f53783959ae8bd44553a5d89031bc043eeb67e38#8fffeae09861a99974e55842964630933974cdc8_2876_2945)
I've gone through and added tests for all these cases now, and we should now handle it in the code.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
mismatch_count++;
}
}
IDirect3DSurface9_UnlockRect(surf);
todo_wine_if(tests[i].todo) ok(!mismatch_count, "Unexpected number of mismatched pixels %u.\n", mismatch_count);
winetest_pop_context();
- }
- /*
* Test color key handling for compressed formats. On 64-bit the color key
* is used, but on 32-bit it is ignored.
*/
- SetRect(&rect, 0, 0, 4, 4);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, dxt5_4_4, D3DFMT_DXT5, 16, NULL, &rect, D3DX_FILTER_NONE,
0xffff0000);
It looks like this and the following tests could also plausibly work in the generic, table-based test above. There are at least a couple ways to handle the 64 vs 32 bit difference, but probably easiest is to just have a separate `expected_32` struct component. We could make it more obvious when it does actually matter by using `NULL` for it otherwise, to imply that there is no difference with the "normal" 64 bit case.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
todo_wine_if(tests[i].todo) ok(!mismatch_count, "Unexpected number of mismatched pixels %u.\n", mismatch_count);
winetest_pop_context();
- }
- /*
* Test color key handling for compressed formats. On 64-bit the color key
* is used, but on 32-bit it is ignored.
*/
- SetRect(&rect, 0, 0, 4, 4);
- hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, dxt5_4_4, D3DFMT_DXT5, 16, NULL, &rect, D3DX_FILTER_NONE,
0xffff0000);
- ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr);
- mismatch_count = 0;
- expected_dst = (sizeof(void *) == 8) ? dxt5_4_4_expected_64_bit : dxt5_4_4_expected_32_bit;
I'd call those `dxt5_4_4_expected_ck` vs `dxt5_4_4_expected_no_ck` to clarify the expected behavior at the first glance.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
+static const uint8_t r3g3b2_4_4_expected[] = +{
- 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0x24,0x24,0xff,0x00,0x24,0x24,0xff,
- 0x55,0x49,0x49,0xff,0x55,0x49,0x49,0xff,0x55,0x6d,0x6d,0xff,0x55,0x6d,0x6d,0xff,
- 0xaa,0x92,0x92,0xff,0xaa,0x92,0x92,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0xff,0xdb,0xdb,0xff,0xff,0xdb,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+};
+static BOOL is_dxt_d3dformat(D3DFORMAT fmt); +static void test_color_key(void) +{
- static const struct
- {
D3DFORMAT src_format;
const RECT src_rect;
Right now this seems to always be set to `{0, 0, 4, 4}`, so it's unnecessary unless you expect more tests to come?
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
color_key_out->color_key_min[i] = color_key_out->color_key_max[i] = 0xff;
continue;
}
/*
* If the source format channel can represent all unique channel
* values in the color key, no extra processing is necessary.
*/
if (src_ctype == CTYPE_FLOAT || (src_ctype == CTYPE_SNORM && channel_bits > 8)
|| (src_ctype != CTYPE_SNORM && channel_bits >= 8))
{
color_key_out->color_key_min[i] = color_key_out->color_key_max[i] = ck_channel;
continue;
}
channel_conv = ((float)ck_channel) / 255.0f;
The explicit cast is unnecessary: `ck_channel` is already going to be promoted to float to divide it by the float constant.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
*/
if (src_ctype == CTYPE_FLOAT || (src_ctype == CTYPE_SNORM && channel_bits > 8)
|| (src_ctype != CTYPE_SNORM && channel_bits >= 8))
{
color_key_out->color_key_min[i] = color_key_out->color_key_max[i] = ck_channel;
continue;
}
channel_conv = ((float)ck_channel) / 255.0f;
if (src_ctype == CTYPE_SNORM)
{
const uint32_t max_value = (1u << (channel_bits - 1)) - 1;
unique_values = (1u << channel_bits) - 2;
channel_conv = (channel_conv * 2.0f) - 1.0f;
channel_conv = ((int8_t)(channel_conv * max_value + 0.5f)) / (float)max_value;
A possible alternative, maybe nicer but not really any different in the generated code: ``` channel_conv = rintf(channel_conv * max_value) / max_value; ```
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
unique_values = (1u << channel_bits) - 2;
channel_conv = (channel_conv * 2.0f) - 1.0f;
channel_conv = ((int8_t)(channel_conv * max_value + 0.5f)) / (float)max_value;
channel_conv = (channel_conv + 1.0f) / 2.0f;
}
else
{
unique_values = (1u << channel_bits) - 1;
channel_conv = ((uint8_t)(channel_conv * unique_values + 0.5f)) / unique_values;
}
channel_conv = channel_conv * 255.0f + 0.5f;
slop = ((255.0f - unique_values) / unique_values) / 2.0f;
color_key_out->color_key_min[i] = d3dx_clamp(channel_conv - slop, 0.0f, 255.0f);
color_key_out->color_key_max[i] = d3dx_clamp(channel_conv + slop, 0.0f, 255.0f);
Similarly here: ``` channel_conv = channel_conv * 255.0f; slop = (255.0f - unique_values) / unique_values / 2.0f; color_key_out->color_key_min[i] = rintf(d3dx_clamp(channel_conv - slop, 0.0f, 255.0f)); color_key_out->color_key_max[i] = rintf(d3dx_clamp(channel_conv + slop, 0.0f, 255.0f)); ``` The whole conversion math is quite questionable, but the results seem to match native pretty closely so I guess it is what it is :sweat_smile:
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
+static void d3dx_init_color_key(const struct pixel_format_desc *src_fmt, uint32_t color_key,
struct d3dx_color_key *color_key_out)
+{
- unsigned int i;
- for (i = 0; i < 4; ++i)
- {
const enum component_type src_ctype = !i ? src_fmt->a_type : src_fmt->rgb_type;
const uint8_t channel_bits = (src_ctype == CTYPE_LUMA) ? src_fmt->bits[1] : src_fmt->bits[i];
const uint8_t ck_channel = (color_key >> (24 - (i * 8))) & 0xff;
float slop, channel_conv, unique_values;
if (!channel_bits)
{
color_key_out->color_key_min[i] = color_key_out->color_key_max[i] = 0xff;
This doesn't seem right to me: an 8 bit per component image could legitimately have `ck_min == ck_max == 0xff` and in the color key check in `convert_argb_pixel()` there is no special casing for a missing component.
We probably want to set a full interval instead: ```suggestion:-0+0 color_key_out->color_key_min[i] = 0; color_key_out->color_key_max[i] = 0xff; ```
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
get_relevant_argb_components(ck_conv_info, src_ptr, channels); ck_pixel = make_argb_color(ck_conv_info, channels);
if (ck_pixel == color_key)
for (i = 0; i < 4; ++i)
{
const uint8_t ck_channel = (ck_pixel >> (24 - (i * 8))) & 0xff;
if ((ck_channel >= color_key->color_key_min[i]) != (ck_channel <= color_key->color_key_max[i]))
break;
I'd have written this more naturally (to me) as: ```suggestion:-1+0 if ((ck_channel < color_key->color_key_min[i]) || (ck_channel > color_key->color_key_max[i])) break; ``` But maybe I'm missing something?
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
UINT x, y, z; TRACE("src %p, src_row_pitch %u, src_slice_pitch %u, src_size %p, src_format %p, dst %p, "
"dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key 0x%08lx, palette %p.\n",
"dst_row_pitch %u, dst_slice_pitch %u, dst_size %p, dst_format %p, color_key %p, palette %p.\n",
It might be nice to introduce a small `debugstr_color_key()` helper to show the full color key interval as it was computed.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
goto exit; }
- if (color_key)
- {
d3dx_init_color_key(src_desc, color_key, &d3dx_color_key);
d3dx_ck = (const struct d3dx_color_key *)&d3dx_color_key;
This cast is unnecessary.
I like the general color-keying approach, reminds me of how we handle it in wined3d.
Maybe we could use yet another test to highlight the component == 0xff case, although I wouldn't consider it mandatory (i.e. checking ad-hoc on the side would be alright, as far as I'm concerned). Otherwise I think this is enough tests and I'm happy with them and the conversion math. In the sense, no point in trying to come up with more tests unless / until we happen to encounter some very specific edge case with some game in the wild...