[PATCH v3 0/7] MR10513: d3dx{9,10,11}: Add support for premultiplied alpha and SRGB conversions.
-- v3: d3dx{9,10,11}: Handle SRGB filter flags. d3dx{10,11}/tests: Add tests for SRGB formats and filter flags. d3dx9/tests: Add tests for D3DX_FILTER_SRGB flags. d3dx{10,11}: Only use passed in filter flags if image scaling is necessary. d3dx{10,11}/tests: Add a test for invalid image load filter flags. d3dx9: Properly handle DXT textures with premultiplied alpha. d3dx{10,11}/tests: Add tests for decoding DXTn DDS files. https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/d3dx10_43/tests/d3dx10.c | 90 +++++++++++++++++++++++++++++++++++ dlls/d3dx11_43/tests/d3dx11.c | 90 +++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index 3ea4499f20e..edea0feaf1d 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -5601,6 +5601,95 @@ static void test_image_filters(void) ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); } +/* + * DXT2 and DXT4 are decoded without taking premultiplied alpha + * into account on d3dx10/d3dx11. + */ +static void test_dxt_formats(void) +{ + static const uint8_t expected_dst[] = + { + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + }; + static const uint8_t test_dxt2_dxt3_data[] = + { + 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x86,0x31,0x04,0x21,0x11,0x11,0x11,0x11, + }; + static const uint8_t test_dxt4_dxt5_data[] = + { + 0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x31,0x04,0x21,0x11,0x11,0x11,0x11, + }; + static const struct + { + DWORD format; + const void *data; + unsigned int size; + } tests[] = + { + { MAKEFOURCC('D','X','T','2'), test_dxt2_dxt3_data, sizeof(test_dxt2_dxt3_data) }, + { MAKEFOURCC('D','X','T','3'), test_dxt2_dxt3_data, sizeof(test_dxt2_dxt3_data) }, + { MAKEFOURCC('D','X','T','4'), test_dxt4_dxt5_data, sizeof(test_dxt4_dxt5_data) }, + { MAKEFOURCC('D','X','T','5'), test_dxt4_dxt5_data, sizeof(test_dxt4_dxt5_data) }, + }; + struct + { + DWORD magic; + struct dds_header header; + BYTE data[256]; + } dds; + D3DX10_IMAGE_LOAD_INFO load_info; + struct resource_readback rb; + ID3D10Resource *resource; + ID3D10Device *device; + unsigned int i; + HRESULT hr; + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + CoInitialize(NULL); + + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + dds.header.pixel_format.flags = DDS_PF_FOURCC; + dds.header.pixel_format.bpp = 0; + dds.header.pixel_format.rmask = 0; + dds.header.pixel_format.gmask = 0; + dds.header.pixel_format.bmask = 0; + dds.header.pixel_format.amask = 0; + + memset(dds.data, 0, sizeof(dds.data)); + load_info = d3dx10_default_load_info; + load_info.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + load_info.Filter = load_info.MipFilter = D3DX10_FILTER_NONE; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("Test %u (%s)", i, debugstr_fourcc(tests[i].format)); + memcpy(dds.data, tests[i].data, tests[i].size); + dds.header.pixel_format.fourcc = tests[i].format; + + hr = D3DX10CreateTextureFromMemory(device, &dds, sizeof(dds), &load_info, NULL, &resource, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + get_resource_readback(resource, 0, &rb); + check_test_readback(&rb, expected_dst, 4, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0); + release_resource_readback(&rb); + ID3D10Resource_Release(resource); + winetest_pop_context(); + } + + CoUninitialize(); + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); +} + #define check_rect(rect, left, top, right, bottom) _check_rect(__LINE__, rect, left, top, right, bottom) static inline void _check_rect(unsigned int line, const RECT *rect, int left, int top, int right, int bottom) { @@ -7090,4 +7179,5 @@ START_TEST(d3dx10) test_legacy_dds_header_image_info(); test_dxt10_dds_header_image_info(); test_image_filters(); + test_dxt_formats(); } diff --git a/dlls/d3dx11_43/tests/d3dx11.c b/dlls/d3dx11_43/tests/d3dx11.c index 4801506b039..992bfddf289 100644 --- a/dlls/d3dx11_43/tests/d3dx11.c +++ b/dlls/d3dx11_43/tests/d3dx11.c @@ -4419,6 +4419,95 @@ static void test_image_filters(void) ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); } +/* + * DXT2 and DXT4 are decoded without taking premultiplied alpha + * into account on d3dx10/d3dx11. + */ +static void test_dxt_formats(void) +{ + static const uint8_t expected_dst[] = + { + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + }; + static const uint8_t test_dxt2_dxt3_data[] = + { + 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x86,0x31,0x04,0x21,0x11,0x11,0x11,0x11, + }; + static const uint8_t test_dxt4_dxt5_data[] = + { + 0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x31,0x04,0x21,0x11,0x11,0x11,0x11, + }; + static const struct + { + DWORD format; + const void *data; + unsigned int size; + } tests[] = + { + { MAKEFOURCC('D','X','T','2'), test_dxt2_dxt3_data, sizeof(test_dxt2_dxt3_data) }, + { MAKEFOURCC('D','X','T','3'), test_dxt2_dxt3_data, sizeof(test_dxt2_dxt3_data) }, + { MAKEFOURCC('D','X','T','4'), test_dxt4_dxt5_data, sizeof(test_dxt4_dxt5_data) }, + { MAKEFOURCC('D','X','T','5'), test_dxt4_dxt5_data, sizeof(test_dxt4_dxt5_data) }, + }; + struct + { + DWORD magic; + struct dds_header header; + BYTE data[256]; + } dds; + D3DX11_IMAGE_LOAD_INFO load_info; + struct resource_readback rb; + ID3D11Resource *resource; + ID3D11Device *device; + unsigned int i; + HRESULT hr; + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + CoInitialize(NULL); + + dds.magic = MAKEFOURCC('D','D','S',' '); + fill_dds_header(&dds.header); + dds.header.pixel_format.flags = DDS_PF_FOURCC; + dds.header.pixel_format.bpp = 0; + dds.header.pixel_format.rmask = 0; + dds.header.pixel_format.gmask = 0; + dds.header.pixel_format.bmask = 0; + dds.header.pixel_format.amask = 0; + + memset(dds.data, 0, sizeof(dds.data)); + load_info = d3dx11_default_load_info; + load_info.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + load_info.Filter = load_info.MipFilter = D3DX11_FILTER_NONE; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("Test %u (%s)", i, debugstr_fourcc(tests[i].format)); + memcpy(dds.data, tests[i].data, tests[i].size); + dds.header.pixel_format.fourcc = tests[i].format; + + hr = D3DX11CreateTextureFromMemory(device, &dds, sizeof(dds), &load_info, NULL, &resource, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + get_resource_readback(resource, 0, &rb); + check_test_readback(&rb, expected_dst, 4, 4, 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0); + release_resource_readback(&rb); + ID3D11Resource_Release(resource); + winetest_pop_context(); + } + + CoUninitialize(); + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); +} + static BOOL create_directory(const WCHAR *dir) { WCHAR path[MAX_PATH]; @@ -4591,4 +4680,5 @@ START_TEST(d3dx11) test_legacy_dds_header_image_info(); test_dxt10_dds_header_image_info(); test_image_filters(); + test_dxt_formats(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/d3dx9_36/d3dx_helpers.c | 91 +++++++++++++++++++++++++++++------ dlls/d3dx9_36/d3dx_helpers.h | 8 +++ dlls/d3dx9_36/tests/surface.c | 15 ++---- 3 files changed, 89 insertions(+), 25 deletions(-) diff --git a/dlls/d3dx9_36/d3dx_helpers.c b/dlls/d3dx9_36/d3dx_helpers.c index 4c0f49be1d4..573a550b5b0 100644 --- a/dlls/d3dx9_36/d3dx_helpers.c +++ b/dlls/d3dx9_36/d3dx_helpers.c @@ -53,6 +53,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3dx); #define D3DX_FILTER_SRGB_OUT 0x00400000 #define D3DX_FILTER_SRGB 0x00600000 +/* These are custom Wine only filter flags. */ +#define D3DX_FILTER_PMA_IN 0x00800000 +#define D3DX_FILTER_PMA_OUT 0x01000000 +#define D3DX_FILTER_PMA 0x01800000 + #define D3DX_FILTER_INVALID_BITS 0xff80fff8 HRESULT d3dx_validate_filter(uint32_t filter) { @@ -62,6 +67,16 @@ HRESULT d3dx_validate_filter(uint32_t filter) return D3D_OK; } +static uint32_t d3dx_conv_flags_from_filter(uint32_t filter) +{ + uint32_t conv_flags = 0; + + if ((filter & D3DX_FILTER_PMA) && ((filter & D3DX_FILTER_PMA) != D3DX_FILTER_PMA)) + conv_flags |= (filter & D3DX_FILTER_PMA_IN) ? CONV_FLAG_PM_ALPHA_IN : CONV_FLAG_PM_ALPHA_OUT; + + return conv_flags; +} + HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); /************************************************************ @@ -100,9 +115,9 @@ static const struct pixel_format_desc formats[] = {D3DX_PIXEL_FORMAT_L8_UNORM, { 0, 8, 0, 0}, { 0, 0, 0, 0}, 1, 1, 1, 1, CTYPE_EMPTY, CTYPE_LUMA, 0 }, {D3DX_PIXEL_FORMAT_L16_UNORM, { 0, 16, 0, 0}, { 0, 0, 0, 0}, 2, 1, 1, 2, CTYPE_EMPTY, CTYPE_LUMA, 0 }, {D3DX_PIXEL_FORMAT_DXT1_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT2_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_DXT2_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT|FMT_FLAG_PM_ALPHA}, {D3DX_PIXEL_FORMAT_DXT3_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, - {D3DX_PIXEL_FORMAT_DXT4_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, + {D3DX_PIXEL_FORMAT_DXT4_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT|FMT_FLAG_PM_ALPHA}, {D3DX_PIXEL_FORMAT_DXT5_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 16, CTYPE_UNORM, CTYPE_UNORM, FMT_FLAG_DXT}, {D3DX_PIXEL_FORMAT_BC4_UNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_EMPTY, CTYPE_UNORM, FMT_FLAG_DXT|FMT_FLAG_DXGI}, {D3DX_PIXEL_FORMAT_BC4_SNORM, { 0, 0, 0, 0}, { 0, 0, 0, 0}, 1, 4, 4, 8, CTYPE_EMPTY, CTYPE_SNORM, FMT_FLAG_DXT|FMT_FLAG_DXGI}, @@ -1205,6 +1220,16 @@ static HRESULT d3dx_initialize_image_from_dds(const void *src_data, uint32_t src if ((image->format = d3dx_pixel_format_id_from_dds_pixel_format(&header->pixel_format)) == D3DX_PIXEL_FORMAT_COUNT) return D3DXERR_INVALIDDATA; + if (flags & D3DX_IMAGE_SUPPORT_DXT10 && (image->format == D3DX_PIXEL_FORMAT_DXT2_UNORM + || image->format == D3DX_PIXEL_FORMAT_DXT4_UNORM)) + { + TRACE("Loading a DXT%d texture on d3dx10+, ignoring premultiplied alpha.\n", + image->format == D3DX_PIXEL_FORMAT_DXT2_UNORM ? 2 : 4); + if (image->format == D3DX_PIXEL_FORMAT_DXT2_UNORM) + image->format = D3DX_PIXEL_FORMAT_DXT3_UNORM; + else + image->format = D3DX_PIXEL_FORMAT_DXT5_UNORM; + } image->image_file_format = D3DX_IMAGE_FILE_FORMAT_DDS; image->layer_count = 1; @@ -1632,7 +1657,7 @@ 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, const struct d3dx_color_key *color_key, - const PALETTEENTRY *palette); + const PALETTEENTRY *palette, uint32_t conv_flags); static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_size, uint32_t src_header_size, struct d3dx_image *image) @@ -1678,7 +1703,7 @@ static HRESULT d3dx_image_tga_decode(const void *src_data, uint32_t src_data_siz dst_desc = get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_R8G8B8A8_UNORM); 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, NULL, NULL); + dst_row_pitch, dst_slice_pitch, &image_map_size, dst_desc, NULL, NULL, 0); /* Initialize unused palette entries to 0xff. */ if (header->color_map_length < 256) @@ -2429,14 +2454,29 @@ static void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitc } } +static void premultiplied_alpha_from_straight_alpha(struct vec4 *vec) +{ + vec->x *= vec->w; + vec->y *= vec->w; + vec->z *= vec->w; +} + +static void straight_alpha_from_premultiplied_alpha(struct vec4 *vec) +{ + vec->x = (vec->w == 0.0f) ? 0.0f : vec->x / vec->w; + vec->y = (vec->w == 0.0f) ? 0.0f : vec->y / vec->w; + vec->z = (vec->w == 0.0f) ? 0.0f : vec->z / vec->w; +} + 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, const struct d3dx_color_key *color_key, - const struct pixel_format_desc *ck_format, struct argb_conversion_info *ck_conv_info) + const struct pixel_format_desc *ck_format, struct argb_conversion_info *ck_conv_info, uint32_t conv_flags) { unsigned int i; - if (format_types_match(src_fmt, dst_fmt) && src_fmt->bytes_per_pixel <= 4 && dst_fmt->bytes_per_pixel <= 4) + if (format_types_match(src_fmt, dst_fmt) && src_fmt->bytes_per_pixel <= 4 && dst_fmt->bytes_per_pixel <= 4 + && !conv_flags) { DWORD channels[4]; DWORD val; @@ -2467,6 +2507,8 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format struct d3dx_color color, tmp; format_to_d3dx_color(src_fmt, src_ptr, palette, &color); + if (conv_flags & CONV_FLAG_PM_ALPHA_IN) + straight_alpha_from_premultiplied_alpha(&color.value); tmp = color; if (color_key) @@ -2486,6 +2528,8 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format } color = tmp; + if (conv_flags & CONV_FLAG_PM_ALPHA_OUT) + premultiplied_alpha_from_straight_alpha(&color.value); format_from_d3dx_color(dst_fmt, &color, dst_ptr); } } @@ -2500,7 +2544,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, const struct d3dx_color_key *color_key, - const PALETTEENTRY *palette) + const PALETTEENTRY *palette, uint32_t conv_flags) { /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; @@ -2532,7 +2576,7 @@ static void convert_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_sl for (x = 0; x < min_width; x++) { convert_argb_pixel(src_ptr, src_format, dst_ptr, dst_format, palette, - &conv_info, color_key, ck_format, &ck_conv_info); + &conv_info, color_key, ck_format, &ck_conv_info, conv_flags); src_ptr += src_format->bytes_per_pixel; dst_ptr += dst_format->bytes_per_pixel; @@ -2559,7 +2603,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, - const struct d3dx_color_key *color_key, const PALETTEENTRY *palette) + const struct d3dx_color_key *color_key, const PALETTEENTRY *palette, uint32_t conv_flags) { /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; @@ -2591,7 +2635,7 @@ 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; convert_argb_pixel(src_ptr, src_format, dst_ptr, dst_format, palette, - &conv_info, color_key, ck_format, &ck_conv_info); + &conv_info, color_key, ck_format, &ck_conv_info, conv_flags); dst_ptr += dst_format->bytes_per_pixel; } } @@ -2640,7 +2684,7 @@ static inline void vec4_scale(struct vec4 *out, const float scale) static void box_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, - const struct d3dx_color_key *color_key, const PALETTEENTRY *palette) + const struct d3dx_color_key *color_key, const PALETTEENTRY *palette, uint32_t conv_flags) { /* Color keys are always represented in D3DFMT_A8R8G8B8 format. */ const struct pixel_format_desc *ck_format = color_key ? get_d3dx_pixel_format_info(D3DX_PIXEL_FORMAT_B8G8R8A8_UNORM) : NULL; @@ -2681,28 +2725,38 @@ static void box_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src const BYTE *ptr = src_ptr + i * src_slice_pitch; format_to_d3dx_color(src_format, ptr, palette, &tmp); + if (conv_flags & CONV_FLAG_PM_ALPHA_IN) + straight_alpha_from_premultiplied_alpha(&color.value); if (color_key) check_color_key(&tmp, color_key, ck_format); vec4_add(&color.value, &tmp.value); format_to_d3dx_color(src_format, ptr + src_format->bytes_per_pixel, palette, &tmp); + if (conv_flags & CONV_FLAG_PM_ALPHA_IN) + straight_alpha_from_premultiplied_alpha(&color.value); if (color_key) check_color_key(&tmp, color_key, ck_format); vec4_add(&color.value, &tmp.value); ptr += src_row_pitch; format_to_d3dx_color(src_format, ptr, palette, &tmp); + if (conv_flags & CONV_FLAG_PM_ALPHA_IN) + straight_alpha_from_premultiplied_alpha(&color.value); if (color_key) check_color_key(&tmp, color_key, ck_format); vec4_add(&color.value, &tmp.value); format_to_d3dx_color(src_format, ptr + src_format->bytes_per_pixel, palette, &tmp); + if (conv_flags & CONV_FLAG_PM_ALPHA_IN) + straight_alpha_from_premultiplied_alpha(&color.value); if (color_key) check_color_key(&tmp, color_key, ck_format); vec4_add(&color.value, &tmp.value); } vec4_scale(&color.value, src_size->depth > 1 ? 0.125f : 0.25f); + if (conv_flags & CONV_FLAG_PM_ALPHA_OUT) + premultiplied_alpha_from_straight_alpha(&color.value); format_from_d3dx_color(dst_format, &color, dst_ptr); dst_ptr += dst_format->bytes_per_pixel; } @@ -3125,12 +3179,20 @@ HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, struct volume src_size, dst_size, dst_size_aligned; const struct d3dx_color_key *d3dx_ck = NULL; struct d3dx_color_key d3dx_color_key; + uint32_t conv_flags; HRESULT hr = S_OK; TRACE("dst_pixels %s, dst_desc %p, src_pixels %s, src_desc %p, filter_flags %#x, color_key %#x.\n", debug_d3dx_pixels(dst_pixels), dst_desc, debug_d3dx_pixels(src_pixels), src_desc, filter_flags, color_key); + if (src_desc->flags & FMT_FLAG_PM_ALPHA) + filter_flags |= D3DX_FILTER_PMA_IN; + + if (dst_desc->flags & FMT_FLAG_PM_ALPHA) + filter_flags |= D3DX_FILTER_PMA_OUT; + + conv_flags = d3dx_conv_flags_from_filter(filter_flags); if (is_compressed_format(src_desc)) set_volume_struct(&src_size, (src_pixels->unaligned_rect.right - src_pixels->unaligned_rect.left), (src_pixels->unaligned_rect.bottom - src_pixels->unaligned_rect.top), src_pixels->size.depth); @@ -3150,6 +3212,7 @@ HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, && (dst_size.height == src_size.height && !(dst_size.height % dst_desc->block_height)) && (dst_size.depth == src_size.depth) && color_key == 0 + && !conv_flags && !(src_pixels->unaligned_rect.left & (src_desc->block_width - 1)) && !(src_pixels->unaligned_rect.top & (src_desc->block_height - 1)) && !(dst_pixels->unaligned_rect.left & (dst_desc->block_width - 1)) @@ -3280,13 +3343,13 @@ HRESULT d3dx_load_pixels_from_pixels(struct d3dx_pixels *dst_pixels, { 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, - d3dx_ck, src_pixels->palette); + d3dx_ck, src_pixels->palette, conv_flags); } else if ((filter_flags & 0xf) == D3DX_FILTER_BOX) { box_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, d3dx_ck, src_pixels->palette); + dst_desc, d3dx_ck, src_pixels->palette, conv_flags); } else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ { @@ -3297,7 +3360,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, d3dx_ck, src_pixels->palette); + dst_desc, d3dx_ck, src_pixels->palette, conv_flags); } exit: diff --git a/dlls/d3dx9_36/d3dx_helpers.h b/dlls/d3dx9_36/d3dx_helpers.h index 9b85149cbaa..5b65f52cfa3 100644 --- a/dlls/d3dx9_36/d3dx_helpers.h +++ b/dlls/d3dx9_36/d3dx_helpers.h @@ -242,6 +242,12 @@ enum d3dx_pixel_format_id #define D3DX_PIXEL_FORMAT_BC3_UNORM D3DX_PIXEL_FORMAT_DXT5_UNORM /* for internal use */ +enum conversion_flag +{ + CONV_FLAG_PM_ALPHA_IN = 0x01, + CONV_FLAG_PM_ALPHA_OUT = 0x02, +}; + enum component_type { CTYPE_EMPTY, @@ -264,6 +270,8 @@ enum format_flag * equivalent. */ FMT_FLAG_DXGI = 0x08, + /* Formats with premultiplied alpha, i.e DXT2/DXT4. */ + FMT_FLAG_PM_ALPHA = 0x10, }; struct pixel_format_desc { diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index c72c4a01877..1f2596e1cac 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1326,7 +1326,7 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) { const uint32_t expected_pixel = !(x & 0x01) ? 0xffffffff : 0x00000000; - check_readback_pixel_4bpp(&surface_rb, x, y, expected_pixel, !expected_pixel); + check_readback_pixel_4bpp(&surface_rb, x, y, expected_pixel, FALSE); } } release_surface_readback(&surface_rb); @@ -1348,17 +1348,10 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) */ hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, tests[i].dxt_block, tests[i].pma_fmt, 16, NULL, &src_rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); - IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); - for (y = 0; y < 4; ++y) - { - for (x = 0; x < 4; ++x) - { - const uint32_t expected_pixel = dxt_pma_decompressed_expected[(y * 4) + x]; - const BOOL todo = ((expected_pixel >> 24) & 0xff) != 0xff; - todo_wine_if(todo) check_pixel_4bpp(&lock_rect, x, y, expected_pixel); - } - } + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + check_test_readback(lock_rect.pBits, lock_rect.Pitch, lock_rect.Pitch * 4, dxt_pma_decompressed_expected, 4, 4, + 1, D3DFMT_A8B8G8R8, 1); IDirect3DSurface9_UnlockRect(decomp_surf); /* -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/d3dx10_43/tests/d3dx10.c | 47 +++++++++++++++++++++++++++++++---- dlls/d3dx11_43/tests/d3dx11.c | 47 +++++++++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index edea0feaf1d..5a22240d37b 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -806,6 +806,25 @@ static const uint8_t dds_cube_map_4_4[] = 0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x00, }; +/* 4x4 DXT10 DDS file with a format of DXGI_FORMAT_R8G8B8A8_UNORM. */ +static const uint8_t dds_dxt10_4_4[] = +{ + 0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x04,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,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,0x20,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x44,0x58,0x31,0x30,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, + 0x1c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x20,0x20,0x20,0x20, + 0x30,0x30,0x30,0x30,0x40,0x40,0x40,0x40,0x50,0x50,0x50,0x50,0x60,0x60,0x60,0x60, + 0x70,0x70,0x70,0x70,0x80,0x80,0x80,0x80,0x90,0x90,0x90,0x90,0xa0,0xa0,0xa0,0xa0, + 0xb0,0xb0,0xb0,0xb0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd0,0xd0,0xd0,0xe0,0xe0,0xe0,0xe0, + 0xf0,0xf0,0xf0,0xf0, +}; + /* 1x1 wmp image */ static const uint8_t test_wmp[] = { @@ -1826,6 +1845,24 @@ static const struct test_image_load_info } } }, + /* + * Pass in invalid filter flags. Ignored if the dimensions and format of the + * destination texture match the source image. + */ + { + dds_dxt10_4_4, sizeof(dds_dxt10_4_4), + { + D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, 1, (D3D10_USAGE)D3DX10_DEFAULT, + D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, 7, D3DX10_DEFAULT + }, + S_OK, D3D10_RESOURCE_DIMENSION_TEXTURE2D, + { + .desc_2d = + { + 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D10_USAGE_DEFAULT, D3D10_BIND_SHADER_RESOURCE, 0, 0 + } + } + }, }; static const struct test_invalid_image_load_info @@ -5044,7 +5081,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX10CreateTextureFromMemory(device, test->data, test->size, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -5245,7 +5282,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX10CreateTextureFromFileW(device, path, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -5255,7 +5292,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX10CreateTextureFromFileA(device, get_str_a(path), &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -5366,7 +5403,7 @@ static void test_create_texture(void) hr = D3DX10CreateTextureFromResourceW(device, resource_module, test_resource_name, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -5377,7 +5414,7 @@ static void test_create_texture(void) hr = D3DX10CreateTextureFromResourceA(device, resource_module, get_str_a(test_resource_name), &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); diff --git a/dlls/d3dx11_43/tests/d3dx11.c b/dlls/d3dx11_43/tests/d3dx11.c index 992bfddf289..30efd8a341e 100644 --- a/dlls/d3dx11_43/tests/d3dx11.c +++ b/dlls/d3dx11_43/tests/d3dx11.c @@ -806,6 +806,25 @@ static const uint8_t dds_cube_map_4_4[] = 0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x00, }; +/* 4x4 DXT10 DDS file with a format of DXGI_FORMAT_R8G8B8A8_UNORM. */ +static const uint8_t dds_dxt10_4_4[] = +{ + 0x44,0x44,0x53,0x20,0x7c,0x00,0x00,0x00,0x01,0x10,0x00,0x00,0x04,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,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,0x20,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x44,0x58,0x31,0x30,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, + 0x1c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x20,0x20,0x20,0x20, + 0x30,0x30,0x30,0x30,0x40,0x40,0x40,0x40,0x50,0x50,0x50,0x50,0x60,0x60,0x60,0x60, + 0x70,0x70,0x70,0x70,0x80,0x80,0x80,0x80,0x90,0x90,0x90,0x90,0xa0,0xa0,0xa0,0xa0, + 0xb0,0xb0,0xb0,0xb0,0xc0,0xc0,0xc0,0xc0,0xd0,0xd0,0xd0,0xd0,0xe0,0xe0,0xe0,0xe0, + 0xf0,0xf0,0xf0,0xf0, +}; + /* 1x1 wmp image */ static const uint8_t test_wmp[] = { @@ -1798,6 +1817,24 @@ static const struct test_image_load_info } } }, + /* + * Pass in invalid filter flags. Ignored if the dimensions and format of the + * destination texture match the source image. + */ + { + dds_dxt10_4_4, sizeof(dds_dxt10_4_4), + { + D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, 1, (D3D11_USAGE)D3DX11_DEFAULT, + D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, D3DX11_DEFAULT, 7, D3DX11_DEFAULT + }, + S_OK, D3D11_RESOURCE_DIMENSION_TEXTURE2D, + { + .desc_2d = + { + 4, 4, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, { 1, 0 }, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0 + } + } + }, }; static const struct test_invalid_image_load_info @@ -3868,7 +3905,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX11CreateTextureFromMemory(device, test->data, test->size, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -4063,7 +4100,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX11CreateTextureFromFileW(device, path, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -4073,7 +4110,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX11CreateTextureFromFileA(device, get_str_a(path), &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -4184,7 +4221,7 @@ static void test_create_texture(void) hr = D3DX11CreateTextureFromResourceW(device, resource_module, test_resource_name, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -4195,7 +4232,7 @@ static void test_create_texture(void) hr = D3DX11CreateTextureFromResourceA(device, resource_module, get_str_a(test_resource_name), &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/d3dx10_43/tests/d3dx10.c | 10 +++++----- dlls/d3dx10_43/texture.c | 25 +++++++++++++++++-------- dlls/d3dx11_43/tests/d3dx11.c | 10 +++++----- dlls/d3dx11_43/texture.c | 25 +++++++++++++++++-------- 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index 5a22240d37b..c35351a2301 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -5081,7 +5081,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX10CreateTextureFromMemory(device, test->data, test->size, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -5282,7 +5282,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX10CreateTextureFromFileW(device, path, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -5292,7 +5292,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX10CreateTextureFromFileA(device, get_str_a(path), &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -5403,7 +5403,7 @@ static void test_create_texture(void) hr = D3DX10CreateTextureFromResourceW(device, resource_module, test_resource_name, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -5414,7 +5414,7 @@ static void test_create_texture(void) hr = D3DX10CreateTextureFromResourceA(device, resource_module, get_str_a(test_resource_name), &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); diff --git a/dlls/d3dx10_43/texture.c b/dlls/d3dx10_43/texture.c index aa173e3f004..bb312ae42ff 100644 --- a/dlls/d3dx10_43/texture.c +++ b/dlls/d3dx10_43/texture.c @@ -649,14 +649,6 @@ HRESULT load_texture_data(const void *data, SIZE_T size, D3DX10_IMAGE_LOAD_INFO return E_FAIL; *resource_data = NULL; - if (!load_info->Filter || load_info->Filter == D3DX10_DEFAULT) - load_info->Filter = D3DX10_FILTER_LINEAR; - if (FAILED(hr = d3dx_validate_filter(load_info->Filter))) - { - WARN("Invalid filter argument %#x.\n", load_info->Filter); - return hr; - } - hr = d3dx_image_init(data, size, &image, 0, D3DX_IMAGE_SUPPORT_DXT10); if (FAILED(hr)) return E_FAIL; @@ -710,6 +702,23 @@ HRESULT load_texture_data(const void *data, SIZE_T size, D3DX10_IMAGE_LOAD_INFO load_info->MipLevels = (load_info->MipLevels == D3DX10_FROM_FILE) ? img_info.MipLevels : max_mip_level_count; load_info->MipLevels = min(max_mip_level_count, load_info->MipLevels); + if ((load_info->Width != image.size.width) || (load_info->Height != image.size.height) + || (load_info->Depth != image.size.depth) || (load_info->MipLevels != image.mip_levels) + || (fmt_desc->format != image.format)) + { + if (!load_info->Filter || load_info->Filter == D3DX10_DEFAULT) + load_info->Filter = D3DX10_FILTER_LINEAR; + if (FAILED(hr = d3dx_validate_filter(load_info->Filter))) + { + WARN("Invalid filter argument %#x.\n", load_info->Filter); + goto end; + } + } + else + { + load_info->Filter = D3DX10_FILTER_NONE; + } + hr = d3dx_create_subresource_data_for_texture(load_info->Width, load_info->Height, load_info->Depth, load_info->MipLevels, img_info.ArraySize, fmt_desc, &sub_rsrcs); if (FAILED(hr)) diff --git a/dlls/d3dx11_43/tests/d3dx11.c b/dlls/d3dx11_43/tests/d3dx11.c index 30efd8a341e..5bdfb0de976 100644 --- a/dlls/d3dx11_43/tests/d3dx11.c +++ b/dlls/d3dx11_43/tests/d3dx11.c @@ -3905,7 +3905,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX11CreateTextureFromMemory(device, test->data, test->size, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -4100,7 +4100,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX11CreateTextureFromFileW(device, path, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -4110,7 +4110,7 @@ static void test_create_texture(void) hr2 = 0xdeadbeef; hr = D3DX11CreateTextureFromFileA(device, get_str_a(path), &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -4221,7 +4221,7 @@ static void test_create_texture(void) hr = D3DX11CreateTextureFromResourceW(device, resource_module, test_resource_name, &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); @@ -4232,7 +4232,7 @@ static void test_create_texture(void) hr = D3DX11CreateTextureFromResourceA(device, resource_module, get_str_a(test_resource_name), &load_info, NULL, &resource, &hr2); ok(hr == hr2, "Got unexpected hr2 %#lx.\n", hr2); - todo_wine_if(i == 2) ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); + ok(hr == test->expected_hr, "Got unexpected hr %#lx.\n", hr); if (SUCCEEDED(hr)) { check_test_image_load_info_resource(resource, test); diff --git a/dlls/d3dx11_43/texture.c b/dlls/d3dx11_43/texture.c index e3218e3ec04..21f5b008964 100644 --- a/dlls/d3dx11_43/texture.c +++ b/dlls/d3dx11_43/texture.c @@ -384,14 +384,6 @@ HRESULT load_texture_data(const void *data, SIZE_T size, D3DX11_IMAGE_LOAD_INFO return E_FAIL; *resource_data = NULL; - if (!load_info->Filter || load_info->Filter == D3DX11_DEFAULT) - load_info->Filter = D3DX11_FILTER_LINEAR; - if (FAILED(hr = d3dx_validate_filter(load_info->Filter))) - { - WARN("Invalid filter argument %#x.\n", load_info->Filter); - return hr; - } - hr = d3dx_image_init(data, size, &image, 0, D3DX_IMAGE_SUPPORT_DXT10); if (FAILED(hr)) return E_FAIL; @@ -445,6 +437,23 @@ HRESULT load_texture_data(const void *data, SIZE_T size, D3DX11_IMAGE_LOAD_INFO load_info->MipLevels = (load_info->MipLevels == D3DX11_FROM_FILE) ? img_info.MipLevels : max_mip_level_count; load_info->MipLevels = min(max_mip_level_count, load_info->MipLevels); + if ((load_info->Width != image.size.width) || (load_info->Height != image.size.height) + || (load_info->Depth != image.size.depth) || (load_info->MipLevels != image.mip_levels) + || (fmt_desc->format != image.format)) + { + if (!load_info->Filter || load_info->Filter == D3DX11_DEFAULT) + load_info->Filter = D3DX11_FILTER_LINEAR; + if (FAILED(hr = d3dx_validate_filter(load_info->Filter))) + { + WARN("Invalid filter argument %#x.\n", load_info->Filter); + goto end; + } + } + else + { + load_info->Filter = D3DX11_FILTER_NONE; + } + hr = d3dx_create_subresource_data_for_texture(load_info->Width, load_info->Height, load_info->Depth, load_info->MipLevels, img_info.ArraySize, fmt_desc, &sub_rsrcs); if (FAILED(hr)) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/d3dx9_36/tests/d3dx9_test_images.h | 43 +++++ dlls/d3dx9_36/tests/surface.c | 237 ++++++++++++++++++++++-- 2 files changed, 266 insertions(+), 14 deletions(-) diff --git a/dlls/d3dx9_36/tests/d3dx9_test_images.h b/dlls/d3dx9_36/tests/d3dx9_test_images.h index 49fa4135ca6..c6e59ef0efc 100644 --- a/dlls/d3dx9_36/tests/d3dx9_test_images.h +++ b/dlls/d3dx9_36/tests/d3dx9_test_images.h @@ -95,6 +95,24 @@ test_filter_values[] = { 0xff800001, D3DERR_INVALIDCALL }, }; +static inline const char *debug_d3dx_filter(uint32_t filter_flags) +{ + static const char *filter_types[] = { "", "D3DX_FILTER_NONE", "D3DX_FILTER_POINT", "D3DX_FILTER_LINEAR", + "D3DX_FILTER_TRIANGLE", "D3DX_FILTER_BOX", "", "" }; + static const char *srgb_types[] = { "", "|D3DX_FILTER_SRGB_IN", "|D3DX_FILTER_SRGB_OUT", "|D3DX_FILTER_SRGB" }; + static const char *dither_types[] = { "", "|D3DX_FILTER_DITHER", "|D3DX_FILTER_DITHER_DIFFUSION", ""}; + static const char *mirror_types[] = { "", "|D3DX_FILTER_MIRROR_U", "|D3DX_FILTER_MIRROR_V", + "|D3DX_FILTER_MIRROR_U|D3DX_FILTER_MIRROR_V", "|D3DX_FILTER_MIRROR_W", + "|D3DX_FILTER_MIRROR_U|D3DX_FILTER_MIRROR_W", + "|D3DX_FILTER_MIRROR_V|D3DX_FILTER_MIRROR_W", "|D3DX_FILTER_MIRROR", }; + const uint8_t mirror = ((filter_flags >> 16) & 0x7); + const uint8_t dither = ((filter_flags >> 19) & 0x3); + const uint8_t srgb = ((filter_flags >> 21) & 0x3); + const uint8_t filter = (filter_flags & 0x7); + + return wine_dbg_sprintf("%s%s%s%s", filter_types[filter], mirror_types[mirror], dither_types[dither], srgb_types[srgb]); +} + static const PALETTEENTRY test_palette[256] = { {0x00,0x00,0x00,0x00}, {0x00,0x00,0x80,0x01}, {0x00,0x80,0x00,0x02}, {0x00,0x80,0x80,0x03}, @@ -1972,6 +1990,19 @@ static inline BOOL compare_uint(uint32_t x, uint32_t y, uint32_t max_diff) return diff <= max_diff; } +static inline BOOL compare_float(float f, float g, uint32_t ulps) +{ + int32_t x = *(int32_t *)&f; + int32_t y = *(int32_t *)&g; + + if (x < 0) + x = INT_MIN - x; + if (y < 0) + y = INT_MIN - y; + + return compare_uint(x, y, ulps); +} + static inline BOOL compare_color_4bpp(uint32_t c1, uint32_t c2, uint8_t max_diff) { return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) @@ -2008,6 +2039,15 @@ static inline BOOL check_readback_pixel_4bpp_rgba(const void *got, const void *e return compare_color_4bpp(*a, *b, max_diff); } +static inline BOOL check_readback_pixel_float4_rgba(const void *got, const void *expected, uint32_t max_diff) +{ + const float *a = got; + const float *b = expected; + + return (compare_float(a[0], b[0], max_diff) && compare_float(a[1], b[1], max_diff) + && compare_float(a[2], b[2], max_diff) && compare_float(a[3], b[3], max_diff)); +} + typedef BOOL (*check_readback_pixel_func)(const void *, const void *, uint32_t); static inline check_readback_pixel_func get_readback_pixel_func_for_d3dformat(D3DFORMAT format) { @@ -2017,6 +2057,9 @@ static inline check_readback_pixel_func get_readback_pixel_func_for_d3dformat(D3 case D3DFMT_A8R8G8B8: return check_readback_pixel_4bpp_rgba; + case D3DFMT_A32B32G32R32F: + return check_readback_pixel_float4_rgba; + default: assert(0 && "Need to add format to get_readback_pixel_func_for_d3dformat()."); return 0; diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 1f2596e1cac..99a6af38ae8 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -26,19 +26,6 @@ #include <stdint.h> #include "d3dx9_test_images.h" -static BOOL compare_float(float f, float g, uint32_t ulps) -{ - int32_t x = *(int32_t *)&f; - int32_t y = *(int32_t *)&g; - - if (x < 0) - x = INT_MIN - x; - if (y < 0) - y = INT_MIN - y; - - return compare_uint(x, y, ulps); -} - #define check_release(obj, exp) _check_release(__LINE__, obj, exp) static inline void _check_release(unsigned int line, IUnknown *obj, int exp) { @@ -1252,6 +1239,28 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) { 0x22,0xcc,0x86,0xc6,0xe6,0x86,0xc6,0xe6,0x10,0x84,0x10,0x84,0x00,0x00,0x00,0x00, }; + static const uint8_t dxt2_block_srgb[] = + { + 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x86,0x31,0x04,0x21,0x11,0x11,0x11,0x11, + }; + static const uint8_t dxt4_block_srgb[] = + { + 0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x86,0x31,0x04,0x21,0x11,0x11,0x11,0x11, + }; + static const uint8_t dxt_srgb_in_expected[] = + { + 0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88,0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88, + 0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88,0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88, + 0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88,0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88, + 0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88,0x0b,0x0b,0x0b,0x88,0x1b,0x1a,0x1b,0x88, + }; + static const uint8_t dxt_srgb_out_expected[] = + { + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + 0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88,0x21,0x20,0x21,0x88,0x31,0x31,0x31,0x88, + }; static const uint32_t test_compress_pixels[] = { 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, 0xffffffff, 0x00ffffff, @@ -1269,9 +1278,10 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) { D3DFMT_DXT4, D3DFMT_DXT5, dxt5_block, "DXT4 / DXT5" }, }; static const RECT src_rect = { 0, 0, 4, 4 }; - IDirect3DSurface9 *decomp_surf; + IDirect3DSurface9 *decomp_surf, *comp_surf; D3DLOCKED_RECT lock_rect; uint32_t i, x, y; + uint8_t tmp[16]; HRESULT hr; hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &decomp_surf, NULL); @@ -1374,6 +1384,71 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) IDirect3DTexture9_Release(tex); winetest_pop_context(); } + + /* + * DXT2/DXT4 combined with SRGB filter flags. Premultiplied alpha is + * undone prior to undoing the SRGB conversion, and vice versa. + */ + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, dxt2_block_srgb, D3DFMT_DXT2, 16, NULL, &src_rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_in_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 1); + IDirect3DSurface9_UnlockRect(decomp_surf); + + /* DXT4, SRGB in. */ + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, dxt4_block_srgb, D3DFMT_DXT4, 16, NULL, &src_rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_in_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 1); + IDirect3DSurface9_UnlockRect(decomp_surf); + + /* + * DXT2, SRGB out. SRGB conversion is done first, and then premultiplied + * by alpha. + */ + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_DXT2, D3DPOOL_SCRATCH, &comp_surf, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(comp_surf, NULL, NULL, dxt_srgb_in_expected, D3DFMT_A8R8G8B8, 16, NULL, &src_rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(comp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + memcpy(tmp, lock_rect.pBits, 16); + IDirect3DSurface9_UnlockRect(comp_surf); + IDirect3DSurface9_Release(comp_surf); + + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, tmp, D3DFMT_DXT3, 16, NULL, &src_rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_out_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 0); + IDirect3DSurface9_UnlockRect(decomp_surf); + + /* DXT4, SRGB out. */ + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 4, D3DFMT_DXT4, D3DPOOL_SCRATCH, &comp_surf, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(comp_surf, NULL, NULL, dxt_srgb_in_expected, D3DFMT_A8R8G8B8, 16, NULL, &src_rect, + D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(comp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + memcpy(tmp, lock_rect.pBits, 16); + IDirect3DSurface9_UnlockRect(comp_surf); + IDirect3DSurface9_Release(comp_surf); + + hr = D3DXLoadSurfaceFromMemory(decomp_surf, NULL, NULL, tmp, D3DFMT_DXT5, 16, NULL, &src_rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_out_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 0); + IDirect3DSurface9_UnlockRect(decomp_surf); + IDirect3DSurface9_Release(decomp_surf); } @@ -5281,6 +5356,139 @@ static void test_image_filters(void) DestroyWindow(hwnd); } +static void test_srgb_filter_flags(void) +{ + static const float test_float4_srgb_in[] = + { + 0.0900000f, 0.1000000f, 0.2000000f, 1.0f, + 0.3000000f, 0.4000000f, 0.5000000f, 2.0f, + 0.6000000f, 0.7000000f, 0.8000000f, 3.0f, + 0.9000000f, 1.5000000f, -1.0000000f, 4.0f, + }; + static const float test_float4_srgb_in_expected[] = + { + 5.00732847e-003, 6.32313965e-003, 2.89932229e-002, 1.00000000e+000, + 7.07411841e-002, 1.33209527e-001, 2.17638373e-001, 2.00000000e+000, + 3.25037479e-001, 4.56263810e-001, 6.12065971e-001, 3.00000000e+000, + 7.93110251e-001, 1.54501167e-009, 1.00000000e+000, 4.00000000e+000, + }; + static const float test_float4_srgb_in_expected_32[] = + { + 5.00732800e-003, 6.32313825e-003, 2.89932154e-002, 1.00000000e+000, + 7.07411841e-002, 1.33209497e-001, 2.17638358e-001, 2.00000000e+000, + 3.25037479e-001, 4.56263781e-001, 6.12065852e-001, 3.00000000e+000, + /* + * On 32-bit d3dx9, an input value of 1.5f being converted from SRGB + * to linear produces quite a few different values depending on the + * SDK version. Presumably it's reading beyond the end of a LUT. + */ +#if D3DX_SDK_VERSION <= 36 + 7.93110192e-001, 7.85714269e-001, 1.00000000e+000, 4.00000000e+000, +#else + 7.93110192e-001, 4.68750000e-001, 1.00000000e+000, 4.00000000e+000, +#endif + }; + static const float test_float4_srgb_out[] = + { + 0.0010000f, 0.1000000f, 0.2000000f, 1.0f, + 0.3000000f, 0.4000000f, 0.5000000f, 2.0f, + 0.6000000f, 0.7000000f, 0.8000000f, 3.0f, + 0.9000000f, 1.5000000f, -1.0000000f, 4.0f, + }; + static const float test_float4_srgb_out_expected[] = + { + 4.32867892e-002, 3.51118684e-001, 4.81156141e-001, 1.00000000e+000, + 5.78532457e-001, 6.59353077e-001, 7.29739845e-001, 2.00000000e+000, + 7.92792618e-001, 8.50334764e-001, 9.03545380e-001, 3.00000000e+000, + 9.53237534e-001, 1.86132386e-001, -NAN, 4.00000000e+000, + }; + static const float test_float4_srgb_out_expected_32[] = + { + 4.32868116e-002, 3.51118803e-001, 4.81156349e-001, 1.00000000e+000, + 5.78532696e-001, 6.59353256e-001, 7.29739845e-001, 2.00000000e+000, + 7.92793036e-001, 8.50335181e-001, 9.03545737e-001, 3.00000000e+000, + 9.53237772e-001, 1.86132386e-001, -INFINITY, 4.00000000e+000, + + }; + static const uint32_t test_a8r8g8b8[] = { 0x00102030, 0x40506070, 0x8090a0b0, 0xc0d0e0ff }; + static const uint32_t test_a8r8g8b8_srgb_in_expected[] = { 0x00010306, 0x40141e2a, 0x80495b71, 0xc0a3c0ff }; + static const uint32_t test_a8r8g8b8_srgb_out_expected[] = { 0x00486377, 0x4097a4af, 0x80c5ced7, 0xc0e8f0ff }; + static const struct + { + const RECT src_rect; + const void *src_data; + D3DFORMAT format; + DWORD flags; + + const void *expected_dst_data; + const void *expected_dst_data_32; + BOOL todo; + } tests[] = + { + /* Both IN and OUT flags, nothing changes. */ + { + { 0, 0, 2, 2 }, test_a8r8g8b8, D3DFMT_A8R8G8B8, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN | D3DX_FILTER_SRGB_OUT, + test_a8r8g8b8 + }, + { + { 0, 0, 2, 2 }, test_a8r8g8b8, D3DFMT_A8R8G8B8, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, + test_a8r8g8b8_srgb_in_expected, .todo = TRUE + }, + { + { 0, 0, 2, 2 }, test_a8r8g8b8, D3DFMT_A8R8G8B8, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, + test_a8r8g8b8_srgb_out_expected, .todo = TRUE + }, + { + { 0, 0, 2, 2 }, test_float4_srgb_in, D3DFMT_A32B32G32R32F, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, + test_float4_srgb_in_expected, test_float4_srgb_in_expected_32, .todo = TRUE + }, + { + { 0, 0, 2, 2 }, test_float4_srgb_out, D3DFMT_A32B32G32R32F, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, + test_float4_srgb_out_expected, test_float4_srgb_out_expected_32, .todo = TRUE + }, + }; + const BOOL is_32 = (sizeof(void *) == 4); + IDirect3DDevice9 *device; + D3DLOCKED_RECT lock_rect; + IDirect3DSurface9 *surf; + unsigned int i; + HRESULT hr; + HWND hwnd; + + if (!(device = create_device(&hwnd))) + return; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + const unsigned int fmt_bpp = get_bpp_for_d3dformat(tests[i].format); + unsigned int width = tests[i].src_rect.right - tests[i].src_rect.left; + unsigned int height = tests[i].src_rect.bottom- tests[i].src_rect.top; + unsigned int src_pitch = fmt_bpp * width; + const uint8_t *expected_dst; + + winetest_push_context("Test %u (%s)", i, debug_d3dx_filter(tests[i].flags)); + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, tests[i].format, D3DPOOL_SCRATCH, + &surf, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromMemory(surf, NULL, NULL, tests[i].src_data, tests[i].format, + src_pitch, NULL, &tests[i].src_rect, tests[i].flags, 0); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + + expected_dst = (is_32 && tests[i].expected_dst_data_32) ? tests[i].expected_dst_data_32 : tests[i].expected_dst_data; + IDirect3DSurface9_LockRect(surf, &lock_rect, NULL, D3DLOCK_READONLY); + todo_wine_if(tests[i].todo) check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, expected_dst, width, + height, 1, tests[i].format, 0); + IDirect3DSurface9_UnlockRect(surf); + + winetest_pop_context(); + } + + check_release((IUnknown *)surf, 0); + winetest_pop_context(); +} + START_TEST(surface) { HWND wnd; @@ -5324,4 +5532,5 @@ START_TEST(surface) test_color_key(); test_image_filters(); + test_srgb_filter_flags(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/d3dx10_43/tests/d3dx10.c | 234 +++++++++++++++++++++++++++++ dlls/d3dx11_42/tests/Makefile.in | 1 + dlls/d3dx11_43/tests/Makefile.in | 1 + dlls/d3dx11_43/tests/d3dx11.c | 244 +++++++++++++++++++++++++++++++ 4 files changed, 480 insertions(+) diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index c35351a2301..26d5d65c200 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -25,6 +25,24 @@ #include <stdint.h> #include <assert.h> +static const char *debug_d3dx10_filter(uint32_t filter_flags) +{ + static const char *filter_types[] = { "", "D3DX10_FILTER_NONE", "D3DX10_FILTER_POINT", "D3DX10_FILTER_LINEAR", + "D3DX10_FILTER_TRIANGLE", "D3DX10_FILTER_BOX", "", "" }; + static const char *srgb_types[] = { "", "|D3DX10_FILTER_SRGB_IN", "|D3DX10_FILTER_SRGB_OUT", "|D3DX10_FILTER_SRGB" }; + static const char *dither_types[] = { "", "|D3DX10_FILTER_DITHER", "|D3DX10_FILTER_DITHER_DIFFUSION", ""}; + static const char *mirror_types[] = { "", "|D3DX10_FILTER_MIRROR_U", "|D3DX10_FILTER_MIRROR_V", + "|D3DX10_FILTER_MIRROR_U|D3DX10_FILTER_MIRROR_V", "|D3DX10_FILTER_MIRROR_W", + "|D3DX10_FILTER_MIRROR_U|D3DX10_FILTER_MIRROR_W", + "|D3DX10_FILTER_MIRROR_V|D3DX10_FILTER_MIRROR_W", "|D3DX10_FILTER_MIRROR", }; + const uint8_t mirror = ((filter_flags >> 16) & 0x7); + const uint8_t dither = ((filter_flags >> 19) & 0x3); + const uint8_t srgb = ((filter_flags >> 21) & 0x3); + const uint8_t filter = (filter_flags & 0x7); + + return wine_dbg_sprintf("%s%s%s%s", filter_types[filter], mirror_types[mirror], dither_types[dither], srgb_types[srgb]); +} + static const D3DX10_IMAGE_LOAD_INFO d3dx10_default_load_info = { D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, D3DX10_DEFAULT, @@ -1986,6 +2004,24 @@ static BOOL is_block_compressed(DXGI_FORMAT format) return FALSE; } +static BOOL is_srgb_format(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return TRUE; + + default: + return FALSE; + } +} + static unsigned int get_bpp_from_format(DXGI_FORMAT format) { switch (format) @@ -2704,15 +2740,28 @@ static inline BOOL check_readback_pixel_4bpp_rgba(const void *got, const void *e && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); } +static inline BOOL check_readback_pixel_float4_rgba(const void *got, const void *expected, uint32_t max_diff) +{ + const float *a = got; + const float *b = expected; + + return (compare_float(a[0], b[0], max_diff) && compare_float(a[1], b[1], max_diff) + && compare_float(a[2], b[2], max_diff) && compare_float(a[3], b[3], max_diff)); +} + typedef BOOL (*check_readback_pixel_func)(const void *, const void *, uint32_t); static inline check_readback_pixel_func get_readback_pixel_func_for_dxgi_format(DXGI_FORMAT format) { switch (format) { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM: return check_readback_pixel_4bpp_rgba; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return check_readback_pixel_float4_rgba; + default: assert(0 && "Need to add format to get_readback_pixel_func_for_dxgi_format()."); return 0; @@ -5727,6 +5776,190 @@ static void test_dxt_formats(void) ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); } +static void test_srgb_filter_flags(void) +{ + static const float test_float4_srgb_in[] = + { + 0.09f, 0.1f, 0.2f, 1.0f, + 0.30f, 0.4f, 0.5f, 2.0f, + 0.60f, 0.7f, 0.8f, 3.0f, + 0.90f, 1.5f, -1.0f, 4.0f, + }; + static const float test_float4_srgb_in_expected[] = + { + 5.00732847e-003, 6.27983455e-003, 2.89932229e-002, 1.00000000e+000, + 7.07391128e-002, 1.33206353e-001, 2.17635408e-001, 2.00000000e+000, + 3.25037479e-001, 4.56263810e-001, 6.12064898e-001, 3.00000000e+000, + 7.93109715e-001, -2.24207754e-044, 1.00000000e+000, 4.00000000e+000, + }; + static const float test_float4_srgb_in_expected_32[] = + { + 5.00732893e-003, 6.27983361e-003, 2.89932191e-002, 1.00000000e+000, + 7.07391202e-002, 1.33206338e-001, 2.17635408e-001, 2.00000000e+000, + 3.25037509e-001, 4.56263840e-001, 6.12064838e-001, 3.00000000e+000, + /* + * On 32-bit d3dx10+, an input value of 1.5f being converted from SRGB + * to linear produces quite a few different values depending on the + * SDK version. Presumably it's reading beyond the end of a LUT, + * values above ~106.0f will cause a crash on all versions and + * bitnesses. + */ +#if D3DX10_SDK_VERSION < 35 + 7.93109715e-001, 3.48807693e-001, 1.00000000e+000, 4.00000000e+000 +#elif D3DX10_SDK_VERSION < 37 + 7.93109715e-001, 3.56686294e-001, 1.00000000e+000, 4.00000000e+000 +#elif D3DX10_SDK_VERSION < 40 + 7.93109715e-001, 3.64580810e-001, 1.00000000e+000, 4.00000000e+000 +#else + 7.93109715e-001, 3.33099246e-001, 1.00000000e+000, 4.00000000e+000 +#endif + }; + static const float test_float4_srgb_out[] = + { + 0.001f, 0.1f, 0.2f, 1.0f, + 0.300f, 0.4f, 0.5f, 2.0f, + 0.600f, 0.7f, 0.8f, 3.0f, + 0.900f, 1.5f, 1.0f, 4.0f, + }; + /* 32-bit can handle a -1.0f input, 64-bit will crash. */ + static const float test_float4_srgb_out_32[] = + { + 0.001f, 0.1f, 0.2f, 1.0f, + 0.300f, 0.4f, 0.5f, 2.0f, + 0.600f, 0.7f, 0.8f, 3.0f, + 0.900f, 1.5f, -1.0f, 4.0f, + }; + static const float test_float4_srgb_out_expected[] = + { + 4.32867892e-002, 3.51118684e-001, 4.81157422e-001, 1.00000000e+000, + 5.78532457e-001, 6.59353793e-001, 7.29740620e-001, 2.00000000e+000, + 7.92793036e-001, 8.50335538e-001, 9.03545380e-001, 3.00000000e+000, + 9.53237593e-001, 1.86132386e-001, 1.00000000e+000, 4.00000000e+000, + }; + static const float test_float4_srgb_out_expected_32[] = + { + 4.32868190e-002, 3.51118833e-001, 4.81157631e-001, 1.00000000e+000, + 5.78532815e-001, 6.59354091e-001, 7.29740679e-001, 2.00000000e+000, + 7.92793512e-001, 8.50336075e-001, 9.03545797e-001, 3.00000000e+000, + 9.53237832e-001, 1.86132386e-001, -INFINITY, 4.00000000e+000, + }; + static const uint32_t test_a8r8g8b8[] = { 0x00102030, 0x40506070, 0x8090a0b0, 0xc0d0e0ff }; + static const uint32_t test_a8r8g8b8_srgb_in_expected[] = { 0x00010306, 0x40141e2a, 0x80495b71, 0xc0a3c0ff }; + static const uint32_t test_a8r8g8b8_srgb_out_expected[] = { 0x00486377, 0x4097a4af, 0x80c5ced7, 0xc0e8f0ff }; + static const struct + { + unsigned int width; + unsigned int height; + const void *src_data; + const void *src_data_32; + DXGI_FORMAT src_format; + DWORD flags; + + const void *expected_dst_data; + const void *expected_dst_data_32; + DXGI_FORMAT dst_format; + BOOL todo; + } tests[] = + { + /* Both IN and OUT flags, nothing changes. */ + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_FILTER_NONE | D3DX10_FILTER_SRGB, + test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM + }, + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_FILTER_NONE | D3DX10_FILTER_SRGB_IN, + test_a8r8g8b8_srgb_in_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + }, + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3DX10_FILTER_NONE, + test_a8r8g8b8_srgb_in_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + }, + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_FILTER_NONE | D3DX10_FILTER_SRGB_OUT, + test_a8r8g8b8_srgb_out_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + }, + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_FILTER_NONE, + test_a8r8g8b8_srgb_out_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, .todo = TRUE + }, + /* 5. */ + { + 2, 2, test_float4_srgb_in, NULL, DXGI_FORMAT_R32G32B32A32_FLOAT, D3DX10_FILTER_NONE | D3DX10_FILTER_SRGB_IN, + test_float4_srgb_in_expected, test_float4_srgb_in_expected_32, DXGI_FORMAT_R32G32B32A32_FLOAT, .todo = TRUE + }, + { + 2, 2, test_float4_srgb_out, test_float4_srgb_out_32, DXGI_FORMAT_R32G32B32A32_FLOAT, + D3DX10_FILTER_NONE | D3DX10_FILTER_SRGB_OUT, test_float4_srgb_out_expected, test_float4_srgb_out_expected_32, + DXGI_FORMAT_R32G32B32A32_FLOAT, .todo = TRUE + }, + }; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + BYTE data[8192]; + } dds; + const BOOL is_32 = (sizeof(void *) == 4); + D3DX10_IMAGE_LOAD_INFO load_info; + struct resource_readback rb; + ID3D10Resource *resource; + ID3D10Device *device; + unsigned int i; + HRESULT hr; + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + CoInitialize(NULL); + + dds.magic = MAKEFOURCC('D','D','S',' '); + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + const unsigned int fmt_bpp = (get_bpp_from_format(tests[i].src_format) + 7) / 8; + unsigned int src_pitch = fmt_bpp * tests[i].width; + const uint8_t *src_data, *expected_dst; + + winetest_push_context("Test %u (%s)", i, debug_d3dx10_filter(tests[i].flags)); + + load_info = d3dx10_default_load_info; + load_info.Height = tests[i].height; + load_info.Width = tests[i].width; + load_info.Filter = tests[i].flags; + load_info.Format = tests[i].dst_format; + load_info.MipLevels = 1; + + expected_dst = (is_32 && tests[i].expected_dst_data_32) ? tests[i].expected_dst_data_32 : tests[i].expected_dst_data; + src_data = (is_32 && tests[i].src_data_32) ? tests[i].src_data_32 : tests[i].src_data; + + /* Height + 1 to make sure filter flags aren't ignored. */ + set_dxt10_dds_header(&dds.header, 0, tests[i].width, tests[i].height + 1, 0, 1, src_pitch, 0, 0); + set_dds_header_dxt10(&dds.dxt10, tests[i].src_format, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0); + memcpy(dds.data, src_data, src_pitch * tests[i].height); + + hr = D3DX10CreateTextureFromMemory(device, &dds, sizeof(dds), &load_info, NULL, &resource, NULL); + todo_wine_if(is_srgb_format(tests[i].src_format) || is_srgb_format(tests[i].dst_format)) + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + get_resource_readback(resource, 0, &rb); + todo_wine_if(tests[i].todo) check_test_readback(&rb, expected_dst, tests[i].width, tests[i].height, 1, + tests[i].dst_format, 0); + release_resource_readback(&rb); + ID3D10Resource_Release(resource); + } + + winetest_pop_context(); + } + + CoUninitialize(); + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); +} + #define check_rect(rect, left, top, right, bottom) _check_rect(__LINE__, rect, left, top, right, bottom) static inline void _check_rect(unsigned int line, const RECT *rect, int left, int top, int right, int bottom) { @@ -7217,4 +7450,5 @@ START_TEST(d3dx10) test_dxt10_dds_header_image_info(); test_image_filters(); test_dxt_formats(); + test_srgb_filter_flags(); } diff --git a/dlls/d3dx11_42/tests/Makefile.in b/dlls/d3dx11_42/tests/Makefile.in index 7eae4f26e0d..bb2d006916a 100644 --- a/dlls/d3dx11_42/tests/Makefile.in +++ b/dlls/d3dx11_42/tests/Makefile.in @@ -1,3 +1,4 @@ +EXTRADEFS = -DD3DX11_SDK_VERSION=42 TESTDLL = d3dx11_42.dll IMPORTS = d3dx11_42 ole32 PARENTSRC = ../../d3dx11_43/tests diff --git a/dlls/d3dx11_43/tests/Makefile.in b/dlls/d3dx11_43/tests/Makefile.in index fc9007fc878..6c54e4d8ccd 100644 --- a/dlls/d3dx11_43/tests/Makefile.in +++ b/dlls/d3dx11_43/tests/Makefile.in @@ -1,3 +1,4 @@ +EXTRADEFS = -DD3DX11_SDK_VERSION=43 TESTDLL = d3dx11_43.dll IMPORTS = d3dx11 ole32 diff --git a/dlls/d3dx11_43/tests/d3dx11.c b/dlls/d3dx11_43/tests/d3dx11.c index 5bdfb0de976..97f963ad59e 100644 --- a/dlls/d3dx11_43/tests/d3dx11.c +++ b/dlls/d3dx11_43/tests/d3dx11.c @@ -24,6 +24,25 @@ #include "wine/test.h" #include <stdint.h> #include <assert.h> +#include <math.h> + +static const char *debug_d3dx11_filter(uint32_t filter_flags) +{ + static const char *filter_types[] = { "", "D3DX11_FILTER_NONE", "D3DX11_FILTER_POINT", "D3DX11_FILTER_LINEAR", + "D3DX11_FILTER_TRIANGLE", "D3DX11_FILTER_BOX", "", "" }; + static const char *srgb_types[] = { "", "|D3DX11_FILTER_SRGB_IN", "|D3DX11_FILTER_SRGB_OUT", "|D3DX11_FILTER_SRGB" }; + static const char *dither_types[] = { "", "|D3DX11_FILTER_DITHER", "|D3DX11_FILTER_DITHER_DIFFUSION", ""}; + static const char *mirror_types[] = { "", "|D3DX11_FILTER_MIRROR_U", "|D3DX11_FILTER_MIRROR_V", + "|D3DX11_FILTER_MIRROR_U|D3DX11_FILTER_MIRROR_V", "|D3DX11_FILTER_MIRROR_W", + "|D3DX11_FILTER_MIRROR_U|D3DX11_FILTER_MIRROR_W", + "|D3DX11_FILTER_MIRROR_V|D3DX11_FILTER_MIRROR_W", "|D3DX11_FILTER_MIRROR", }; + const uint8_t mirror = ((filter_flags >> 16) & 0x7); + const uint8_t dither = ((filter_flags >> 19) & 0x3); + const uint8_t srgb = ((filter_flags >> 21) & 0x3); + const uint8_t filter = (filter_flags & 0x7); + + return wine_dbg_sprintf("%s%s%s%s", filter_types[filter], mirror_types[mirror], dither_types[dither], srgb_types[srgb]); +} static const D3DX11_IMAGE_LOAD_INFO d3dx11_default_load_info = { @@ -1957,6 +1976,24 @@ static BOOL is_block_compressed(DXGI_FORMAT format) return FALSE; } +static BOOL is_srgb_format(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return TRUE; + + default: + return FALSE; + } +} + static unsigned int get_bpp_from_format(DXGI_FORMAT format) { switch (format) @@ -2187,6 +2224,19 @@ static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) return diff <= max_diff; } +static BOOL compare_float(float f, float g, unsigned int ulps) +{ + int x = *(int *)&f; + int y = *(int *)&g; + + if (x < 0) + x = INT_MIN - x; + if (y < 0) + y = INT_MIN - y; + + return compare_uint(x, y, ulps); +} + static char *get_str_a(const WCHAR *wstr) { static char buffer[MAX_PATH]; @@ -2649,15 +2699,28 @@ static inline BOOL check_readback_pixel_4bpp_rgba(const void *got, const void *e && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); } +static inline BOOL check_readback_pixel_float4_rgba(const void *got, const void *expected, uint32_t max_diff) +{ + const float *a = got; + const float *b = expected; + + return (compare_float(a[0], b[0], max_diff) && compare_float(a[1], b[1], max_diff) + && compare_float(a[2], b[2], max_diff) && compare_float(a[3], b[3], max_diff)); +} + typedef BOOL (*check_readback_pixel_func)(const void *, const void *, uint32_t); static inline check_readback_pixel_func get_readback_pixel_func_for_dxgi_format(DXGI_FORMAT format) { switch (format) { + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM: return check_readback_pixel_4bpp_rgba; + case DXGI_FORMAT_R32G32B32A32_FLOAT: + return check_readback_pixel_float4_rgba; + default: assert(0 && "Need to add format to get_readback_pixel_func_for_dxgi_format()."); return 0; @@ -4545,6 +4608,186 @@ static void test_dxt_formats(void) ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); } +static void test_srgb_filter_flags(void) +{ + static const float test_float4_srgb_in[] = + { + 0.09f, 0.1f, 0.2f, 1.0f, + 0.30f, 0.4f, 0.5f, 2.0f, + 0.60f, 0.7f, 0.8f, 3.0f, + 0.90f, 1.5f, -1.0f, 4.0f, + }; + static const float test_float4_srgb_in_expected[] = + { + 5.00732847e-003, 6.27983455e-003, 2.89932229e-002, 1.00000000e+000, + 7.07391128e-002, 1.33206353e-001, 2.17635408e-001, 2.00000000e+000, + 3.25037479e-001, 4.56263810e-001, 6.12064898e-001, 3.00000000e+000, + 7.93109715e-001, 0.00000000e-000, 1.00000000e+000, 4.00000000e+000, + }; + static const float test_float4_srgb_in_expected_32[] = + { + 5.00732893e-003, 6.27983361e-003, 2.89932191e-002, 1.00000000e+000, + 7.07391202e-002, 1.33206338e-001, 2.17635408e-001, 2.00000000e+000, + 3.25037509e-001, 4.56263840e-001, 6.12064838e-001, 3.00000000e+000, + /* + * On 32-bit d3dx10+, an input value of 1.5f being converted from SRGB + * to linear produces quite a few different values depending on the + * SDK version. Presumably it's reading beyond the end of a LUT, + * values above ~106.0f will cause a crash on all versions and + * bitnesses. + */ +#if D3DX11_SDK_VERSION == 42 + 7.93109715e-001, 6.54184470e+027, 1.00000000e+000, 4.00000000e+000 +#else + 7.93109715e-001, 1.12405043e+032, 1.00000000e+000, 4.00000000e+000 +#endif + }; + static const float test_float4_srgb_out[] = + { + 0.001f, 0.1f, 0.2f, 1.0f, + 0.300f, 0.4f, 0.5f, 2.0f, + 0.600f, 0.7f, 0.8f, 3.0f, + 0.900f, 1.5f, 1.0f, 4.0f, + }; + /* 32-bit can handle a -1.0f input, 64-bit will crash. */ + static const float test_float4_srgb_out_32[] = + { + 0.001f, 0.1f, 0.2f, 1.0f, + 0.300f, 0.4f, 0.5f, 2.0f, + 0.600f, 0.7f, 0.8f, 3.0f, + 0.900f, 1.5f, -1.0f, 4.0f, + }; + static const float test_float4_srgb_out_expected[] = + { + 4.32867892e-002, 3.51118684e-001, 4.81157422e-001, 1.00000000e+000, + 5.78532457e-001, 6.59353793e-001, 7.29740620e-001, 2.00000000e+000, + 7.92793036e-001, 8.50335538e-001, 9.03545380e-001, 3.00000000e+000, + 9.53237593e-001, 1.86132386e-001, 1.00000000e+000, 4.00000000e+000, + }; + static const float test_float4_srgb_out_expected_32[] = + { + 4.32868190e-002, 3.51118833e-001, 4.81157631e-001, 1.00000000e+000, + 5.78532815e-001, 6.59354091e-001, 7.29740679e-001, 2.00000000e+000, + 7.92793512e-001, 8.50336075e-001, 9.03545797e-001, 3.00000000e+000, + 9.53237832e-001, 1.86132386e-001, -INFINITY, 4.00000000e+000, + }; + static const uint32_t test_a8r8g8b8[] = { 0x00102030, 0x40506070, 0x8090a0b0, 0xc0d0e0ff }; + static const uint32_t test_a8r8g8b8_srgb_in_expected[] = { 0x00010306, 0x40141e2a, 0x80495b71, 0xc0a3c0ff }; + static const uint32_t test_a8r8g8b8_srgb_out_expected[] = { 0x00486377, 0x4097a4af, 0x80c5ced7, 0xc0e8f0ff }; + static const struct + { + unsigned int width; + unsigned int height; + const void *src_data; + const void *src_data_32; + DXGI_FORMAT src_format; + DWORD flags; + + const void *expected_dst_data; + const void *expected_dst_data_32; + DXGI_FORMAT dst_format; + BOOL todo; + } tests[] = + { + /* Both IN and OUT flags, nothing changes. */ + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_FILTER_NONE | D3DX11_FILTER_SRGB, + test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM + }, + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_FILTER_NONE | D3DX11_FILTER_SRGB_IN, + test_a8r8g8b8_srgb_in_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + }, + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3DX11_FILTER_NONE, + test_a8r8g8b8_srgb_in_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + }, + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_FILTER_NONE | D3DX11_FILTER_SRGB_OUT, + test_a8r8g8b8_srgb_out_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + }, + { + 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_FILTER_NONE, + test_a8r8g8b8_srgb_out_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, .todo = TRUE + }, + /* 5. */ + { + 2, 2, test_float4_srgb_in, NULL, DXGI_FORMAT_R32G32B32A32_FLOAT, D3DX11_FILTER_NONE | D3DX11_FILTER_SRGB_IN, + test_float4_srgb_in_expected, test_float4_srgb_in_expected_32, DXGI_FORMAT_R32G32B32A32_FLOAT, .todo = TRUE + }, + { + 2, 2, test_float4_srgb_out, test_float4_srgb_out_32, DXGI_FORMAT_R32G32B32A32_FLOAT, + D3DX11_FILTER_NONE | D3DX11_FILTER_SRGB_OUT, test_float4_srgb_out_expected, test_float4_srgb_out_expected_32, + DXGI_FORMAT_R32G32B32A32_FLOAT, .todo = TRUE + }, + }; + struct + { + DWORD magic; + struct dds_header header; + struct dds_header_dxt10 dxt10; + BYTE data[8192]; + } dds; + const BOOL is_32 = (sizeof(void *) == 4); + D3DX11_IMAGE_LOAD_INFO load_info; + struct resource_readback rb; + ID3D11Resource *resource; + ID3D11Device *device; + unsigned int i; + HRESULT hr; + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + CoInitialize(NULL); + + dds.magic = MAKEFOURCC('D','D','S',' '); + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + const unsigned int fmt_bpp = (get_bpp_from_format(tests[i].src_format) + 7) / 8; + unsigned int src_pitch = fmt_bpp * tests[i].width; + const uint8_t *src_data, *expected_dst; + + winetest_push_context("Test %u (%s)", i, debug_d3dx11_filter(tests[i].flags)); + + load_info = d3dx11_default_load_info; + load_info.Height = tests[i].height; + load_info.Width = tests[i].width; + load_info.Filter = tests[i].flags; + load_info.Format = tests[i].dst_format; + load_info.MipLevels = 1; + + expected_dst = (is_32 && tests[i].expected_dst_data_32) ? tests[i].expected_dst_data_32 : tests[i].expected_dst_data; + src_data = (is_32 && tests[i].src_data_32) ? tests[i].src_data_32 : tests[i].src_data; + + /* Height + 1 to make sure filter flags aren't ignored. */ + set_dxt10_dds_header(&dds.header, 0, tests[i].width, tests[i].height + 1, 0, 1, src_pitch, 0, 0); + set_dds_header_dxt10(&dds.dxt10, tests[i].src_format, D3D10_RESOURCE_DIMENSION_TEXTURE2D, 0, 1, 0); + memcpy(dds.data, src_data, src_pitch * tests[i].height); + + hr = D3DX11CreateTextureFromMemory(device, &dds, sizeof(dds), &load_info, NULL, &resource, NULL); + todo_wine_if(is_srgb_format(tests[i].src_format) || is_srgb_format(tests[i].dst_format)) + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + { + get_resource_readback(resource, 0, &rb); + todo_wine_if(tests[i].todo) check_test_readback(&rb, expected_dst, tests[i].width, tests[i].height, 1, + tests[i].dst_format, 0); + release_resource_readback(&rb); + ID3D11Resource_Release(resource); + } + + winetest_pop_context(); + } + + CoUninitialize(); + ok(!ID3D11Device_Release(device), "Unexpected refcount.\n"); +} + static BOOL create_directory(const WCHAR *dir) { WCHAR path[MAX_PATH]; @@ -4718,4 +4961,5 @@ START_TEST(d3dx11) test_dxt10_dds_header_image_info(); test_image_filters(); test_dxt_formats(); + test_srgb_filter_flags(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/d3dx10_43/tests/d3dx10.c | 4 ++-- dlls/d3dx11_43/tests/d3dx11.c | 4 ++-- dlls/d3dx9_36/d3dx_helpers.c | 43 +++++++++++++++++++++++++++++++++++ dlls/d3dx9_36/d3dx_helpers.h | 2 ++ dlls/d3dx9_36/tests/surface.c | 12 +++++----- 5 files changed, 55 insertions(+), 10 deletions(-) diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index 26d5d65c200..252a64cddd2 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -5868,7 +5868,7 @@ static void test_srgb_filter_flags(void) }, { 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_FILTER_NONE | D3DX10_FILTER_SRGB_IN, - test_a8r8g8b8_srgb_in_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + test_a8r8g8b8_srgb_in_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM }, { 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3DX10_FILTER_NONE, @@ -5876,7 +5876,7 @@ static void test_srgb_filter_flags(void) }, { 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_FILTER_NONE | D3DX10_FILTER_SRGB_OUT, - test_a8r8g8b8_srgb_out_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + test_a8r8g8b8_srgb_out_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM }, { 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX10_FILTER_NONE, diff --git a/dlls/d3dx11_43/tests/d3dx11.c b/dlls/d3dx11_43/tests/d3dx11.c index 97f963ad59e..a56f415dced 100644 --- a/dlls/d3dx11_43/tests/d3dx11.c +++ b/dlls/d3dx11_43/tests/d3dx11.c @@ -4696,7 +4696,7 @@ static void test_srgb_filter_flags(void) }, { 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_FILTER_NONE | D3DX11_FILTER_SRGB_IN, - test_a8r8g8b8_srgb_in_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + test_a8r8g8b8_srgb_in_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM }, { 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, D3DX11_FILTER_NONE, @@ -4704,7 +4704,7 @@ static void test_srgb_filter_flags(void) }, { 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_FILTER_NONE | D3DX11_FILTER_SRGB_OUT, - test_a8r8g8b8_srgb_out_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, .todo = TRUE + test_a8r8g8b8_srgb_out_expected, NULL, DXGI_FORMAT_R8G8B8A8_UNORM }, { 2, 2, test_a8r8g8b8, NULL, DXGI_FORMAT_R8G8B8A8_UNORM, D3DX11_FILTER_NONE, diff --git a/dlls/d3dx9_36/d3dx_helpers.c b/dlls/d3dx9_36/d3dx_helpers.c index 573a550b5b0..bff7798006d 100644 --- a/dlls/d3dx9_36/d3dx_helpers.c +++ b/dlls/d3dx9_36/d3dx_helpers.c @@ -73,6 +73,8 @@ static uint32_t d3dx_conv_flags_from_filter(uint32_t filter) if ((filter & D3DX_FILTER_PMA) && ((filter & D3DX_FILTER_PMA) != D3DX_FILTER_PMA)) conv_flags |= (filter & D3DX_FILTER_PMA_IN) ? CONV_FLAG_PM_ALPHA_IN : CONV_FLAG_PM_ALPHA_OUT; + if ((filter & D3DX_FILTER_SRGB) && ((filter & D3DX_FILTER_SRGB) != D3DX_FILTER_SRGB)) + conv_flags |= (filter & D3DX_FILTER_SRGB_IN) ? CONV_FLAG_SRGB_IN : CONV_FLAG_SRGB_OUT; return conv_flags; } @@ -2468,6 +2470,33 @@ static void straight_alpha_from_premultiplied_alpha(struct vec4 *vec) vec->z = (vec->w == 0.0f) ? 0.0f : vec->z / vec->w; } +/* + * All versions of d3dx (9-11) treat sRGB as "simplified sRGB." Rather + * than using the sRGB transfer function defined in IEC 61966-2-1:1999, they + * use a plain gamma 2.2 transfer function which ignores the special handling + * of the linear section near 0. + * + * Native d3dx also seems to use a lookup table to do this conversion, which + * matches the output of earlier versions of DirectXTex (prior to commit + * 98699f90f9177cee0f1be5ff441d0c42c32d9b69). If it's determined later on that + * an application needs to more closely match native's conversion values for + * formats larger than 8bpc this should be considered, but for now these + * functions result in matching native's output for 8bpc formats. + */ +static void srgb_from_linear_rgb(struct vec4 *vec) +{ + vec->x = powf(vec->x, 1.0f / 2.2f); + vec->y = powf(vec->y, 1.0f / 2.2f); + vec->z = powf(vec->z, 1.0f / 2.2f); +} + +static void linear_rgb_from_srgb(struct vec4 *vec) +{ + vec->x = powf(vec->x, 2.2f); + vec->y = powf(vec->y, 2.2f); + vec->z = powf(vec->z, 2.2f); +} + 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, const struct d3dx_color_key *color_key, @@ -2509,6 +2538,8 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format format_to_d3dx_color(src_fmt, src_ptr, palette, &color); if (conv_flags & CONV_FLAG_PM_ALPHA_IN) straight_alpha_from_premultiplied_alpha(&color.value); + if (conv_flags & CONV_FLAG_SRGB_IN) + linear_rgb_from_srgb(&color.value); tmp = color; if (color_key) @@ -2528,6 +2559,8 @@ static void convert_argb_pixel(const uint8_t *src_ptr, const struct pixel_format } color = tmp; + if (conv_flags & CONV_FLAG_SRGB_OUT) + srgb_from_linear_rgb(&color.value); if (conv_flags & CONV_FLAG_PM_ALPHA_OUT) premultiplied_alpha_from_straight_alpha(&color.value); format_from_d3dx_color(dst_fmt, &color, dst_ptr); @@ -2727,6 +2760,8 @@ static void box_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src format_to_d3dx_color(src_format, ptr, palette, &tmp); if (conv_flags & CONV_FLAG_PM_ALPHA_IN) straight_alpha_from_premultiplied_alpha(&color.value); + if (conv_flags & CONV_FLAG_SRGB_IN) + linear_rgb_from_srgb(&color.value); if (color_key) check_color_key(&tmp, color_key, ck_format); vec4_add(&color.value, &tmp.value); @@ -2734,6 +2769,8 @@ static void box_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src format_to_d3dx_color(src_format, ptr + src_format->bytes_per_pixel, palette, &tmp); if (conv_flags & CONV_FLAG_PM_ALPHA_IN) straight_alpha_from_premultiplied_alpha(&color.value); + if (conv_flags & CONV_FLAG_SRGB_IN) + linear_rgb_from_srgb(&color.value); if (color_key) check_color_key(&tmp, color_key, ck_format); vec4_add(&color.value, &tmp.value); @@ -2742,6 +2779,8 @@ static void box_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src format_to_d3dx_color(src_format, ptr, palette, &tmp); if (conv_flags & CONV_FLAG_PM_ALPHA_IN) straight_alpha_from_premultiplied_alpha(&color.value); + if (conv_flags & CONV_FLAG_SRGB_IN) + linear_rgb_from_srgb(&color.value); if (color_key) check_color_key(&tmp, color_key, ck_format); vec4_add(&color.value, &tmp.value); @@ -2749,12 +2788,16 @@ static void box_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src format_to_d3dx_color(src_format, ptr + src_format->bytes_per_pixel, palette, &tmp); if (conv_flags & CONV_FLAG_PM_ALPHA_IN) straight_alpha_from_premultiplied_alpha(&color.value); + if (conv_flags & CONV_FLAG_SRGB_IN) + linear_rgb_from_srgb(&color.value); if (color_key) check_color_key(&tmp, color_key, ck_format); vec4_add(&color.value, &tmp.value); } vec4_scale(&color.value, src_size->depth > 1 ? 0.125f : 0.25f); + if (conv_flags & CONV_FLAG_SRGB_OUT) + srgb_from_linear_rgb(&color.value); if (conv_flags & CONV_FLAG_PM_ALPHA_OUT) premultiplied_alpha_from_straight_alpha(&color.value); format_from_d3dx_color(dst_format, &color, dst_ptr); diff --git a/dlls/d3dx9_36/d3dx_helpers.h b/dlls/d3dx9_36/d3dx_helpers.h index 5b65f52cfa3..10cbc1723ed 100644 --- a/dlls/d3dx9_36/d3dx_helpers.h +++ b/dlls/d3dx9_36/d3dx_helpers.h @@ -246,6 +246,8 @@ enum conversion_flag { CONV_FLAG_PM_ALPHA_IN = 0x01, CONV_FLAG_PM_ALPHA_OUT = 0x02, + CONV_FLAG_SRGB_IN = 0x04, + CONV_FLAG_SRGB_OUT = 0x08, }; enum component_type diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 99a6af38ae8..ea01e3389a9 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1394,7 +1394,7 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); - todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_in_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 1); + check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_in_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 1); IDirect3DSurface9_UnlockRect(decomp_surf); /* DXT4, SRGB in. */ @@ -1403,7 +1403,7 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); - todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_in_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 1); + check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_in_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 1); IDirect3DSurface9_UnlockRect(decomp_surf); /* @@ -1426,7 +1426,7 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); - todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_out_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 0); + check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_out_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 0); IDirect3DSurface9_UnlockRect(decomp_surf); /* DXT4, SRGB out. */ @@ -1446,7 +1446,7 @@ static void test_dxt_premultiplied_alpha(IDirect3DDevice9 *device) ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); IDirect3DSurface9_LockRect(decomp_surf, &lock_rect, NULL, D3DLOCK_READONLY); - todo_wine check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_out_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 0); + check_test_readback(lock_rect.pBits, lock_rect.Pitch, 0, dxt_srgb_out_expected, 4, 4, 1, D3DFMT_A8R8G8B8, 0); IDirect3DSurface9_UnlockRect(decomp_surf); IDirect3DSurface9_Release(decomp_surf); @@ -5432,11 +5432,11 @@ static void test_srgb_filter_flags(void) }, { { 0, 0, 2, 2 }, test_a8r8g8b8, D3DFMT_A8R8G8B8, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, - test_a8r8g8b8_srgb_in_expected, .todo = TRUE + test_a8r8g8b8_srgb_in_expected }, { { 0, 0, 2, 2 }, test_a8r8g8b8, D3DFMT_A8R8G8B8, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_OUT, - test_a8r8g8b8_srgb_out_expected, .todo = TRUE + test_a8r8g8b8_srgb_out_expected }, { { 0, 0, 2, 2 }, test_float4_srgb_in, D3DFMT_A32B32G32R32F, D3DX_FILTER_NONE | D3DX_FILTER_SRGB_IN, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
On Thu Apr 16 22:14:31 2026 +0000, Matteo Bruni wrote:
It's probably not a big deal, but this is missing the matching `CoUninitialize()` at the end (I'm genuinely not sure but all the preexisting instances do have it). I _think_ it became convention because it's necessary for formats that use WIC. I've had cases where I forgot to do `CoInitialize()`, added some tests and got random unexpected failures. Either way, I've added a `CoUninitialize()` to the end of this function (and also a missing `ID3D10Device_Release()`) :)
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10513#note_136754
participants (2)
-
Connor McAdams -
Connor McAdams (@cmcadams)