From: Santino Mazza <smazza@codeweavers.com> --- dlls/d2d1/Makefile.in | 1 + dlls/d2d1/d2d1_private.h | 8 + dlls/d2d1/device.c | 8 +- dlls/d2d1/sprite_batch.c | 141 +++++++++++++++++ dlls/d2d1/tests/d2d1.c | 333 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 489 insertions(+), 2 deletions(-) create mode 100644 dlls/d2d1/sprite_batch.c diff --git a/dlls/d2d1/Makefile.in b/dlls/d2d1/Makefile.in index 7c4596462aa..73add39286b 100644 --- a/dlls/d2d1/Makefile.in +++ b/dlls/d2d1/Makefile.in @@ -19,6 +19,7 @@ SOURCES = \ hwnd_render_target.c \ layer.c \ mesh.c \ + sprite_batch.c \ state_block.c \ stroke.c \ wic_render_target.c diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 9c78aaf92e2..a54077f8f98 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -460,6 +460,14 @@ HRESULT d2d_bitmap_create_from_wic_bitmap(struct d2d_device_context *context, IW unsigned int d2d_get_bitmap_options_for_surface(IDXGISurface *surface); struct d2d_bitmap *unsafe_impl_from_ID2D1Bitmap(ID2D1Bitmap *iface); +struct d2d_sprite_batch { + ID2D1SpriteBatch ID2D1SpriteBatch_iface; + + LONG refcount; +}; + +HRESULT d2d_create_sprite_batch(struct d2d_device_context *ctx, ID2D1SpriteBatch **iface); + struct d2d_state_block { ID2D1DrawingStateBlock1 ID2D1DrawingStateBlock1_iface; diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index b3560f09c12..0082288b4e9 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -3037,9 +3037,13 @@ static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateTransformedImageSource static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSpriteBatch(ID2D1DeviceContext6 *iface, ID2D1SpriteBatch **sprite_batch) { - FIXME("iface %p, sprite_batch %p stub!\n", iface, sprite_batch); + struct d2d_device_context *ctx = impl_from_ID2D1DeviceContext(iface); + TRACE("iface %p, sprite_batch %p\n", iface, sprite_batch); - return E_NOTIMPL; + if (!sprite_batch) + return E_INVALIDARG; + + return d2d_create_sprite_batch(ctx, sprite_batch); } static void STDMETHODCALLTYPE d2d_device_context_DrawSpriteBatch(ID2D1DeviceContext6 *iface, diff --git a/dlls/d2d1/sprite_batch.c b/dlls/d2d1/sprite_batch.c new file mode 100644 index 00000000000..e5d8c0c88a6 --- /dev/null +++ b/dlls/d2d1/sprite_batch.c @@ -0,0 +1,141 @@ +/* + * Copyright 2026 Santino Mazza for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "d2d1_private.h" +#include <windows.h> + +WINE_DEFAULT_DEBUG_CHANNEL(d2d); + +static inline struct d2d_sprite_batch *impl_from_ID2D1SpriteBatch(ID2D1SpriteBatch *iface) +{ + return CONTAINING_RECORD(iface, struct d2d_sprite_batch, ID2D1SpriteBatch_iface); +} + +static HRESULT STDMETHODCALLTYPE d2d_sprite_batch_QueryInterface(ID2D1SpriteBatch *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_ID2D1SpriteBatch) + || IsEqualGUID(iid, &IID_IUnknown)) + { + ID2D1SpriteBatch_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE d2d_sprite_batch_AddRef(ID2D1SpriteBatch *iface) +{ + struct d2d_sprite_batch *batch = impl_from_ID2D1SpriteBatch(iface); + ULONG refcount = InterlockedIncrement(&batch->refcount); + + TRACE("%p increasing refcount to %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE d2d_sprite_batch_Release(ID2D1SpriteBatch *iface) +{ + struct d2d_sprite_batch *batch = impl_from_ID2D1SpriteBatch(iface); + ULONG refcount = InterlockedDecrement(&batch->refcount); + + TRACE("%p decreasing refcount to %lu.\n", iface, refcount); + + if (!refcount) { + free(batch); + } + + return refcount; +} + +static void STDMETHODCALLTYPE d2d_sprite_batch_GetFactory(ID2D1SpriteBatch *iface, ID2D1Factory **factory) +{ + FIXME("(%p): stub\n", iface); +} + +static HRESULT STDMETHODCALLTYPE d2d_sprite_batch_AddSprites(ID2D1SpriteBatch *iface, UINT32 sprite_count, + const D2D1_RECT_F *destination_rectangles, const D2D1_RECT_U *source_rectangles, const D2D1_COLOR_F *colors, + const D2D1_MATRIX_3X2_F *transforms, UINT32 destination_rectangles_stride, UINT32 source_rectangles_stride, + UINT32 colors_stride, UINT32 transforms_stride) +{ + FIXME("(%p): stub\n", iface); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_sprite_batch_SetSprites(ID2D1SpriteBatch *iface, UINT32 start_index, UINT32 sprite_count, + const D2D1_RECT_F *destination_rectangles, const D2D1_RECT_U *source_rectangles, const D2D1_COLOR_F *colors, + const D2D1_MATRIX_3X2_F *transforms, UINT32 destination_rectangles_stride, UINT32 source_rectangles_stride, + UINT32 colors_stride, UINT32 transforms_stride) +{ + FIXME("(%p): stub\n", iface); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_sprite_batch_GetSprites(ID2D1SpriteBatch *iface, UINT32 start_index, UINT32 sprite_count, + D2D1_RECT_F *destination_rectangles, D2D1_RECT_U *source_rectangles, D2D1_COLOR_F *colors, + D2D1_MATRIX_3X2_F *transforms) +{ + FIXME("(%p): stub\n", iface); + + return E_NOTIMPL; +} + +static UINT32 STDMETHODCALLTYPE d2d_sprite_batch_GetSpritesCount(ID2D1SpriteBatch *iface) +{ + FIXME("(%p): stub\n", iface); + + return 0; +} + +static void STDMETHODCALLTYPE d2d_sprite_batch_Clear(ID2D1SpriteBatch *iface) +{ + FIXME("(%p): stub\n", iface); +} + +static const struct ID2D1SpriteBatchVtbl d2d_sprite_batch_vtbl = { + d2d_sprite_batch_QueryInterface, + d2d_sprite_batch_AddRef, + d2d_sprite_batch_Release, + d2d_sprite_batch_GetFactory, + d2d_sprite_batch_AddSprites, + d2d_sprite_batch_SetSprites, + d2d_sprite_batch_GetSprites, + d2d_sprite_batch_GetSpritesCount, + d2d_sprite_batch_Clear +}; + +HRESULT d2d_create_sprite_batch(struct d2d_device_context *ctx, ID2D1SpriteBatch **iface) { + struct d2d_sprite_batch *sprite_batch; + + if (!(sprite_batch = calloc(1, sizeof(*sprite_batch)))) + return E_OUTOFMEMORY; + + sprite_batch->ID2D1SpriteBatch_iface.lpVtbl = &d2d_sprite_batch_vtbl; + + ID2D1SpriteBatch_AddRef(&sprite_batch->ID2D1SpriteBatch_iface); + *iface = &sprite_batch->ID2D1SpriteBatch_iface; + + return S_OK; +} diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index afda90f1271..7404c3aa2a4 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -909,6 +909,14 @@ static BOOL compare_rect_f(const D2D1_RECT_F *rect, float left, float top, float && compare_float(rect->bottom, bottom, ulps); } +static BOOL compare_rect_u(const D2D1_RECT_U *rect, UINT left, UINT top, UINT right, UINT bottom) +{ + return rect->left == left && + rect->top == top && + rect->right == right && + rect->bottom == bottom; +} + static BOOL compare_bezier_segment(const D2D1_BEZIER_SEGMENT *b, float x1, float y1, float x2, float y2, float x3, float y3, unsigned int ulps) { @@ -18004,6 +18012,330 @@ static void test_glyph_run_world_bounds(BOOL d3d11) release_test_context(&ctx); } +static void test_sprite_batches(BOOL d3d11) { + ID2D1SpriteBatch *sprite_batch; + struct d2d1_test_context ctx; + ID2D1DeviceContext3 *device; + ID2D1Bitmap *bitmap; + UINT32 sprite_count; + BOOL check; + HRESULT hr; + + static const DWORD bitmap_data[] = + { + 0xffff0000, 0xffffff00, 0xff00ff00, 0xff00ffff, + 0xff0000ff, 0xffff00ff, 0xff000000, 0xff7f7f7f, + 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, + 0xffffffff, 0xff000000, 0xff000000, 0xff000000, + }; + const D2D1_SIZE_U bitmap_size = {4, 4}; + const D2D1_BITMAP_PROPERTIES bitmap_desc = { + {DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_IGNORE}, + 96.0f, + 96.0f + }; + + D2D1_RECT_F test_destination_rect[2] = {{0, 0, bitmap_size.width, bitmap_size.height}, {5, 5, 9, 9}}; + D2D1_RECT_U test_source_rect[2] = {{0, 0, 4, 4}, {1, 1, 4, 4}}; + D2D1_COLOR_F test_colors[2] = {{1.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}; + D2D1_MATRIX_3X2_F test_matrixes[2]; + + D2D1_RECT_F destination_rects[4]; + D2D1_RECT_U source_rects[4]; + D2D1_COLOR_F colors[4]; + D2D1_MATRIX_3X2_F transforms[4]; + + set_matrix_identity(&test_matrixes[0]); + set_matrix_identity(&test_matrixes[1]); + + if (!init_test_context(&ctx, d3d11)) + return; + + hr = ID2D1DeviceContext_QueryInterface(ctx.context, &IID_ID2D1DeviceContext3, (void**)&device); + ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1DeviceContext3_CreateSpriteBatch(device, &sprite_batch); + ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + todo_wine check_interface(sprite_batch, &IID_ID2D1Resource, TRUE); + + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, NULL, NULL, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + ok(sprite_count == 0, "Expected sprite count of 0 got %d\n", sprite_count); + + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, NULL, test_source_rect, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + ok(sprite_count == 0, "Expected sprite count of 0 got %d\n", sprite_count); + + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, test_destination_rect, NULL, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + todo_wine ok(sprite_count == 2, "Expected sprite count of 2 got %d\n", sprite_count); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 2, destination_rects, source_rects, colors, transforms); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + todo_wine ok(compare_rect_f(&destination_rects[0], 0, 0, 4, 4, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[0].left, destination_rects[0].top, + destination_rects[0].right, destination_rects[0].bottom); + + todo_wine ok(compare_rect_f(&destination_rects[1], 0, 0, 4, 4, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[1].left, destination_rects[1].top, + destination_rects[1].right, destination_rects[1].bottom); + + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, test_destination_rect, NULL, NULL, NULL, sizeof(*test_destination_rect), 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + todo_wine ok(sprite_count == 4, "Expected sprite count of 4 got %d\n", sprite_count); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 4, destination_rects, source_rects, colors, transforms); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + todo_wine ok(compare_rect_f(&destination_rects[0], 0, 0, 4, 4, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[0].left, destination_rects[0].top, + destination_rects[0].right, destination_rects[0].bottom); + + todo_wine ok(compare_rect_f(&destination_rects[1], 0, 0, 4, 4, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[1].left, destination_rects[1].top, + destination_rects[1].right, destination_rects[1].bottom); + + todo_wine ok(compare_rect_f(&destination_rects[2], 0, 0, 4, 4, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[2].left, destination_rects[2].top, + destination_rects[2].right, destination_rects[2].bottom); + + todo_wine ok(compare_rect_f(&destination_rects[3], 5, 5, 9, 9, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[3].left, destination_rects[3].top, + destination_rects[3].right, destination_rects[3].bottom); + + hr = ID2D1SpriteBatch_SetSprites(sprite_batch, 0, 0, NULL, NULL, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_SetSprites(sprite_batch, 0, 8, NULL, NULL, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_SetSprites(sprite_batch, 5, 1, NULL, NULL, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_SetSprites(sprite_batch, 0, 1, NULL, NULL, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_SetSprites(sprite_batch, 0, 8, &test_destination_rect[1], NULL, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_SetSprites(sprite_batch, 0, 1, &test_destination_rect[1], NULL, NULL, NULL, 0, 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 1, destination_rects, NULL, NULL, NULL); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + todo_wine ok(compare_rect_f(&destination_rects[0], 5, 5, 9, 9, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[0].left, destination_rects[0].top, + destination_rects[0].right, destination_rects[0].bottom); + + ID2D1SpriteBatch_Clear(sprite_batch); + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + ok(sprite_count == 0, "Expected sprite count of 0 got %d\n", sprite_count); + + + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, test_destination_rect, NULL, NULL, NULL, sizeof(test_destination_rect->top), 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + todo_wine ok(sprite_count == 2, "Expected sprite count of 2 got %d\n", sprite_count); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 2, destination_rects, source_rects, colors, transforms); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + todo_wine ok(compare_rect_f(&destination_rects[0], 0, 0, 4, 4, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[0].left, destination_rects[0].top, + destination_rects[0].right, destination_rects[0].bottom); + + todo_wine ok(compare_rect_f(&destination_rects[1], 0, 4, 4, 5, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[1].left, destination_rects[1].top, + destination_rects[1].right, destination_rects[1].bottom); + + ID2D1SpriteBatch_Clear(sprite_batch); + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + ok(sprite_count == 0, "Expected sprite count of 0 got %d\n", sprite_count); + + + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, test_destination_rect, NULL, NULL, NULL, sizeof(*test_destination_rect), 0, 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + todo_wine ok(sprite_count == 2, "Expected sprite count of 2 got %d\n", sprite_count); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 4, destination_rects, source_rects, colors, transforms); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 3, 1, destination_rects, source_rects, colors, transforms); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 3, 0, destination_rects, source_rects, colors, transforms); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 0, destination_rects, source_rects, colors, transforms); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 2, NULL, NULL, NULL, NULL); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 2, destination_rects, source_rects, colors, transforms); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 2, NULL, source_rects, NULL, NULL); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 2, destination_rects, NULL, NULL, NULL); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + todo_wine ok(compare_rect_f(&destination_rects[0], 0, 0, 4, 4, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[0].left, destination_rects[0].top, + destination_rects[0].right, destination_rects[0].bottom); + + todo_wine ok(compare_rect_f(&destination_rects[1], 5, 5, 9, 9, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[1].left, destination_rects[1].top, + destination_rects[1].right, destination_rects[1].bottom); + + hr = ID2D1RenderTarget_CreateBitmap(ctx.rt, bitmap_size, bitmap_data, bitmap_size.width * sizeof(*bitmap_data), &bitmap_desc, &bitmap); + ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + ID2D1DeviceContext3_SetAntialiasMode(device, D2D1_ANTIALIAS_MODE_ALIASED); + + ID2D1DeviceContext3_BeginDraw(device); + ID2D1DeviceContext3_DrawSpriteBatch(device, sprite_batch, 0, 1, bitmap, 0, D2D1_SPRITE_OPTIONS_NONE); + hr = ID2D1DeviceContext3_EndDraw(device, 0, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check = compare_surface(&ctx, "5e8144c13d1a71f0b59d54eba7156218693fa7bd"); + todo_wine ok(check, "Surface does not match.\n"); + + ID2D1DeviceContext3_BeginDraw(device); + ID2D1DeviceContext3_DrawSpriteBatch(device, sprite_batch, 0, 2, bitmap, 0, D2D1_SPRITE_OPTIONS_NONE); + hr = ID2D1DeviceContext3_EndDraw(device, 0, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check = compare_surface(&ctx, "064e9e8b46799904cab52b14d69a235d4f41409b"); + todo_wine ok(check, "Surface does not match.\n"); + + ID2D1SpriteBatch_Clear(sprite_batch); + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + ok(sprite_count == 0, "Expected sprite count of 0 got %d\n", sprite_count); + + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, test_destination_rect, test_source_rect, NULL, NULL, sizeof(*test_destination_rect), sizeof(*test_source_rect), 0, 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + hr = ID2D1SpriteBatch_GetSprites(sprite_batch, 0, 2, destination_rects, source_rects, NULL, NULL); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + todo_wine ok(compare_rect_f(&destination_rects[0], 0, 0, 4, 4, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[0].left, destination_rects[0].top, + destination_rects[0].right, destination_rects[0].bottom); + + todo_wine ok(compare_rect_f(&destination_rects[1], 5, 5, 9, 9, 0), + "Got unexpected rectangle {%f, %f, %f, %f}.\n", + destination_rects[1].left, destination_rects[1].top, + destination_rects[1].right, destination_rects[1].bottom); + + todo_wine ok(compare_rect_u(&source_rects[0], 0, 0, 4, 4), + "Got unexpected rectangle {%u, %u, %u, %u}.\n", + source_rects[0].left, source_rects[0].top, + source_rects[0].right, source_rects[0].bottom); + + todo_wine ok(compare_rect_u(&source_rects[1], 1, 1, 4, 4), + "Got unexpected rectangle {%u, %u, %u, %u}.\n", + source_rects[1].left, source_rects[1].top, + source_rects[1].right, source_rects[1].bottom); + + ID2D1DeviceContext3_BeginDraw(device); + ID2D1DeviceContext3_DrawSpriteBatch(device, sprite_batch, 0, 2, bitmap, 0, D2D1_SPRITE_OPTIONS_NONE); + hr = ID2D1DeviceContext3_EndDraw(device, 0, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check = compare_surface(&ctx, "9133aab139f4c0ec2edea7e3c63069370ff88083"); + todo_wine ok(check, "Surface does not match.\n"); + + + ID2D1SpriteBatch_Clear(sprite_batch); + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + ok(sprite_count == 0, "Expected sprite count of 0 got %d\n", sprite_count); + + set_matrix_identity(&test_matrixes[1]); + scale_matrix(&test_matrixes[1], 4.0f, 4.0f); + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, test_destination_rect, test_source_rect, NULL, test_matrixes, sizeof(*test_destination_rect), sizeof(*test_source_rect), 0, sizeof(D2D1_MATRIX_3X2_F)); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + ID2D1DeviceContext3_BeginDraw(device); + ID2D1DeviceContext3_DrawSpriteBatch(device, sprite_batch, 0, 2, bitmap, 0, D2D1_SPRITE_OPTIONS_NONE); + hr = ID2D1DeviceContext3_EndDraw(device, 0, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check = compare_surface(&ctx, "30bf2de6f4f10ae8ebfc61261ad0d0a4abfed094"); + todo_wine ok(check, "Surface does not match.\n"); + + + ID2D1SpriteBatch_Clear(sprite_batch); + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + ok(sprite_count == 0, "Expected sprite count of 0 got %d\n", sprite_count); + + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, test_destination_rect, test_source_rect, test_colors, NULL, sizeof(*test_destination_rect), sizeof(*test_source_rect), sizeof(D2D1_COLOR_F), 0); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + ID2D1DeviceContext3_BeginDraw(device); + ID2D1DeviceContext3_DrawSpriteBatch(device, sprite_batch, 0, 2, bitmap, 0, D2D1_SPRITE_OPTIONS_NONE); + hr = ID2D1DeviceContext3_EndDraw(device, 0, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check = compare_surface(&ctx, "e21f4ac578dcc4ed266959872d243a8ce4f493d7"); + todo_wine ok(check, "Surface does not match.\n"); + + + ID2D1SpriteBatch_Clear(sprite_batch); + sprite_count = ID2D1SpriteBatch_GetSpriteCount(sprite_batch); + ok(sprite_count == 0, "Expected sprite count of 0 got %d\n", sprite_count); + + set_matrix_identity(&test_matrixes[1]); + skew_matrix(&test_matrixes[1], 0.5f, 0.5f); + hr = ID2D1SpriteBatch_AddSprites(sprite_batch, 2, test_destination_rect, test_source_rect, NULL, test_matrixes, sizeof(*test_destination_rect), sizeof(*test_source_rect), 0, sizeof(D2D1_MATRIX_3X2_F)); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx\n", hr); + + ID2D1DeviceContext3_BeginDraw(device); + ID2D1DeviceContext3_DrawSpriteBatch(device, sprite_batch, 0, 2, bitmap, 0, D2D1_SPRITE_OPTIONS_NONE); + hr = ID2D1DeviceContext3_EndDraw(device, 0, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + check = compare_surface(&ctx, "72d4c7723073eabc2d7d1939b6f41040546b21f7"); + todo_wine ok(check, "Surface does not match.\n"); + + ID2D1DeviceContext3_SetAntialiasMode(device, D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + + ID2D1DeviceContext3_BeginDraw(device); + ID2D1DeviceContext3_DrawSpriteBatch(device, sprite_batch, 0, 2, bitmap, 0, D2D1_SPRITE_OPTIONS_NONE); + hr = ID2D1DeviceContext3_EndDraw(device, 0, 0); + todo_wine ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + + ID2D1Bitmap_Release(bitmap); + + ID2D1DeviceContext3_Release(device); + ID2D1SpriteBatch_Release(sprite_batch); + release_test_context(&ctx); +} + START_TEST(d2d1) { HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); @@ -18127,6 +18459,7 @@ START_TEST(d2d1) queue_d3d10_test(test_path_geometry_stream); queue_d3d10_test(test_transformed_geometry); queue_d3d10_test(test_glyph_run_world_bounds); + queue_test(test_sprite_batches); run_queued_tests(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11249