[PATCH v2 0/7] MR10513: d3dx{9,10,11}: Add support for premultiplied alpha and SRGB conversions.
-- v2: 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 | 232 +++++++++++++++++++++++++++++ dlls/d3dx11_42/tests/Makefile.in | 1 + dlls/d3dx11_43/tests/Makefile.in | 1 + dlls/d3dx11_43/tests/d3dx11.c | 242 +++++++++++++++++++++++++++++++ 4 files changed, 476 insertions(+) diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index c35351a2301..c7d4f21bc2c 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,188 @@ 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; + unsigned int dds_size = sizeof(dds); + + 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, dds_size, &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(); + } +} + #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 +7448,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..4f1349c8ea8 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,184 @@ 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; + unsigned int dds_size = sizeof(dds); + + 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, dds_size, &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(); + } +} + static BOOL create_directory(const WCHAR *dir) { WCHAR path[MAX_PATH]; @@ -4718,4 +4959,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 c7d4f21bc2c..5c97470fc65 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 4f1349c8ea8..a9cbc762d02 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 14:09:26 2026 +0000, Connor McAdams wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/10513/diffs?diff_id=260854&start_sha=aa32ea309f50824ab09836b1ebcf8a18d25da4cd#7af4349b75c315543424998c70f7c31a2fc44f6a_5766_5761) Fixed in the newest revision. :)
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10513#note_136512
On Tue Apr 7 17:33:31 2026 +0000, Matteo Bruni wrote:
I seem to recall that you tried with the "accurate" piecewise sRGB definition previously (i.e. the one that's linear in the very low end and then uses a 2.4 exponent for the rest) but that didn't quite match as nicely? Maybe it makes sense to leave a small comment to that point, here or elsewhere. Separately, a bit of a nitpick. `apply_gamma_2_2()` might be slightly confusing: does it mean that gamma is applied to an sRGB color value to return the corresponding linear value or does it transform a linear color value into the corresponding sRGB value? In this case it's the latter, but you see the problem :slight_smile: Personally I'd just go with something like `srgb_from_linear()` and `linear_from_srgb()`, respectively. I've changed the conversion function names to be as you've suggested in the current revision, it definitely is clearer. I've done the same renaming to the premultiplied alpha conversion functions as well, I think it helps there too.
I've added some more tests around sRGB, as well as a comment above the conversion functions that hopefully explains things... the definition of "sRGB" is hard to track down, it seems some interpret it as just plain gamma 2.2, and others claim it only means the piece-wise sRGB definition. The MSDN docs refer to it as gamma 2.2 in some places, but then there are things like `D3DX_FLOAT_to_SRGB` in the DirectX SDK that treat it as the piece-wise version. Hopefully my code comment clarifies things :) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10513#note_136513
Matteo Bruni (@Mystral) commented about dlls/d3dx10_43/tests/d3dx10.c:
+ 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); 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).
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10513#note_136630
This merge request was approved by Matteo Bruni. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10513
Matteo Bruni (@Mystral) commented about dlls/d3dx10_43/tests/d3dx10.c:
+ 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; + unsigned int dds_size = sizeof(dds); The variable seems unnecessary.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10513#note_136631
participants (3)
-
Connor McAdams -
Connor McAdams (@cmcadams) -
Matteo Bruni (@Mystral)