For React Native
-- v2: d2d1: Support creating bitmap from DXGI subresource surface. d2d1/tests: Test creating bitmap from DXGI subresource surface.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/d2d1/tests/d2d1.c | 300 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 297 insertions(+), 3 deletions(-)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 2b894695c98..f0900770271 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -25,6 +25,7 @@ #include "d2d1_3.h" #include "d2d1effectauthor.h" #include "d3d11.h" +#include "dxgi1_2.h" #include "wincrypt.h" #include "wine/test.h" #include "initguid.h" @@ -643,12 +644,21 @@ static void get_d3d10_surface_readback(IDXGISurface *surface, struct resource_re D3D10_MAPPED_TEXTURE2D map_desc; DXGI_SURFACE_DESC surface_desc; ID3D10Resource *src_resource; + UINT subresource_idx = 0; + IDXGISurface2 *surface2; ID3D10Device *device; HRESULT hr;
hr = IDXGISurface_GetDevice(surface, &IID_ID3D10Device, (void **)&device); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = IDXGISurface_QueryInterface(surface, &IID_ID3D10Resource, (void **)&src_resource); + if (hr == E_NOINTERFACE) + { + hr = IDXGISurface_QueryInterface(surface, &IID_IDXGISurface2, (void **)&surface2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IDXGISurface2_GetResource(surface2, &IID_ID3D10Resource, (void **)&src_resource, &subresource_idx); + IDXGISurface2_Release(surface2); + } ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
hr = IDXGISurface_GetDesc(surface, &surface_desc); @@ -669,7 +679,8 @@ static void get_d3d10_surface_readback(IDXGISurface *surface, struct resource_re rb->width = texture_desc.Width; rb->height = texture_desc.Height;
- ID3D10Device_CopyResource(device, rb->u.d3d10_resource, src_resource); + ID3D10Device_CopySubresourceRegion(device, rb->u.d3d10_resource, 0, 0, 0, 0, src_resource, + subresource_idx, NULL); ID3D10Resource_Release(src_resource); ID3D10Device_Release(device);
@@ -687,12 +698,21 @@ static void get_d3d11_surface_readback(IDXGISurface *surface, struct resource_re DXGI_SURFACE_DESC surface_desc; ID3D11Resource *src_resource; ID3D11DeviceContext *context; + UINT subresource_idx = 0; + IDXGISurface2 *surface2; ID3D11Device *device; HRESULT hr;
hr = IDXGISurface_GetDevice(surface, &IID_ID3D11Device, (void **)&device); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = IDXGISurface_QueryInterface(surface, &IID_ID3D11Resource, (void **)&src_resource); + if (hr == E_NOINTERFACE) + { + hr = IDXGISurface_QueryInterface(surface, &IID_IDXGISurface2, (void **)&surface2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IDXGISurface2_GetResource(surface2, &IID_ID3D11Resource, (void **)&src_resource, &subresource_idx); + IDXGISurface2_Release(surface2); + } ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
hr = IDXGISurface_GetDesc(surface, &surface_desc); @@ -714,7 +734,8 @@ static void get_d3d11_surface_readback(IDXGISurface *surface, struct resource_re rb->height = texture_desc.Height;
ID3D11Device_GetImmediateContext(device, &context); - ID3D11DeviceContext_CopyResource(context, rb->u.d3d11_resource, src_resource); + ID3D11DeviceContext_CopySubresourceRegion(context, rb->u.d3d11_resource, 0, 0, 0, 0, + src_resource, subresource_idx, NULL); ID3D11Resource_Release(src_resource); ID3D11Device_Release(device);
@@ -1416,6 +1437,185 @@ static void check_bitmap_surface_(unsigned int line, ID2D1Bitmap *bitmap, BOOL h ID2D1Bitmap1_Release(bitmap1); }
+#define check_bitmap_subresource_surface(a, b, c, d, e, f, g) _check_bitmap_subresource_surface(__LINE__, a, b, c, d, e, f, g) +static void _check_bitmap_subresource_surface(unsigned int line, struct d2d1_test_context *ctx, + ID2D1Bitmap *bitmap, IDXGIResource1 *parent_resource, IDXGISurface *subresource_surface, + BOOL expect_parent_surface, DWORD expect_options, BOOL succeed_draw) +{ + static const D2D1_COLOR_F test_colours_f[] = + { + {1.0f, 0.0f, 0.0f, 1.0f}, + {0.0f, 1.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 1.0f, 1.0f}, + {1.0f, 0.0f, 1.0f, 1.0f}, + }; + static const DWORD test_colours[] = + { + 0xffff0000, + 0xff00ff00, + 0xff0000ff, + 0xffff00ff, + }; + unsigned int usage = 0, bind_flags = 0, cpu_access_flags = 0, misc_flags = 0; + IDXGISurface *surface, *target_surface; + D2D1_BITMAP_PROPERTIES1 bitmap_desc; + D3D10_TEXTURE2D_DESC texture_desc; + IDXGIResource1 *parent_resource2; + ID3D10Texture2D *parent_texture; + DXGI_SURFACE_DESC surface_desc; + DWORD colour, expected_colour; + D2D1_BITMAP_OPTIONS options; + ID2D1Bitmap1 *target_bitmap; + struct resource_readback rb; + IDXGISurface2 *surface2; + D2D1_SIZE_U pixel_size; + UINT subresource_index; + ID2D1Bitmap1 *bitmap1; + IDXGIObject *object; + D2D1_SIZE_U size; + HRESULT hr; + + hr = ID2D1Bitmap_QueryInterface(bitmap, &IID_ID2D1Bitmap1, (void **)&bitmap1); + ok_(__FILE__, line)(hr == S_OK, "Failed to get bitmap, hr %#lx.\n", hr); + + options = ID2D1Bitmap1_GetOptions(bitmap1); + ok_(__FILE__, line)(options == expect_options, "Got unexpected bitmap options %#x, expected %#lx.\n", + options, expect_options); + + surface = (void *)0xdeadbeef; + hr = ID2D1Bitmap1_GetSurface(bitmap1, &surface); + ok_(__FILE__, line)(hr == S_OK, "Failed to get bitmap surface, hr %#lx.\n", hr); + ok_(__FILE__, line)(!!surface, "Expected surface instance.\n"); + hr = IDXGISurface_QueryInterface(surface, &IID_IDXGISurface2, (void **)&surface2); + ok_(__FILE__, line)(hr == S_OK, "Failed to get surface pointer, hr %#lx.\n", hr); + if (expect_parent_surface) + { + hr = IDXGISurface_QueryInterface(surface, &IID_IDXGIObject, (void **)&object); + ok_(__FILE__, line)(hr == S_OK, "Failed to get object pointer, hr %#lx.\n", hr); + ok_(__FILE__, line)(object == (IDXGIObject *)parent_resource, + "Expected the parent surface being used as the bitmap surface.\n"); + IDXGIObject_Release(object); + check_interface_(line, surface, &IID_ID3D10Texture2D, TRUE); + check_interface_(line, surface, &IID_ID3D11Texture2D, TRUE); + } + else + { + hr = IDXGISurface2_GetResource(surface2, &IID_IDXGIResource1, (void **)&parent_resource2, + &subresource_index); + ok_(__FILE__, line)(hr == S_OK, "Failed to get parent texture pointer, hr %#lx.\n", hr); + ok_(__FILE__, line)(surface != subresource_surface, + "Expected the surface is not the same one used for creating the bitmap.\n"); + ok_(__FILE__, line)(parent_resource2 == parent_resource, + "Expected the bitmap surface is subresource surface of the parent surface.\n"); + IDXGIResource1_Release(parent_resource2); + check_interface_(line, surface, &IID_ID3D10Texture2D, FALSE); + check_interface_(line, surface, &IID_ID3D11Texture2D, FALSE); + } + + hr = IDXGISurface2_GetResource(surface2, &IID_ID3D10Texture2D, (void **)&parent_texture, + &subresource_index); + ok_(__FILE__, line)(hr == S_OK, "Failed to get parent texture pointer, hr %#lx.\n", hr); + ID3D10Texture2D_GetDesc(parent_texture, &texture_desc); + + if (options & D2D1_BITMAP_OPTIONS_TARGET) + bind_flags |= D3D10_BIND_RENDER_TARGET; + if (!(options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW)) + bind_flags |= D3D10_BIND_SHADER_RESOURCE; + if (options & D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE) + misc_flags |= D3D10_RESOURCE_MISC_GDI_COMPATIBLE; + if (options & D2D1_BITMAP_OPTIONS_CPU_READ) + { + usage |= D3D11_USAGE_STAGING; + cpu_access_flags |= D3D11_CPU_ACCESS_READ; + } + + ok_(__FILE__, line)(texture_desc.Usage == usage, "Unexpected usage %#x for bitmap options %#x.\n", + texture_desc.Usage, options); + ok_(__FILE__, line)(texture_desc.BindFlags == bind_flags, + "Unexpected bind flags %#x for bitmap options %#x.\n", texture_desc.BindFlags, options); + ok_(__FILE__, line)(texture_desc.CPUAccessFlags == cpu_access_flags, + "Unexpected cpu access flags %#x for bitmap options %#x.\n", + texture_desc.CPUAccessFlags, options); + ok_(__FILE__, line)(texture_desc.MiscFlags == misc_flags, + "Unexpected misc flags %#x for bitmap options %#x.\n", texture_desc.MiscFlags, options); + + pixel_size = ID2D1Bitmap_GetPixelSize(bitmap); + if (!pixel_size.width || !pixel_size.height) + pixel_size.width = pixel_size.height = 1; + + hr = IDXGISurface2_GetDesc(surface2, &surface_desc); + ok_(__FILE__, line)(hr == S_OK, "Failed to get surface description, hr %#lx.\n", hr); + ok_(__FILE__, line)(surface_desc.Width == pixel_size.width, "Got width %u, expected %u.\n", + surface_desc.Width, pixel_size.width); + ok_(__FILE__, line)(surface_desc.Height == pixel_size.height, "Got height %u, expected %u.\n", + surface_desc.Height, pixel_size.height); + + /* Test drawing with the bitmap created from subresource surface */ + if (options & D2D1_BITMAP_OPTIONS_TARGET) + { + /* Test bitmap as rendering destination */ + ID2D1DeviceContext_BeginDraw(ctx->context); + ID2D1DeviceContext_SetTarget(ctx->context, (ID2D1Image *)bitmap); + ID2D1DeviceContext_Clear(ctx->context, &test_colours_f[subresource_index]); + ID2D1DeviceContext_SetTarget(ctx->context, NULL); + hr = ID2D1DeviceContext_EndDraw(ctx->context, NULL, NULL); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + if ((rb.d3d11 = ctx->d3d11)) + get_d3d11_surface_readback(surface, &rb); + else + get_d3d10_surface_readback(surface, &rb); + colour = get_readback_colour(&rb, 0, 0); + + ok_(__FILE__, line)(compare_colour(colour, test_colours[subresource_index], 1), + "Got unexpected colour %#lx, expected %#lx.\n", colour, test_colours[subresource_index]); + release_resource_readback(&rb); + + /* Test bitmap as rendering source */ + if (!(options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW)) + { + set_size_u(&size, pixel_size.width, pixel_size.height); + bitmap_desc.dpiX = 96.0f; + bitmap_desc.dpiY = 96.0f; + bitmap_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE; + bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET; + bitmap_desc.colorContext = NULL; + hr = ID2D1DeviceContext_CreateBitmap(ctx->context, size, NULL, 0, &bitmap_desc, &target_bitmap); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1Bitmap1_GetSurface(target_bitmap, &target_surface); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID2D1DeviceContext_BeginDraw(ctx->context); + ID2D1DeviceContext_SetTarget(ctx->context, (ID2D1Image *)target_bitmap); + ID2D1DeviceContext_DrawBitmap(ctx->context, bitmap, NULL, 1.0f, + D2D1_INTERPOLATION_MODE_LINEAR, NULL, NULL); + hr = ID2D1DeviceContext_EndDraw(ctx->context, NULL, NULL); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + if ((rb.d3d11 = ctx->d3d11)) + get_d3d11_surface_readback(target_surface, &rb); + else + get_d3d10_surface_readback(target_surface, &rb); + colour = get_readback_colour(&rb, 0, 0); + + expected_colour = succeed_draw ? test_colours[subresource_index] : 0; + todo_wine_if(!succeed_draw || !expect_parent_surface) + ok_(__FILE__, line)(compare_colour(colour, expected_colour, 1), + "Got unexpected colour %#lx, expected %#lx.\n", colour, expected_colour); + release_resource_readback(&rb); + + IDXGISurface_Release(target_surface); + ID2D1Bitmap1_Release(target_bitmap); + } + } + + ID3D10Texture2D_Release(parent_texture); + IDXGISurface2_Release(surface2); + IDXGISurface_Release(surface); + ID2D1Bitmap1_Release(bitmap1); +} + static inline struct geometry_sink *impl_from_ID2D1SimplifiedGeometrySink(ID2D1SimplifiedGeometrySink *iface) { return CONTAINING_RECORD(iface, struct geometry_sink, ID2D1SimplifiedGeometrySink_iface); @@ -14150,11 +14350,38 @@ static void test_bitmap_create(BOOL d3d11) { D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE }, { D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ }, }; + static const struct + { + unsigned int mip_levels; + unsigned int array_size; + unsigned int bind_flags; + unsigned int misc_flags; + unsigned int usage; + unsigned int cpu_access_flags; + unsigned int options; + } subresource_tests[] = + { + {1, 1, D3D10_BIND_RENDER_TARGET, 0, D3D10_USAGE_DEFAULT, 0, D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW}, + {2, 2, D3D10_BIND_RENDER_TARGET, 0, D3D10_USAGE_DEFAULT, 0, D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW}, + {1, 1, D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE, 0, D3D10_USAGE_DEFAULT, 0, D2D1_BITMAP_OPTIONS_TARGET}, + {2, 2, D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE, 0, D3D10_USAGE_DEFAULT, 0, D2D1_BITMAP_OPTIONS_TARGET}, + {1, 1, D3D10_BIND_RENDER_TARGET, D3D10_RESOURCE_MISC_GDI_COMPATIBLE, D3D10_USAGE_DEFAULT, 0 , D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE}, + {1, 2, D3D10_BIND_RENDER_TARGET, D3D10_RESOURCE_MISC_GDI_COMPATIBLE, D3D10_USAGE_DEFAULT, 0 , D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE}, + {1, 1, 0, 0, D3D10_USAGE_STAGING, D3D10_CPU_ACCESS_READ, D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ}, + {2, 2, 0, 0, D3D10_USAGE_STAGING, D3D10_CPU_ACCESS_READ, D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ}, + }; + unsigned int i, j, subresource_count; D2D1_BITMAP_PROPERTIES1 bitmap_desc; + D3D10_TEXTURE2D_DESC texture_desc; struct d2d1_test_context ctx; + BOOL expect_parent_surface; + ID3D10Device *d3d_device; + ID3D10Texture2D *texture; + IDXGIResource1 *resource; + IDXGISurface2 *surface2; + ID2D1Bitmap *bitmap2; ID2D1Bitmap1 *bitmap; D2D1_SIZE_U size; - unsigned int i; HRESULT hr;
if (!init_test_context(&ctx, d3d11)) @@ -14195,6 +14422,73 @@ static void test_bitmap_create(BOOL d3d11) winetest_pop_context(); }
+ /* Subresource surface */ + hr = IDXGIDevice_QueryInterface(ctx.device, &IID_ID3D10Device, (void **)&d3d_device); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(subresource_tests); i++) + { + winetest_push_context("Test %u", i); + + texture_desc.Width = 512; + texture_desc.Height = 512; + texture_desc.MipLevels = subresource_tests[i].mip_levels; + texture_desc.ArraySize = subresource_tests[i].array_size; + texture_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + texture_desc.SampleDesc.Count = 1; + texture_desc.SampleDesc.Quality = 0; + texture_desc.Usage = subresource_tests[i].usage; + texture_desc.BindFlags = subresource_tests[i].bind_flags; + texture_desc.CPUAccessFlags = subresource_tests[i].cpu_access_flags; + texture_desc.MiscFlags = subresource_tests[i].misc_flags; + hr = ID3D10Device_CreateTexture2D(d3d_device, &texture_desc, NULL, &texture); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID3D10Texture2D_QueryInterface(texture, &IID_IDXGIResource1, (void **)&resource); + ID3D10Texture2D_Release(texture); + + subresource_count = subresource_tests[i].mip_levels * subresource_tests[i].array_size; + expect_parent_surface = subresource_count == 1; + for (j = 0; j < subresource_count; j++) + { + winetest_push_context("Subtest %u", j); + + hr = IDXGIResource1_CreateSubresourceSurface(resource, j, &surface2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + memset(&bitmap_desc, 0, sizeof(bitmap_desc)); + bitmap_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE; + bitmap_desc.bitmapOptions = subresource_tests[i].options; + hr = ID2D1DeviceContext_CreateSharedBitmap(ctx.context, &IID_IDXGISurface2, surface2, + (const D2D1_BITMAP_PROPERTIES *)&bitmap_desc, &bitmap2); + todo_wine + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_bitmap_subresource_surface(&ctx, bitmap2, resource, (IDXGISurface *)surface2, + expect_parent_surface, subresource_tests[i].options, TRUE); + ID2D1Bitmap_Release(bitmap2); + } + + hr = ID2D1DeviceContext_CreateBitmapFromDxgiSurface(ctx.context, + (IDXGISurface *)surface2, &bitmap_desc, &bitmap); + todo_wine + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + check_bitmap_subresource_surface(&ctx, (ID2D1Bitmap *)bitmap, resource, + (IDXGISurface *)surface2, expect_parent_surface, subresource_tests[i].options, FALSE); + ID2D1Bitmap1_Release(bitmap); + } + + IDXGISurface2_Release(surface2); + winetest_pop_context(); + } + IDXGIResource1_Release(resource); + winetest_pop_context(); + } + + ID3D10Device_Release(d3d_device); release_test_context(&ctx); }
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/d2d1/bitmap.c | 209 +++++++++++++++++++++++++++++++---- dlls/d2d1/d2d1_private.h | 3 + dlls/d2d1/dc_render_target.c | 3 +- dlls/d2d1/device.c | 14 ++- dlls/d2d1/tests/d2d1.c | 20 +--- 5 files changed, 213 insertions(+), 36 deletions(-)
diff --git a/dlls/d2d1/bitmap.c b/dlls/d2d1/bitmap.c index e5048611519..64d213bdeb6 100644 --- a/dlls/d2d1/bitmap.c +++ b/dlls/d2d1/bitmap.c @@ -36,7 +36,7 @@ static HRESULT d2d_bitmap_unmap(struct d2d_bitmap *bitmap)
ID3D11Resource_GetDevice(bitmap->resource, &device); ID3D11Device_GetImmediateContext(device, &context); - ID3D11DeviceContext_Unmap(context, bitmap->resource, 0); + ID3D11DeviceContext_Unmap(context, bitmap->resource, bitmap->subresource_idx == ~0u ? 0 : bitmap->subresource_idx); ID3D11DeviceContext_Release(context); ID3D11Device_Release(device);
@@ -172,9 +172,11 @@ static HRESULT STDMETHODCALLTYPE d2d_bitmap_CopyFromBitmap(ID2D1Bitmap1 *iface,
ID3D11Resource_GetDevice(dst_bitmap->resource, &device); ID3D11Device_GetImmediateContext(device, &context); - ID3D11DeviceContext_CopySubresourceRegion(context, dst_bitmap->resource, 0, - dst_point ? dst_point->x : 0, dst_point ? dst_point->y : 0, 0, - src_bitmap->resource, 0, src_rect ? &box : NULL); + ID3D11DeviceContext_CopySubresourceRegion(context, dst_bitmap->resource, + dst_bitmap->subresource_idx == ~0u ? 0 : dst_bitmap->subresource_idx, + dst_point ? dst_point->x : 0, dst_point ? dst_point->y : 0, + 0, src_bitmap->resource, src_bitmap->subresource_idx == ~0u ? 0 : src_bitmap->subresource_idx, + src_rect ? &box : NULL); ID3D11DeviceContext_Release(context); ID3D11Device_Release(device);
@@ -211,7 +213,9 @@ static HRESULT STDMETHODCALLTYPE d2d_bitmap_CopyFromMemory(ID2D1Bitmap1 *iface,
ID3D11Resource_GetDevice(bitmap->resource, &device); ID3D11Device_GetImmediateContext(device, &context); - ID3D11DeviceContext_UpdateSubresource(context, bitmap->resource, 0, dst_rect ? &box : NULL, src_data, pitch, 0); + ID3D11DeviceContext_UpdateSubresource(context, bitmap->resource, + bitmap->subresource_idx == ~0u ? 0 : bitmap->subresource_idx, dst_rect ? &box : NULL, + src_data, pitch, 0); ID3D11DeviceContext_Release(context); ID3D11Device_Release(device);
@@ -279,8 +283,8 @@ static HRESULT STDMETHODCALLTYPE d2d_bitmap_Map(ID2D1Bitmap1 *iface, D2D1_MAP_OP
ID3D11Resource_GetDevice(bitmap->resource, &device); ID3D11Device_GetImmediateContext(device, &context); - if (SUCCEEDED(hr = ID3D11DeviceContext_Map(context, bitmap->resource, 0, map_type, - 0, &mapped_resource))) + if (SUCCEEDED(hr = ID3D11DeviceContext_Map(context, bitmap->resource, + bitmap->subresource_idx == ~0u ? 0 : bitmap->subresource_idx, map_type, 0, &mapped_resource))) { bitmap->mapped_resource = mapped_resource; } @@ -363,8 +367,143 @@ static BOOL format_supported(const D2D1_PIXEL_FORMAT *format) return FALSE; }
+HRESULT d2d_get_surface_from_resource(ID3D11Resource *resource, UINT subresource_idx, + REFIID surface_iid, void **surface) +{ + IDXGIResource1 *resource1; + IDXGISurface2 *surface2; + HRESULT hr; + + if (SUCCEEDED(ID3D11Resource_QueryInterface(resource, surface_iid, surface))) + return S_OK; + + /* Resource has multiple mipmap levels or array. Query for the subresource surface instead */ + if (FAILED(hr = ID3D11Resource_QueryInterface(resource, &IID_IDXGIResource1, (void **)&resource1))) + return hr; + + if (FAILED(hr = IDXGIResource1_CreateSubresourceSurface(resource1, subresource_idx, &surface2))) + { + IDXGIResource1_Release(resource1); + return hr; + } + + hr = IDXGISurface2_QueryInterface(surface2, surface_iid, surface); + IDXGISurface2_Release(surface2); + IDXGIResource1_Release(resource1); + return hr; +} + +HRESULT d2d_get_resource_from_surface(IDXGISurface *surface, REFIID resource_iid, + UINT *subresource_idx, void **resource) +{ + IDXGISurface2 *surface2; + UINT index; + HRESULT hr; + + if (subresource_idx) + *subresource_idx = ~0u; + + if (SUCCEEDED(IDXGISurface_QueryInterface(surface, resource_iid, resource))) + return S_OK; + + /* Get the parent resource if the surface is a subresource surface */ + if (FAILED(hr = IDXGISurface_QueryInterface(surface, &IID_IDXGISurface2, (void **)&surface2))) + return hr; + + hr = IDXGISurface2_GetResource(surface2, resource_iid, resource, &index); + if (SUCCEEDED(hr) && subresource_idx) + *subresource_idx = index; + IDXGISurface2_Release(surface2); + return hr; +} + +static void d2d_resource_get_rtv_desc(ID3D11Resource *resource, UINT subresource_idx, + D3D11_RENDER_TARGET_VIEW_DESC *rtv_desc) +{ + D3D11_TEXTURE2D_DESC texture_desc; + ID3D11Texture2D *texture; + + ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&texture); + ID3D11Texture2D_GetDesc(texture, &texture_desc); + ID3D11Texture2D_Release(texture); + + rtv_desc->Format = texture_desc.Format; + if (texture_desc.ArraySize > 1) + { + if (texture_desc.SampleDesc.Count == 1) + { + rtv_desc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtv_desc->Texture2DArray.MipSlice = subresource_idx % texture_desc.MipLevels; + rtv_desc->Texture2DArray.FirstArraySlice = subresource_idx / texture_desc.MipLevels; + rtv_desc->Texture2DArray.ArraySize = 1; + } + else + { + rtv_desc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY; + rtv_desc->Texture2DMSArray.FirstArraySlice = subresource_idx; + rtv_desc->Texture2DMSArray.ArraySize = 1; + } + } + else + { + if (texture_desc.SampleDesc.Count == 1) + { + rtv_desc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtv_desc->Texture2D.MipSlice = subresource_idx; + } + else + { + rtv_desc->ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS; + } + } +} + +static void d2d_resource_get_srv_desc(ID3D11Resource *resource, UINT subresource_idx, + D3D11_SHADER_RESOURCE_VIEW_DESC *srv_desc) +{ + D3D11_TEXTURE2D_DESC texture_desc; + ID3D11Texture2D *texture; + + ID3D11Resource_QueryInterface(resource, &IID_ID3D11Texture2D, (void **)&texture); + ID3D11Texture2D_GetDesc(texture, &texture_desc); + ID3D11Texture2D_Release(texture); + + srv_desc->Format = texture_desc.Format; + if (texture_desc.ArraySize > 1) + { + if (texture_desc.SampleDesc.Count == 1) + { + srv_desc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srv_desc->Texture2DArray.MostDetailedMip = subresource_idx % texture_desc.MipLevels; + srv_desc->Texture2DArray.FirstArraySlice = subresource_idx / texture_desc.MipLevels; + srv_desc->Texture2DArray.MipLevels = 1; + srv_desc->Texture2DArray.ArraySize = 1; + } + else + { + srv_desc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; + srv_desc->Texture2DMSArray.FirstArraySlice = subresource_idx; + srv_desc->Texture2DMSArray.ArraySize = 1; + } + } + else + { + if (texture_desc.SampleDesc.Count == 1) + { + srv_desc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srv_desc->Texture2D.MostDetailedMip = subresource_idx; + srv_desc->Texture2D.MipLevels = 1; + } + else + { + srv_desc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMS; + } + } +} + static void d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_device_context *context, - ID3D11Resource *resource, D2D1_SIZE_U size, const D2D1_BITMAP_PROPERTIES1 *desc) + ID3D11Resource *resource, UINT subresource_idx, D2D1_SIZE_U size, + const D2D1_BITMAP_PROPERTIES1 *desc) { ID3D11Device *d3d_device; HRESULT hr; @@ -373,6 +512,7 @@ static void d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_device_context bitmap->refcount = 1; ID2D1Factory_AddRef(bitmap->factory = context->factory); ID3D11Resource_AddRef(bitmap->resource = resource); + bitmap->subresource_idx = subresource_idx; bitmap->pixel_size = size; bitmap->format = desc->pixelFormat; bitmap->dpi_x = desc->dpiX; @@ -380,18 +520,42 @@ static void d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_device_context bitmap->options = desc->bitmapOptions;
if (d2d_device_context_is_dxgi_target(context)) - ID3D11Resource_QueryInterface(resource, &IID_IDXGISurface, (void **)&bitmap->surface); + d2d_get_surface_from_resource(resource, subresource_idx, &IID_IDXGISurface, (void **)&bitmap->surface);
ID3D11Resource_GetDevice(resource, &d3d_device); if (bitmap->options & D2D1_BITMAP_OPTIONS_TARGET) { - if (FAILED(hr = ID3D11Device_CreateRenderTargetView(d3d_device, resource, NULL, &bitmap->rtv))) + if (subresource_idx != ~0u) + { + D3D11_RENDER_TARGET_VIEW_DESC rtv_desc; + + d2d_resource_get_rtv_desc(resource, subresource_idx, &rtv_desc); + hr = ID3D11Device_CreateRenderTargetView(d3d_device, resource, &rtv_desc, &bitmap->rtv); + } + else + { + hr = ID3D11Device_CreateRenderTargetView(d3d_device, resource, NULL, &bitmap->rtv); + } + + if (FAILED(hr)) WARN("Failed to create RTV, hr %#lx.\n", hr); }
if (!(bitmap->options & D2D1_BITMAP_OPTIONS_CANNOT_DRAW)) { - if (FAILED(hr = ID3D11Device_CreateShaderResourceView(d3d_device, resource, NULL, &bitmap->srv))) + if (subresource_idx != ~0u) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc; + + d2d_resource_get_srv_desc(resource, subresource_idx, &srv_desc); + hr = ID3D11Device_CreateShaderResourceView(d3d_device, resource, &srv_desc, &bitmap->srv); + } + else + { + hr = ID3D11Device_CreateShaderResourceView(d3d_device, resource, NULL, &bitmap->srv); + } + + if (FAILED(hr)) WARN("Failed to create SRV, hr %#lx.\n", hr); } ID3D11Device_Release(d3d_device); @@ -487,7 +651,7 @@ HRESULT d2d_bitmap_create(struct d2d_device_context *context, D2D1_SIZE_U size,
if ((*bitmap = calloc(1, sizeof(**bitmap)))) { - d2d_bitmap_init(*bitmap, context, (ID3D11Resource *)texture, size, desc); + d2d_bitmap_init(*bitmap, context, (ID3D11Resource *)texture, ~0u, size, desc); TRACE("Created bitmap %p.\n", *bitmap); } ID3D11Texture2D_Release(texture); @@ -501,7 +665,7 @@ unsigned int d2d_get_bitmap_options_for_surface(IDXGISurface *surface) unsigned int options = 0; ID3D11Texture2D *texture;
- if (FAILED(IDXGISurface_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture))) + if (FAILED(d2d_get_resource_from_surface(surface, &IID_ID3D11Texture2D, NULL, (void **)&texture))) return 0;
ID3D11Texture2D_GetDesc(texture, &desc); @@ -576,27 +740,34 @@ HRESULT d2d_bitmap_create_shared(struct d2d_device_context *context, REFIID iid, goto failed; }
- d2d_bitmap_init(*bitmap, context, src_impl->resource, src_impl->pixel_size, desc); + d2d_bitmap_init(*bitmap, context, src_impl->resource, src_impl->subresource_idx, + src_impl->pixel_size, desc); TRACE("Created bitmap %p.\n", *bitmap);
failed: return hr; }
- if (IsEqualGUID(iid, &IID_IDXGISurface) || IsEqualGUID(iid, &IID_IDXGISurface1)) + if (IsEqualGUID(iid, &IID_IDXGISurface) || IsEqualGUID(iid, &IID_IDXGISurface1) + || IsEqualGUID(iid, &IID_IDXGISurface2)) { DXGI_SURFACE_DESC surface_desc; IDXGISurface *surface = data; + UINT subresource_idx = ~0u; + ID3D11Texture2D *texture; ID3D11Resource *resource; D2D1_SIZE_U pixel_size; ID3D11Device *device; HRESULT hr;
- if (FAILED(IDXGISurface_QueryInterface(surface, &IID_ID3D11Resource, (void **)&resource))) + if (FAILED(hr = d2d_get_resource_from_surface(surface, &IID_ID3D11Texture2D, &subresource_idx, + (void **)&texture))) { - WARN("Failed to get d3d resource from dxgi surface.\n"); - return E_FAIL; + WARN("Surface is not from a 2D texture, hr %#lx.\n", hr); + return hr; } + ID3D11Texture2D_QueryInterface(texture, &IID_ID3D11Resource, (void **)&resource); + ID3D11Texture2D_Release(texture);
ID3D11Resource_GetDevice(resource, &device); ID3D11Device_Release(device); @@ -644,7 +815,7 @@ HRESULT d2d_bitmap_create_shared(struct d2d_device_context *context, REFIID iid, pixel_size.width = surface_desc.Width; pixel_size.height = surface_desc.Height;
- d2d_bitmap_init(*bitmap, context, resource, pixel_size, &d); + d2d_bitmap_init(*bitmap, context, resource, subresource_idx, pixel_size, &d); ID3D11Resource_Release(resource); TRACE("Created bitmap %p.\n", *bitmap);
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 46999eaa272..ca0c6a1333b 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -430,6 +430,7 @@ struct d2d_bitmap ID3D11RenderTargetView *rtv; IDXGISurface *surface; ID3D11Resource *resource; + UINT subresource_idx; D3D11_MAPPED_SUBRESOURCE mapped_resource; D2D1_SIZE_U pixel_size; D2D1_PIXEL_FORMAT format; @@ -446,6 +447,8 @@ HRESULT d2d_bitmap_create_from_wic_bitmap(struct d2d_device_context *context, IW const D2D1_BITMAP_PROPERTIES1 *desc, struct d2d_bitmap **bitmap); unsigned int d2d_get_bitmap_options_for_surface(IDXGISurface *surface); struct d2d_bitmap *unsafe_impl_from_ID2D1Bitmap(ID2D1Bitmap *iface); +HRESULT d2d_get_surface_from_resource(ID3D11Resource *resource, UINT subresource_idx, REFIID surface_iid, void **surface); +HRESULT d2d_get_resource_from_surface(IDXGISurface *surface, REFIID resource_iid, UINT *subresource_idx, void **resource);
struct d2d_state_block { diff --git a/dlls/d2d1/dc_render_target.c b/dlls/d2d1/dc_render_target.c index b09b77ff788..d8028b016ac 100644 --- a/dlls/d2d1/dc_render_target.c +++ b/dlls/d2d1/dc_render_target.c @@ -751,7 +751,8 @@ static HRESULT STDMETHODCALLTYPE d2d_dc_render_target_BindDC(ID2D1DCRenderTarget }
bitmap_impl = unsafe_impl_from_ID2D1Bitmap(bitmap); - ID3D11Resource_QueryInterface(bitmap_impl->resource, &IID_IDXGISurface1, (void **)&dxgi_surface); + d2d_get_surface_from_resource(bitmap_impl->resource, bitmap_impl->subresource_idx, + &IID_IDXGISurface1, (void **)&dxgi_surface);
ID2D1DeviceContext_SetTarget(context, (ID2D1Image *)bitmap); ID2D1Bitmap_Release(bitmap); diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 59e93bfac38..512ca00df86 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -418,7 +418,8 @@ static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateSharedBitmap(ID2D1Devi if (desc) { memcpy(&bitmap_desc, desc, sizeof(*desc)); - if (IsEqualIID(iid, &IID_IDXGISurface) || IsEqualIID(iid, &IID_IDXGISurface1)) + if (IsEqualIID(iid, &IID_IDXGISurface) || IsEqualIID(iid, &IID_IDXGISurface1) + || IsEqualIID(iid, &IID_IDXGISurface2)) bitmap_desc.bitmapOptions = d2d_get_bitmap_options_for_surface(data); else bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW; @@ -2204,10 +2205,18 @@ static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateBitmapFromDxgiSurface( D2D1_BITMAP_PROPERTIES1 bitmap_desc; unsigned int surface_options; struct d2d_bitmap *object; + ID3D11Texture2D *texture; HRESULT hr;
TRACE("iface %p, surface %p, desc %p, bitmap %p.\n", iface, surface, desc, bitmap);
+ if (FAILED(hr = d2d_get_resource_from_surface(surface, &IID_ID3D11Texture2D, NULL, (void **)&texture))) + { + WARN("Surface is not from a 2D texture, hr %#lx.\n", hr); + return hr; + } + ID3D11Texture2D_Release(texture); + surface_options = d2d_get_bitmap_options_for_surface(surface);
if (desc) @@ -3460,7 +3469,8 @@ static HRESULT d2d_gdi_interop_get_surface(struct d2d_device_context *context, I return D2DERR_TARGET_NOT_GDI_COMPATIBLE;
ID3D11RenderTargetView_GetResource(context->target.bitmap->rtv, &resource); - hr = ID3D11Resource_QueryInterface(resource, &IID_IDXGISurface1, (void **)surface); + hr = d2d_get_surface_from_resource(resource, context->target.bitmap->subresource_idx, + &IID_IDXGISurface1, (void **)surface); ID3D11Resource_Release(resource); if (FAILED(hr)) { diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index f0900770271..df2da707ec9 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -14461,25 +14461,17 @@ static void test_bitmap_create(BOOL d3d11) bitmap_desc.bitmapOptions = subresource_tests[i].options; hr = ID2D1DeviceContext_CreateSharedBitmap(ctx.context, &IID_IDXGISurface2, surface2, (const D2D1_BITMAP_PROPERTIES *)&bitmap_desc, &bitmap2); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - check_bitmap_subresource_surface(&ctx, bitmap2, resource, (IDXGISurface *)surface2, - expect_parent_surface, subresource_tests[i].options, TRUE); - ID2D1Bitmap_Release(bitmap2); - } + check_bitmap_subresource_surface(&ctx, bitmap2, resource, (IDXGISurface *)surface2, + expect_parent_surface, subresource_tests[i].options, TRUE); + ID2D1Bitmap_Release(bitmap2);
hr = ID2D1DeviceContext_CreateBitmapFromDxgiSurface(ctx.context, (IDXGISurface *)surface2, &bitmap_desc, &bitmap); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - check_bitmap_subresource_surface(&ctx, (ID2D1Bitmap *)bitmap, resource, - (IDXGISurface *)surface2, expect_parent_surface, subresource_tests[i].options, FALSE); - ID2D1Bitmap1_Release(bitmap); - } + check_bitmap_subresource_surface(&ctx, (ID2D1Bitmap *)bitmap, resource, + (IDXGISurface *)surface2, expect_parent_surface, subresource_tests[i].options, FALSE); + ID2D1Bitmap1_Release(bitmap);
IDXGISurface2_Release(surface2); winetest_pop_context();
Which one of those are actually used by React Native?
React Native uses a subresource surface created from a 2d texture with one subresource. So it's `D3D11_SRV_DIMENSION_TEXTURE2D` with `MostDetailedMip` being 0.
I'd rather we keep it as simple as possible. I'm especially unsure about MS case, if it supposed to work at all.
But removing other cases will certainly break them.
On Tue Jun 10 10:01:37 2025 +0000, Zhiyi Zhang wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/8243/diffs?diff_id=184181&start_sha=f696f8bd4966fdf8542664e614844da0ed9e0f0c#0a5641ba01f61e9eda969890860e19c2269a989a_14299_14355)
It's a 2D texture with only a single subresource.
On Mon Jun 9 11:17:58 2025 +0000, Nikolay Sivov wrote:
Checking every subresource seems unnecessary. I think it's enough to have tests for count>1 and index=1. Case for count==1 is the same as our existing tests, right?
The case for textures with only one subresource has a special behavior. For example, you can create a subresource surface from a surface with only one subresource. And then you create a bitmap from the subresource surface. After that, ID2D1Bitmap1_GetSurface() for the bitmap returns the parent surface, not the subresource surface. This is checked by `expect_parent_surface` in `check_bitmap_subresource_surface`.
For other cases, they are used to cover d2d_resource_get_rtv/srv_desc(). 4 subsoureces are not that many. So I think it's better to just test all subresources.
On Tue Jun 10 10:01:40 2025 +0000, Nikolay Sivov wrote:
Important thing this isn't testing is using such bitmaps for rendering. If 2DArray should work, we should have a test for e.g. 3 elements initialized to different color, and used with DrawBitmap(). This would be a short test.
I added tests for rendering such bitmaps. The results are a bit strange.
On Windows, DrawBitmap() with such bitmaps created from CreateBitmapFromDxgiSurface() with subresource surfaces renders black. For example, see [draw_bitmap_from_dxgi_surface.txt](/uploads/da66fbd5c8ff33486fd63b38ac25b2d1/draw_bitmap_from_dxgi_surface.txt). DrawBitmap() with such bitmaps created from CreateSharedBitmap() with subresource surfaces does work on Windows. So, CreateBitmapFromDxgiSurface() on Windows doesn't create an SRV?
On Wine, DrawBitmap() with bitmaps created from subresource surfaces with more than one subresource doesn't work. The color channels are all black. It looks like DrawBitmap() failed somehow. I checked d2d_resource_get_srv_desc(), and it seems fine. Thus, the problem must lie somewhere else. I've marked the rendering tests as todo_wine for now.
On Tue Jun 10 10:01:39 2025 +0000, Zhiyi Zhang wrote:
I added tests for rendering such bitmaps. The results are a bit strange. On Windows, DrawBitmap() with such bitmaps created from CreateBitmapFromDxgiSurface() with subresource surfaces renders black. For example, see [draw_bitmap_from_dxgi_surface.txt](/uploads/da66fbd5c8ff33486fd63b38ac25b2d1/draw_bitmap_from_dxgi_surface.txt). DrawBitmap() with such bitmaps created from CreateSharedBitmap() with subresource surfaces does work on Windows. So, CreateBitmapFromDxgiSurface() on Windows doesn't create an SRV? On Wine, DrawBitmap() with bitmaps created from subresource surfaces with more than one subresource doesn't work. The color channels are all black. It looks like DrawBitmap() failed somehow. I checked d2d_resource_get_srv_desc(), and it seems fine. Thus, the problem must lie somewhere else. I've marked the rendering tests as todo_wine for now.
I think we need to figure out why they don't work. Using pattern that React Native uses as a start. If we can't render them and we should be able to, it doesn't matter if we can create bitmaps or not, the result won't be useful.
On Tue Jun 10 10:21:49 2025 +0000, Nikolay Sivov wrote:
I think we need to figure out why they don't work. Using pattern that React Native uses as a start. If we can't render them and we should be able to, it doesn't matter if we can create bitmaps or not, the result won't be useful.
Okay. I will look into it.
On Tue Jun 10 10:28:14 2025 +0000, Zhiyi Zhang wrote:
Okay. I will look into it.
React Native creates a bitmap from a DXGI surface with only one subresource. And drawing such a bitmap is fine. So it's not the reason why React Native applications fail to render.
On Fri Jun 13 02:45:29 2025 +0000, Zhiyi Zhang wrote:
React Native creates a bitmap from a DXGI surface with only one subresource. And drawing such a bitmap is fine. So it's not the reason why React Native applications fail to render.
The reason why DrawBitmap() with bitmaps created from subresource surfaces with more than one subresource doesn't work is because `Texture2D` is used in `shape_ps_code`. When the texture is a 2d texture array. `Texture2DArray` needs to be used in the pixel shader.
As for DrawBitmap() with a bitmap created from CreateBitmapFromDxgiSurface() has no effect on Windows, I think it's a special behavior. I don't see any issue in my tests. I also tried a few other things, like changing texture format, using ID2D1RenderTarget instead of ID2D1DeviceContext. A bitmap brush from such a bitmap also doesn't work when used to fill. See [d2d_bitmap_from_dxgi_surface.txt](/uploads/3f94bbfd78a4748a7528cf6c4919b916/d2d_bitmap_from_dxgi_surface.txt). However, I am not sure we want to mimic this behavior on Wine. If we want to change it, then we need to disallow creating an SRV for bitmaps from CreateBitmapFromDxgiSurface(). We also need to disable any drawing operations when such a bitmap is used, for example, opacity brushes shouldn't have any effect as well. Overall, I prefer leaving it unchanged for now.