For React Native
-- v3: 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..279b4d9e865 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) + 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 | 206 +++++++++++++++++++++++++++++++---- dlls/d2d1/d2d1_private.h | 3 + dlls/d2d1/dc_render_target.c | 3 +- dlls/d2d1/device.c | 22 +++- dlls/d2d1/tests/d2d1.c | 20 +--- 5 files changed, 214 insertions(+), 40 deletions(-)
diff --git a/dlls/d2d1/bitmap.c b/dlls/d2d1/bitmap.c index e5048611519..047be8879eb 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,149 @@ 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; + + /* Always use 2d texture array view dimension even if it's not a 2d texture array. See shape_ps_code. */ + if (subresource_idx == ~0u) + { + if (texture_desc.SampleDesc.Count == 1) + { + srv_desc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srv_desc->Texture2DArray.MostDetailedMip = 0; + srv_desc->Texture2DArray.FirstArraySlice = 0; + srv_desc->Texture2DArray.MipLevels = texture_desc.MipLevels; + srv_desc->Texture2DArray.ArraySize = texture_desc.ArraySize; + } + else + { + srv_desc->ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; + srv_desc->Texture2DMSArray.FirstArraySlice = 0; + srv_desc->Texture2DMSArray.ArraySize = texture_desc.ArraySize; + } + } + else + { + 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; + } + } +} + 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 +518,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 +526,33 @@ 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))) + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc; + + d2d_resource_get_srv_desc(resource, subresource_idx, &srv_desc); + if (FAILED(hr = ID3D11Device_CreateShaderResourceView(d3d_device, resource, &srv_desc, &bitmap->srv))) WARN("Failed to create SRV, hr %#lx.\n", hr); } ID3D11Device_Release(d3d_device); @@ -487,7 +648,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 +662,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 +737,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 +812,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..f1472fa7c9f 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)) { @@ -3815,7 +3825,7 @@ static const char shape_ps_code[] = "} colour_brush, opacity_brush;\n" "\n" "SamplerState s0, s1;\n" - "Texture2D t0, t1;\n" + "Texture2DArray t0, t1;\n" "Buffer<float4> b0, b1;\n" "\n" "struct input\n" @@ -3904,7 +3914,7 @@ static const char shape_ps_code[] = " return sample_gradient(gradient, stop_count, l / t);\n" "}\n" "\n" - "float4 brush_bitmap(struct brush brush, Texture2D t, SamplerState s, float2 position)\n" + "float4 brush_bitmap(struct brush brush, Texture2DArray t, SamplerState s, float2 position)\n" "{\n" " float3 transform[2];\n" " bool ignore_alpha;\n" @@ -3917,13 +3927,13 @@ static const char shape_ps_code[] = "\n" " texcoord.x = dot(position.xy, transform[0].xy) + transform[0].z;\n" " texcoord.y = dot(position.xy, transform[1].xy) + transform[1].z;\n" - " colour = t.Sample(s, texcoord);\n" + " colour = t.Sample(s, float3(texcoord, 0.0));\n" " if (ignore_alpha)\n" " colour.a = 1.0;\n" " return colour;\n" "}\n" "\n" - "float4 sample_brush(struct brush brush, Texture2D t, SamplerState s, Buffer<float4> b, float2 position)\n" + "float4 sample_brush(struct brush brush, Texture2DArray t, SamplerState s, Buffer<float4> b, float2 position)\n" "{\n" " if (brush.type == BRUSH_TYPE_SOLID)\n" " return brush.data[0] * brush.opacity;\n" diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 279b4d9e865..3693f07c796 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();
On Mon Jul 14 12:59:39 2025 +0000, Zhiyi Zhang wrote:
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.
So, does it work on Windows for a case with more than one subresource or not? If All we need to support index == 0, we don't need that many changes.
On Mon Jul 14 12:59:39 2025 +0000, Nikolay Sivov wrote:
So, does it work on Windows for a case with more than one subresource or not? If All we need to support index == 0, we don't need that many changes.
Drawing a bitmap from a DXGI subresource surface with more than one subresource does work on Windows. However, the bitmap must be created with ID2D1DeviceContext_CreateSharedBitmap, not ID2D1DeviceContext_CreateBitmapFromDxgiSurface.
On Mon Jul 21 06:32:52 2025 +0000, Zhiyi Zhang wrote:
Drawing a bitmap from a DXGI subresource surface with more than one subresource does work on Windows. However, the bitmap must be created with ID2D1DeviceContext_CreateSharedBitmap, not ID2D1DeviceContext_CreateBitmapFromDxgiSurface.
I still don't think you can simply use Texture2DArray, for effects to work for example there is a convention that you use Texture2D I believe. There are some templates in SDK for that.
On Mon Jul 21 07:39:37 2025 +0000, Nikolay Sivov wrote:
I still don't think you can simply use Texture2DArray, for effects to work for example there is a convention that you use Texture2D I believe. There are some templates in SDK for that.
Okay. React Native only needs subresource surface from index 0 at this point. Is it okay if I only add subresource surface from index 0 support for D2D?