This is the first set of patches in an effort to create more generic image loading/conversion code that can eventually be shared.
-- v2: d3dx9: Preserve the contents of unaligned compressed destination surfaces. d3dx9: Split off image decompression into a helper function. d3dx9: Split D3DXLoadSurfaceFromMemory functionality into a separate function.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/tests/surface.c | 90 +++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+)
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 8b48d13d45b..70c4c993efa 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -279,6 +279,24 @@ static const BYTE dds_dxt5_8_8[] = 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x05,0x05,0x50,0x50, };
+/* + * 8x8 dxt5 image data, four 4x4 blocks: + * +-----+-----+ + * |Blue |Green| + * | | | + * +-----+-----+ + * |Red |Black| + * | | | + * +-----+-----+ + */ +static const BYTE dxt5_8_8[] = +{ + 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xf8,0x1f,0xf8,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x07,0xff,0x07,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00, +}; + static HRESULT create_file(const char *filename, const unsigned char *data, const unsigned int size) { DWORD received; @@ -832,6 +850,35 @@ static inline void _check_pixel_4bpp(unsigned int line, const D3DLOCKED_RECT *lo ok_(__FILE__, line)(color == expected_color, "Got color 0x%08lx, expected 0x%08lx\n", color, expected_color); }
+#define check_dxt_pixel_4bpp(device, dxt_surf, width, height, x, y, color, todo) _check_dxt_pixel_4bpp(__LINE__, device,\ + dxt_surf, width, height, x, y, color, todo) +static inline void _check_dxt_pixel_4bpp(unsigned int line, IDirect3DDevice9 *device, IDirect3DSurface9 *dxt_surf, int width, + int height, int x, int y, DWORD expected_color, BOOL todo) +{ + IDirect3DSurface9 *decomp_surf; + D3DLOCKED_RECT lockrect; + DWORD color; + HRESULT hr; + RECT rect; + + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &decomp_surf, NULL); + ok_(__FILE__, line)(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = D3DXLoadSurfaceFromSurface(decomp_surf, NULL, NULL, dxt_surf, NULL, NULL, D3DX_FILTER_NONE, 0); + ok_(__FILE__, line)(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + SetRect(&rect, 0, 0, width, height); + hr = IDirect3DSurface9_LockRect(decomp_surf, &lockrect, &rect, D3DLOCK_READONLY); + ok_(__FILE__, line)(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + color = ((DWORD*)lockrect.pBits)[x + y * lockrect.Pitch / 4]; + todo_wine_if(todo) ok_(__FILE__, line)(color == expected_color, "Got color 0x%08lx, expected 0x%08lx\n", color, expected_color); + + hr = IDirect3DSurface9_UnlockRect(decomp_surf); + ok_(__FILE__, line)(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + check_release((IUnknown *)decomp_surf, 0); +} + static void test_D3DXLoadSurface(IDirect3DDevice9 *device) { HRESULT hr; @@ -1521,6 +1568,49 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device)
check_release((IUnknown *)newsurf, 1); check_release((IUnknown *)tex, 0); + + /* Misalignment tests but check the resulting image. */ + hr = IDirect3DDevice9_CreateTexture(device, 8, 8, 1, 0, D3DFMT_DXT5, D3DPOOL_SYSTEMMEM, &tex, NULL); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + SetRect(&rect, 0, 0, 8, 8); + hr = D3DXLoadSurfaceFromMemory(newsurf, NULL, NULL, dxt5_8_8, + D3DFMT_DXT5, 16 * 2, NULL, &rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 0, 0xff0000ff, FALSE); /* Blue block, top left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 3, 0xff0000ff, FALSE); /* Blue block, bottom right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 0, 0x00ff00ff, FALSE); /* Green block, top right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 3, 0x00ff00ff, FALSE); /* Green block, bottom left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 4, 0x0000ffff, FALSE); /* Red block, top right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 7, 0x0000ffff, FALSE); /* Red block, bottom left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 4, 0x000000ff, FALSE); /* Black block, top left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 7, 0x000000ff, FALSE); /* Black block, bottom right. */ + + /* + * Load our surface into a destination rectangle that overlaps + * multiple blocks. Original data in the blocks should be + * preserved. + */ + SetRect(&rect, 4, 4, 8, 8); + SetRect(&destrect, 2, 2, 6, 6); + hr = D3DXLoadSurfaceFromMemory(newsurf, NULL, &destrect, dxt5_8_8, + D3DFMT_DXT5, 16 * 2, NULL, &rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 0, 0xff0000ff, TRUE); /* Blue block, top left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 3, 0x000000ff, TRUE); /* Blue block, bottom right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 0, 0x00ff00ff, TRUE); /* Green block, top right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 3, 0x000000ff, TRUE); /* Green block, bottom left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 4, 0x000000ff, TRUE); /* Red block, top right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 7, 0x0000ffff, TRUE); /* Red block, bottom left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 4, 0x000000ff, TRUE); /* Black block, top left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 7, 0x000000ff, TRUE); /* Black block, bottom right. */ + + check_release((IUnknown *)newsurf, 1); + check_release((IUnknown *)tex, 0); }
hr = IDirect3DDevice9_CreateTexture(device, 4, 4, 1, 0, D3DFMT_DXT1, D3DPOOL_SYSTEMMEM, &tex, NULL);
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 11 ++++++----- dlls/d3dx9_36/tests/surface.c | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 25a762e7e8a..b8dd67d106f 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1914,6 +1914,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, { const struct pixel_format_desc *srcformatdesc, *destformatdesc; struct volume src_size, dst_size, dst_size_aligned; + const BYTE *src_memory_offset = src_memory; RECT dst_rect_temp, dst_rect_aligned; IDirect3DSurface9 *surface; D3DSURFACE_DESC surfdesc; @@ -2000,7 +2001,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, if (FAILED(hr = lock_surface(dst_surface, &dst_rect_aligned, &lockrect, &surface, TRUE))) return hr;
- src_memory = (BYTE *)src_memory + src_rect->top / srcformatdesc->block_height * src_pitch + src_memory_offset += src_rect->top / srcformatdesc->block_height * src_pitch + src_rect->left / srcformatdesc->block_width * srcformatdesc->block_byte_count;
if (src_format == surfdesc.Format @@ -2013,7 +2014,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, && !(dst_rect->top & (destformatdesc->block_height - 1))) { TRACE("Simple copy.\n"); - copy_pixels(src_memory, src_pitch, 0, lockrect.pBits, lockrect.Pitch, 0, + copy_pixels(src_memory_offset, src_pitch, 0, lockrect.pBits, lockrect.Pitch, 0, &src_size, srcformatdesc); } else /* Stretching or format conversion. */ @@ -2075,7 +2076,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, ++ptr; } } - src_memory = src_uncompressed; + src_memory_offset = (BYTE *)src_uncompressed; src_pitch = src_size.width * sizeof(DWORD); srcformatdesc = get_format_info(D3DFMT_A8B8G8R8); } @@ -2110,7 +2111,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface,
if ((filter & 0xf) == D3DX_FILTER_NONE) { - convert_argb_pixels(src_memory, src_pitch, 0, &src_size, srcformatdesc, + convert_argb_pixels(src_memory_offset, src_pitch, 0, &src_size, srcformatdesc, dst_mem, dst_pitch, 0, &dst_size, dst_format, color_key, src_palette); } else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ @@ -2120,7 +2121,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface,
/* Always apply a point filter until D3DX_FILTER_LINEAR, * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ - point_filter_argb_pixels(src_memory, src_pitch, 0, &src_size, srcformatdesc, + point_filter_argb_pixels(src_memory_offset, src_pitch, 0, &src_size, srcformatdesc, dst_mem, dst_pitch, 0, &dst_size, dst_format, color_key, src_palette); }
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 70c4c993efa..8823c4e0b52 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1601,12 +1601,12 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 0, 0xff0000ff, TRUE); /* Blue block, top left. */ - check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 3, 0x000000ff, TRUE); /* Blue block, bottom right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 3, 0x000000ff, FALSE); /* Blue block, bottom right. */ check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 0, 0x00ff00ff, TRUE); /* Green block, top right. */ - check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 3, 0x000000ff, TRUE); /* Green block, bottom left. */ - check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 4, 0x000000ff, TRUE); /* Red block, top right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 3, 0x000000ff, FALSE); /* Green block, bottom left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 4, 0x000000ff, FALSE); /* Red block, top right. */ check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 7, 0x0000ffff, TRUE); /* Red block, bottom left. */ - check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 4, 0x000000ff, TRUE); /* Black block, top left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 4, 0x000000ff, FALSE); /* Black block, top left. */ check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 7, 0x000000ff, TRUE); /* Black block, bottom right. */
check_release((IUnknown *)newsurf, 1);
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 354 +++++++++++++++++++++------------------- 1 file changed, 188 insertions(+), 166 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index b8dd67d106f..177197e8f3f 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1875,6 +1875,190 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic } }
+static void set_volume_struct(struct volume *volume, UINT width, UINT height, UINT depth) +{ + volume->width = width; + volume->height = height; + volume->depth = depth; +} + +static HRESULT d3dx_load_image_from_memory(void *dst_memory, int32_t dst_row_pitch, const struct pixel_format_desc *dst_desc, + const PALETTEENTRY *dst_palette, const RECT *dst_rect, const RECT *dst_rect_aligned, const void *src_memory, + int32_t src_row_pitch, const struct pixel_format_desc *src_desc, const PALETTEENTRY *src_palette, const RECT *src_rect, + uint32_t filter_flags, uint32_t color_key) +{ + struct volume src_size, dst_size, dst_size_aligned; + const BYTE *src_memory_offset = src_memory; + HRESULT hr = S_OK; + + TRACE("dst_memory %p, dst_row_pitch %d, dst_desc %p, dst_palette %p, dst_rect %s, dst_rect_aligned %s, src_memory %p, " + "src_row_pitch %d, src_desc %p, src_palette %p, src_rect %s, filter %#x, color_key 0x%08x.\n", + dst_memory, dst_row_pitch, dst_desc, dst_palette, wine_dbgstr_rect(dst_rect), wine_dbgstr_rect(dst_rect_aligned), + src_memory, src_row_pitch, src_desc, src_palette, wine_dbgstr_rect(src_rect), filter_flags, color_key); + + set_volume_struct(&src_size, (src_rect->right - src_rect->left), (src_rect->bottom - src_rect->top), 1); + set_volume_struct(&dst_size, (dst_rect->right - dst_rect->left), (dst_rect->bottom - dst_rect->top), 1); + set_volume_struct(&dst_size_aligned, (dst_rect_aligned->right - dst_rect_aligned->left), + (dst_rect_aligned->bottom - dst_rect_aligned->top), 1); + + src_memory_offset += (src_rect->top / src_desc->block_height) * src_row_pitch; + src_memory_offset += (src_rect->left / src_desc->block_width) * src_desc->block_byte_count; + + /* Everything matches, simply copy the pixels. */ + if (src_desc->format == dst_desc->format + && dst_size.width == src_size.width + && dst_size.height == src_size.height + && color_key == 0 + && !(src_rect->left & (src_desc->block_width - 1)) + && !(src_rect->top & (src_desc->block_height - 1)) + && !(dst_rect->left & (dst_desc->block_width - 1)) + && !(dst_rect->top & (dst_desc->block_height - 1))) + { + TRACE("Simple copy.\n"); + copy_pixels(src_memory_offset, src_row_pitch, 0, dst_memory, dst_row_pitch, 0, &src_size, src_desc); + return S_OK; + } + + /* Stretching or format conversion. */ + if (!is_conversion_from_supported(src_desc) + || !is_conversion_to_supported(dst_desc)) + { + FIXME("Unsupported format conversion %#x -> %#x.\n", src_desc->format, dst_desc->format); + return E_NOTIMPL; + } + + /* + * If the source is a compressed image, we need to decompress it first + * before doing any modifications. + */ + if (src_desc->type == FORMAT_DXT) + { + void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); + const struct pixel_format_desc *src_uncompressed_desc; + UINT src_uncompressed_row_pitch, tmp_pitch; + DWORD *src_uncompressed = NULL; + RECT src_uncompressed_rect; + unsigned int x, y; + + tmp_pitch = src_row_pitch * src_desc->block_width / src_desc->block_byte_count; + + src_uncompressed = malloc(src_size.width * src_size.height * sizeof(DWORD)); + if (!src_uncompressed) + return E_OUTOFMEMORY; + + switch (src_desc->format) + { + case D3DFMT_DXT1: + fetch_dxt_texel = fetch_2d_texel_rgba_dxt1; + break; + case D3DFMT_DXT2: + case D3DFMT_DXT3: + fetch_dxt_texel = fetch_2d_texel_rgba_dxt3; + break; + case D3DFMT_DXT4: + case D3DFMT_DXT5: + fetch_dxt_texel = fetch_2d_texel_rgba_dxt5; + break; + default: + FIXME("Unexpected compressed texture format %u.\n", src_desc->format); + fetch_dxt_texel = NULL; + } + + TRACE("Uncompressing DXTn surface.\n"); + for (y = 0; y < src_size.height; ++y) + { + DWORD *ptr = &src_uncompressed[y * src_size.width]; + for (x = 0; x < src_size.width; ++x) + { + fetch_dxt_texel(tmp_pitch, src_memory, x + src_rect->left, y + src_rect->top, ptr); + ++ptr; + } + } + + src_uncompressed_row_pitch = src_size.width * sizeof(DWORD); + src_uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); + SetRect(&src_uncompressed_rect, 0, 0, src_size.width, src_size.height); + hr = d3dx_load_image_from_memory(dst_memory, dst_row_pitch, dst_desc, dst_palette, dst_rect, dst_rect_aligned, + src_uncompressed, src_uncompressed_row_pitch, src_uncompressed_desc, src_palette, &src_uncompressed_rect, + filter_flags, color_key); + free(src_uncompressed); + return hr; + } + + /* Same as the above, need to decompress the destination prior to modifying. */ + if (dst_desc->type == FORMAT_DXT) + { + size_t dst_uncompressed_size = dst_size_aligned.width * dst_size_aligned.height * sizeof(DWORD); + BOOL dst_misaligned = dst_rect->left != dst_rect_aligned->left + || dst_rect->top != dst_rect_aligned->top + || dst_rect->right != dst_rect_aligned->right + || dst_rect->bottom != dst_rect_aligned->bottom; + const struct pixel_format_desc *dst_uncompressed_desc; + BYTE *dst_uncompressed, *dst_uncompressed_aligned; + UINT dst_uncompressed_row_pitch; + RECT dst_uncompressed_rect; + + dst_uncompressed_aligned = malloc(dst_uncompressed_size); + if (!dst_uncompressed_aligned) + return E_OUTOFMEMORY; + + if (dst_misaligned) memset(dst_uncompressed_aligned, 0, dst_uncompressed_size); + dst_uncompressed_row_pitch = dst_size_aligned.width * sizeof(DWORD); + dst_uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); + dst_uncompressed = dst_uncompressed_aligned + (dst_rect->top - dst_rect_aligned->top) * dst_uncompressed_row_pitch + + (dst_rect->left - dst_rect_aligned->left) * sizeof(DWORD); + + SetRect(&dst_uncompressed_rect, 0, 0, dst_size.width, dst_size.height); + hr = d3dx_load_image_from_memory(dst_uncompressed, dst_uncompressed_row_pitch, dst_uncompressed_desc, dst_palette, + &dst_uncompressed_rect, &dst_uncompressed_rect, src_memory_offset, src_row_pitch, src_desc, src_palette, + src_rect, filter_flags, color_key); + if (SUCCEEDED(hr)) + { + GLenum gl_format = 0; + + TRACE("Compressing DXTn surface.\n"); + switch (dst_desc->format) + { + case D3DFMT_DXT1: + gl_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case D3DFMT_DXT2: + case D3DFMT_DXT3: + gl_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case D3DFMT_DXT4: + case D3DFMT_DXT5: + gl_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + default: + ERR("Unexpected destination compressed format %u.\n", dst_desc->format); + } + tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, dst_uncompressed_aligned, gl_format, + dst_memory, dst_row_pitch); + } + free(dst_uncompressed_aligned); + return hr; + } + + if ((filter_flags & 0xf) == D3DX_FILTER_NONE) + { + convert_argb_pixels(src_memory_offset, src_row_pitch, 0, &src_size, src_desc, + dst_memory, dst_row_pitch, 0, &dst_size, dst_desc, color_key, src_palette); + } + else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ + { + if ((filter_flags & 0xf) != D3DX_FILTER_POINT) + FIXME("Unhandled filter %#x.\n", filter_flags); + + /* Always apply a point filter until D3DX_FILTER_LINEAR, + * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ + point_filter_argb_pixels(src_memory_offset, src_row_pitch, 0, &src_size, src_desc, dst_memory, dst_row_pitch, 0, + &dst_size, dst_desc, color_key, src_palette); + } + + return hr; +} + /************************************************************ * D3DXLoadSurfaceFromMemory * @@ -1913,8 +2097,6 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, DWORD filter, D3DCOLOR color_key) { const struct pixel_format_desc *srcformatdesc, *destformatdesc; - struct volume src_size, dst_size, dst_size_aligned; - const BYTE *src_memory_offset = src_memory; RECT dst_rect_temp, dst_rect_aligned; IDirect3DSurface9 *surface; D3DSURFACE_DESC surfdesc; @@ -1946,10 +2128,6 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, return E_NOTIMPL; }
- src_size.width = src_rect->right - src_rect->left; - src_size.height = src_rect->bottom - src_rect->top; - src_size.depth = 1; - IDirect3DSurface9_GetDesc(dst_surface, &surfdesc); destformatdesc = get_format_info(surfdesc.Format); if (!dst_rect) @@ -1988,172 +2166,16 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, dst_rect_aligned.bottom = min((dst_rect_aligned.bottom + destformatdesc->block_height - 1) & ~(destformatdesc->block_height - 1), surfdesc.Height);
- dst_size.width = dst_rect->right - dst_rect->left; - dst_size.height = dst_rect->bottom - dst_rect->top; - dst_size.depth = 1; - dst_size_aligned.width = dst_rect_aligned.right - dst_rect_aligned.left; - dst_size_aligned.height = dst_rect_aligned.bottom - dst_rect_aligned.top; - dst_size_aligned.depth = 1; - if (filter == D3DX_DEFAULT) filter = D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER;
if (FAILED(hr = lock_surface(dst_surface, &dst_rect_aligned, &lockrect, &surface, TRUE))) return hr;
- src_memory_offset += src_rect->top / srcformatdesc->block_height * src_pitch - + src_rect->left / srcformatdesc->block_width * srcformatdesc->block_byte_count; - - if (src_format == surfdesc.Format - && dst_size.width == src_size.width - && dst_size.height == src_size.height - && color_key == 0 - && !(src_rect->left & (srcformatdesc->block_width - 1)) - && !(src_rect->top & (srcformatdesc->block_height - 1)) - && !(dst_rect->left & (destformatdesc->block_width - 1)) - && !(dst_rect->top & (destformatdesc->block_height - 1))) - { - TRACE("Simple copy.\n"); - copy_pixels(src_memory_offset, src_pitch, 0, lockrect.pBits, lockrect.Pitch, 0, - &src_size, srcformatdesc); - } - else /* Stretching or format conversion. */ - { - const struct pixel_format_desc *dst_format; - DWORD *src_uncompressed = NULL; - BYTE *dst_uncompressed = NULL; - unsigned int dst_pitch; - BYTE *dst_mem; - - if (!is_conversion_from_supported(srcformatdesc) - || !is_conversion_to_supported(destformatdesc)) - { - FIXME("Unsupported format conversion %#x -> %#x.\n", src_format, surfdesc.Format); - unlock_surface(dst_surface, &dst_rect_aligned, surface, FALSE); - return E_NOTIMPL; - } - - if (srcformatdesc->type == FORMAT_DXT) - { - void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, - int i, int j, void *texel); - unsigned int x, y; - - src_pitch = src_pitch * srcformatdesc->block_width / srcformatdesc->block_byte_count; - - src_uncompressed = malloc(src_size.width * src_size.height * sizeof(DWORD)); - if (!src_uncompressed) - { - unlock_surface(dst_surface, &dst_rect_aligned, surface, FALSE); - return E_OUTOFMEMORY; - } - - switch(src_format) - { - case D3DFMT_DXT1: - fetch_dxt_texel = fetch_2d_texel_rgba_dxt1; - break; - case D3DFMT_DXT2: - case D3DFMT_DXT3: - fetch_dxt_texel = fetch_2d_texel_rgba_dxt3; - break; - case D3DFMT_DXT4: - case D3DFMT_DXT5: - fetch_dxt_texel = fetch_2d_texel_rgba_dxt5; - break; - default: - FIXME("Unexpected compressed texture format %u.\n", src_format); - fetch_dxt_texel = NULL; - } - - TRACE("Uncompressing DXTn surface.\n"); - for (y = 0; y < src_size.height; ++y) - { - DWORD *ptr = &src_uncompressed[y * src_size.width]; - for (x = 0; x < src_size.width; ++x) - { - fetch_dxt_texel(src_pitch, src_memory, x + src_rect->left, y + src_rect->top, ptr); - ++ptr; - } - } - src_memory_offset = (BYTE *)src_uncompressed; - src_pitch = src_size.width * sizeof(DWORD); - srcformatdesc = get_format_info(D3DFMT_A8B8G8R8); - } - - if (destformatdesc->type == FORMAT_DXT) - { - BOOL dst_misaligned = dst_rect->left != dst_rect_aligned.left - || dst_rect->top != dst_rect_aligned.top - || dst_rect->right != dst_rect_aligned.right - || dst_rect->bottom != dst_rect_aligned.bottom; - size_t dst_uncompressed_size = dst_size_aligned.width * dst_size_aligned.height * sizeof(DWORD); - - dst_uncompressed = malloc(dst_uncompressed_size); - if (!dst_uncompressed) - { - free(src_uncompressed); - unlock_surface(dst_surface, &dst_rect_aligned, surface, FALSE); - return E_OUTOFMEMORY; - } - if (dst_misaligned) memset(dst_uncompressed, 0, dst_uncompressed_size); - dst_pitch = dst_size_aligned.width * sizeof(DWORD); - dst_format = get_format_info(D3DFMT_A8B8G8R8); - dst_mem = dst_uncompressed + (dst_rect->top - dst_rect_aligned.top) * dst_pitch - + (dst_rect->left - dst_rect_aligned.left) * sizeof(DWORD); - } - else - { - dst_mem = lockrect.pBits; - dst_pitch = lockrect.Pitch; - dst_format = destformatdesc; - } - - if ((filter & 0xf) == D3DX_FILTER_NONE) - { - convert_argb_pixels(src_memory_offset, src_pitch, 0, &src_size, srcformatdesc, - dst_mem, dst_pitch, 0, &dst_size, dst_format, color_key, src_palette); - } - else /* if ((filter & 0xf) == D3DX_FILTER_POINT) */ - { - if ((filter & 0xf) != D3DX_FILTER_POINT) - FIXME("Unhandled filter %#lx.\n", filter); - - /* Always apply a point filter until D3DX_FILTER_LINEAR, - * D3DX_FILTER_TRIANGLE and D3DX_FILTER_BOX are implemented. */ - point_filter_argb_pixels(src_memory_offset, src_pitch, 0, &src_size, srcformatdesc, - dst_mem, dst_pitch, 0, &dst_size, dst_format, color_key, src_palette); - } - - free(src_uncompressed); - - if (dst_uncompressed) - { - GLenum gl_format = 0; - - TRACE("Compressing DXTn surface.\n"); - switch(surfdesc.Format) - { - case D3DFMT_DXT1: - gl_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - break; - case D3DFMT_DXT2: - case D3DFMT_DXT3: - gl_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - break; - case D3DFMT_DXT4: - case D3DFMT_DXT5: - gl_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - break; - default: - ERR("Unexpected destination compressed format %u.\n", surfdesc.Format); - } - tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, - dst_uncompressed, gl_format, lockrect.pBits, - lockrect.Pitch); - free(dst_uncompressed); - } - } + hr = d3dx_load_image_from_memory(lockrect.pBits, lockrect.Pitch, destformatdesc, dst_palette, dst_rect, + &dst_rect_aligned, src_memory, src_pitch, srcformatdesc, src_palette, src_rect, filter, color_key); + if (FAILED(hr)) + WARN("d3dx_load_image_from_memory failed with hr %#lx\n", hr);
return unlock_surface(dst_surface, &dst_rect_aligned, surface, TRUE); }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 111 +++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 46 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 177197e8f3f..14395d956e9 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1875,6 +1875,60 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic } }
+static HRESULT d3dx_image_decompress(const void *memory, UINT row_pitch, const RECT *rect, + const struct volume *size, const struct pixel_format_desc *desc, void **out_memory, + UINT *out_row_pitch, RECT *out_rect, const struct pixel_format_desc **out_desc) +{ + void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); + const struct pixel_format_desc *uncompressed_desc = NULL; + BYTE *uncompressed_mem; + unsigned int x, y; + UINT tmp_pitch; + + switch (desc->format) + { + case D3DFMT_DXT1: + uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); + fetch_dxt_texel = fetch_2d_texel_rgba_dxt1; + break; + case D3DFMT_DXT2: + case D3DFMT_DXT3: + uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); + fetch_dxt_texel = fetch_2d_texel_rgba_dxt3; + break; + case D3DFMT_DXT4: + case D3DFMT_DXT5: + uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); + fetch_dxt_texel = fetch_2d_texel_rgba_dxt5; + break; + default: + FIXME("Unexpected compressed texture format %u.\n", desc->format); + return E_NOTIMPL; + } + + if (!(uncompressed_mem = malloc(size->width * size->height * size->depth * uncompressed_desc->bytes_per_pixel))) + return E_OUTOFMEMORY; + + TRACE("Decompressing image.\n"); + tmp_pitch = row_pitch * desc->block_width / desc->block_byte_count; + for (y = 0; y < size->height; ++y) + { + BYTE *ptr = &uncompressed_mem[y * size->width * uncompressed_desc->bytes_per_pixel]; + for (x = 0; x < size->width; ++x) + { + fetch_dxt_texel(tmp_pitch, (BYTE *)memory, x + rect->left, y + rect->top, ptr); + ptr += uncompressed_desc->bytes_per_pixel; + } + } + + *out_memory = uncompressed_mem; + *out_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; + SetRect(out_rect, 0, 0, size->width, size->height); + *out_desc = uncompressed_desc; + + return S_OK; +} + static void set_volume_struct(struct volume *volume, UINT width, UINT height, UINT depth) { volume->width = width; @@ -1933,55 +1987,20 @@ static HRESULT d3dx_load_image_from_memory(void *dst_memory, int32_t dst_row_pit */ if (src_desc->type == FORMAT_DXT) { - void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); - const struct pixel_format_desc *src_uncompressed_desc; - UINT src_uncompressed_row_pitch, tmp_pitch; - DWORD *src_uncompressed = NULL; - RECT src_uncompressed_rect; - unsigned int x, y; - - tmp_pitch = src_row_pitch * src_desc->block_width / src_desc->block_byte_count; - - src_uncompressed = malloc(src_size.width * src_size.height * sizeof(DWORD)); - if (!src_uncompressed) - return E_OUTOFMEMORY; + const struct pixel_format_desc *uncompressed_desc; + void *uncompressed_mem = NULL; + UINT uncompressed_row_pitch; + RECT uncompressed_rect;
- switch (src_desc->format) + hr = d3dx_image_decompress(src_memory, src_row_pitch, src_rect, &src_size, src_desc, + &uncompressed_mem, &uncompressed_row_pitch, &uncompressed_rect, &uncompressed_desc); + if (SUCCEEDED(hr)) { - case D3DFMT_DXT1: - fetch_dxt_texel = fetch_2d_texel_rgba_dxt1; - break; - case D3DFMT_DXT2: - case D3DFMT_DXT3: - fetch_dxt_texel = fetch_2d_texel_rgba_dxt3; - break; - case D3DFMT_DXT4: - case D3DFMT_DXT5: - fetch_dxt_texel = fetch_2d_texel_rgba_dxt5; - break; - default: - FIXME("Unexpected compressed texture format %u.\n", src_desc->format); - fetch_dxt_texel = NULL; + hr = d3dx_load_image_from_memory(dst_memory, dst_row_pitch, dst_desc, dst_palette, dst_rect, dst_rect_aligned, + uncompressed_mem, uncompressed_row_pitch, uncompressed_desc, src_palette, &uncompressed_rect, + filter_flags, color_key); } - - TRACE("Uncompressing DXTn surface.\n"); - for (y = 0; y < src_size.height; ++y) - { - DWORD *ptr = &src_uncompressed[y * src_size.width]; - for (x = 0; x < src_size.width; ++x) - { - fetch_dxt_texel(tmp_pitch, src_memory, x + src_rect->left, y + src_rect->top, ptr); - ++ptr; - } - } - - src_uncompressed_row_pitch = src_size.width * sizeof(DWORD); - src_uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); - SetRect(&src_uncompressed_rect, 0, 0, src_size.width, src_size.height); - hr = d3dx_load_image_from_memory(dst_memory, dst_row_pitch, dst_desc, dst_palette, dst_rect, dst_rect_aligned, - src_uncompressed, src_uncompressed_row_pitch, src_uncompressed_desc, src_palette, &src_uncompressed_rect, - filter_flags, color_key); - free(src_uncompressed); + free(uncompressed_mem); return hr; }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/d3dx9_36/surface.c | 62 ++++++++++++++++++----------------- dlls/d3dx9_36/tests/surface.c | 8 ++--- 2 files changed, 36 insertions(+), 34 deletions(-)
diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 14395d956e9..9cde35fd856 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -1876,8 +1876,8 @@ void point_filter_argb_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slic }
static HRESULT d3dx_image_decompress(const void *memory, UINT row_pitch, const RECT *rect, - const struct volume *size, const struct pixel_format_desc *desc, void **out_memory, - UINT *out_row_pitch, RECT *out_rect, const struct pixel_format_desc **out_desc) + const RECT *exclude_rect, const struct volume *size, const struct pixel_format_desc *desc, + void **out_memory, UINT *out_row_pitch, RECT *out_rect, const struct pixel_format_desc **out_desc) { void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); const struct pixel_format_desc *uncompressed_desc = NULL; @@ -1909,6 +1909,9 @@ static HRESULT d3dx_image_decompress(const void *memory, UINT row_pitch, const R if (!(uncompressed_mem = malloc(size->width * size->height * size->depth * uncompressed_desc->bytes_per_pixel))) return E_OUTOFMEMORY;
+ if (exclude_rect && EqualRect(rect, exclude_rect)) + goto exit; + TRACE("Decompressing image.\n"); tmp_pitch = row_pitch * desc->block_width / desc->block_byte_count; for (y = 0; y < size->height; ++y) @@ -1916,14 +1919,21 @@ static HRESULT d3dx_image_decompress(const void *memory, UINT row_pitch, const R BYTE *ptr = &uncompressed_mem[y * size->width * uncompressed_desc->bytes_per_pixel]; for (x = 0; x < size->width; ++x) { - fetch_dxt_texel(tmp_pitch, (BYTE *)memory, x + rect->left, y + rect->top, ptr); + const POINT pt = { x, y }; + + if (!PtInRect(exclude_rect, pt)) + fetch_dxt_texel(tmp_pitch, (BYTE *)memory, x + rect->left, y + rect->top, ptr); ptr += uncompressed_desc->bytes_per_pixel; } }
+exit: *out_memory = uncompressed_mem; *out_row_pitch = size->width * uncompressed_desc->bytes_per_pixel; - SetRect(out_rect, 0, 0, size->width, size->height); + if (exclude_rect) + *out_rect = *exclude_rect; + else + SetRect(out_rect, 0, 0, size->width, size->height); *out_desc = uncompressed_desc;
return S_OK; @@ -1992,7 +2002,7 @@ static HRESULT d3dx_load_image_from_memory(void *dst_memory, int32_t dst_row_pit UINT uncompressed_row_pitch; RECT uncompressed_rect;
- hr = d3dx_image_decompress(src_memory, src_row_pitch, src_rect, &src_size, src_desc, + hr = d3dx_image_decompress(src_memory, src_row_pitch, src_rect, NULL, &src_size, src_desc, &uncompressed_mem, &uncompressed_row_pitch, &uncompressed_rect, &uncompressed_desc); if (SUCCEEDED(hr)) { @@ -2007,29 +2017,21 @@ static HRESULT d3dx_load_image_from_memory(void *dst_memory, int32_t dst_row_pit /* Same as the above, need to decompress the destination prior to modifying. */ if (dst_desc->type == FORMAT_DXT) { - size_t dst_uncompressed_size = dst_size_aligned.width * dst_size_aligned.height * sizeof(DWORD); - BOOL dst_misaligned = dst_rect->left != dst_rect_aligned->left - || dst_rect->top != dst_rect_aligned->top - || dst_rect->right != dst_rect_aligned->right - || dst_rect->bottom != dst_rect_aligned->bottom; - const struct pixel_format_desc *dst_uncompressed_desc; - BYTE *dst_uncompressed, *dst_uncompressed_aligned; - UINT dst_uncompressed_row_pitch; - RECT dst_uncompressed_rect; - - dst_uncompressed_aligned = malloc(dst_uncompressed_size); - if (!dst_uncompressed_aligned) - return E_OUTOFMEMORY; - - if (dst_misaligned) memset(dst_uncompressed_aligned, 0, dst_uncompressed_size); - dst_uncompressed_row_pitch = dst_size_aligned.width * sizeof(DWORD); - dst_uncompressed_desc = get_format_info(D3DFMT_A8B8G8R8); - dst_uncompressed = dst_uncompressed_aligned + (dst_rect->top - dst_rect_aligned->top) * dst_uncompressed_row_pitch - + (dst_rect->left - dst_rect_aligned->left) * sizeof(DWORD); - - SetRect(&dst_uncompressed_rect, 0, 0, dst_size.width, dst_size.height); - hr = d3dx_load_image_from_memory(dst_uncompressed, dst_uncompressed_row_pitch, dst_uncompressed_desc, dst_palette, - &dst_uncompressed_rect, &dst_uncompressed_rect, src_memory_offset, src_row_pitch, src_desc, src_palette, + const struct pixel_format_desc *uncompressed_desc; + void *uncompressed_mem = NULL; + BYTE *uncompressed_mem_offset; + UINT uncompressed_row_pitch; + RECT uncompressed_rect; + + hr = d3dx_image_decompress(dst_memory, dst_row_pitch, dst_rect_aligned, dst_rect, &dst_size_aligned, dst_desc, + &uncompressed_mem, &uncompressed_row_pitch, &uncompressed_rect, &uncompressed_desc); + if (FAILED(hr)) + return hr; + + uncompressed_mem_offset = (BYTE *)uncompressed_mem + (dst_rect->top - dst_rect_aligned->top) * uncompressed_row_pitch + + (dst_rect->left - dst_rect_aligned->left) * uncompressed_desc->bytes_per_pixel; + hr = d3dx_load_image_from_memory(uncompressed_mem_offset, uncompressed_row_pitch, uncompressed_desc, dst_palette, + &uncompressed_rect, &uncompressed_rect, src_memory, src_row_pitch, src_desc, src_palette, src_rect, filter_flags, color_key); if (SUCCEEDED(hr)) { @@ -2052,10 +2054,10 @@ static HRESULT d3dx_load_image_from_memory(void *dst_memory, int32_t dst_row_pit default: ERR("Unexpected destination compressed format %u.\n", dst_desc->format); } - tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, dst_uncompressed_aligned, gl_format, + tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, uncompressed_mem, gl_format, dst_memory, dst_row_pitch); } - free(dst_uncompressed_aligned); + free(uncompressed_mem); return hr; }
diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index 8823c4e0b52..de2253fa6af 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -1600,14 +1600,14 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) D3DFMT_DXT5, 16 * 2, NULL, &rect, D3DX_FILTER_NONE, 0); ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
- check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 0, 0xff0000ff, TRUE); /* Blue block, top left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 0, 0xff0000ff, FALSE); /* Blue block, top left. */ check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 3, 0x000000ff, FALSE); /* Blue block, bottom right. */ - check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 0, 0x00ff00ff, TRUE); /* Green block, top right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 0, 0x00ff00ff, FALSE); /* Green block, top right. */ check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 3, 0x000000ff, FALSE); /* Green block, bottom left. */ check_dxt_pixel_4bpp(device, newsurf, 8, 8, 3, 4, 0x000000ff, FALSE); /* Red block, top right. */ - check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 7, 0x0000ffff, TRUE); /* Red block, bottom left. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 0, 7, 0x0000ffff, FALSE); /* Red block, bottom left. */ check_dxt_pixel_4bpp(device, newsurf, 8, 8, 4, 4, 0x000000ff, FALSE); /* Black block, top left. */ - check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 7, 0x000000ff, TRUE); /* Black block, bottom right. */ + check_dxt_pixel_4bpp(device, newsurf, 8, 8, 7, 7, 0x000000ff, FALSE); /* Black block, bottom right. */
check_release((IUnknown *)newsurf, 1); check_release((IUnknown *)tex, 0);
Thanks Connor! I like the MR and the general direction a lot. I do have a few specific comments which I'm going to write out in a bit.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
- 8x8 dxt5 image data, four 4x4 blocks:
- +-----+-----+
- |Blue |Green|
- | | |
- +-----+-----+
- |Red |Black|
- | | |
- +-----+-----+
- */
+static const BYTE dxt5_8_8[] = +{
- 0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0xf8,0x1f,0xf8,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x07,0xff,0x07,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,
+};
I have been confused about this image data for a bit. The first row is alright, but there is no way that the others are what they claim to be: ``` [0x1f, 0xf8] -> this sets the first and last color components to "1.0", the middle one to 0. [0xff, 0x07] -> this sets the first two (LSB to MSB) components to "1.0", last to 0. Notice also how the last row has the same color data as the first. ``` Problem is, the tests pass and trying to "fix" the colors obviously broke the test.
Turns out, this is a combination of "comment misdirection" and slight test confusion. The uncompressed texture uses D3DFMT_A8R8G8B8, which is a BGRA format - channels are sort of "reversed". So the last (MSB -> LSB) component in the expected value isn't alpha but blue. Which means the second block is purple and the third one is cyan. The last one is transparent blue.
So, I'd either fix the comments to match the actual colors or (probably slightly preferable) fix the image and expected data to match the comment.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/tests/surface.c:
+#define check_dxt_pixel_4bpp(device, dxt_surf, width, height, x, y, color, todo) _check_dxt_pixel_4bpp(__LINE__, device,\
dxt_surf, width, height, x, y, color, todo)
+static inline void _check_dxt_pixel_4bpp(unsigned int line, IDirect3DDevice9 *device, IDirect3DSurface9 *dxt_surf, int width,
int height, int x, int y, DWORD expected_color, BOOL todo)
+{
- IDirect3DSurface9 *decomp_surf;
- D3DLOCKED_RECT lockrect;
- DWORD color;
- HRESULT hr;
- RECT rect;
- hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, width, height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &decomp_surf, NULL);
- ok_(__FILE__, line)(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
- hr = D3DXLoadSurfaceFromSurface(decomp_surf, NULL, NULL, dxt_surf, NULL, NULL, D3DX_FILTER_NONE, 0);
- ok_(__FILE__, line)(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
Efficiency isn't usually the top priority in the tests, but it's nice to have quicker tests if it doesn't take a lot of effort. In particular, for this kind of operation, I suggest to introduce a set of functions like the readback helpers from e.g. the d3d9:visual tests. In this case, it could be something like: ``` get_surface_readback() get_readback_color() release_readback() ``` Then the `check_pixel_4bpp` function will only take care of the comparison itself, maybe also of the call to get_readback_color().
Relatedly, notice that you can pass a NULL rect to LockRect and it will map the whole surface.
With this kind of "toolset" you can avoid repeating the decompression and locking steps. I don't expect some crazy improvement from this since, in this particular case, the textures are small and in system memory, but it's redundant work that can be avoided without complicating things too much (IMO) and it might actually matter more if we end up reusing these helpers for other tests.
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
}
}
+static HRESULT d3dx_image_decompress(const void *memory, UINT row_pitch, const RECT *rect,
const struct volume *size, const struct pixel_format_desc *desc, void **out_memory,
UINT *out_row_pitch, RECT *out_rect, const struct pixel_format_desc **out_desc)
+{
- void (*fetch_dxt_texel)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel);
- const struct pixel_format_desc *uncompressed_desc = NULL;
- BYTE *uncompressed_mem;
- unsigned int x, y;
- UINT tmp_pitch;
Let's avoid UINT when not necessary (like in this case for an internal function).
Matteo Bruni (@Mystral) commented about dlls/d3dx9_36/surface.c:
}
static HRESULT d3dx_image_decompress(const void *memory, UINT row_pitch, const RECT *rect,
const struct volume *size, const struct pixel_format_desc *desc, void **out_memory,
UINT *out_row_pitch, RECT *out_rect, const struct pixel_format_desc **out_desc)
const RECT *exclude_rect, const struct volume *size, const struct pixel_format_desc *desc,
void **out_memory, UINT *out_row_pitch, RECT *out_rect, const struct pixel_format_desc **out_desc)
I'd go for `aligned_rect` or something like that, `exclude` seems vague to me.