For React Native.
-- v2: d2d1: Implement d2d_device_GetDxgiDevice(). d2d1: Remove an unnecessary cast in d2d_device_context_init(). d2d1/tests: Add ID2D1Device2_GetDxgiDevice() tests.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/d2d1/tests/d2d1.c | 166 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 625ad53292f..011e1d51ccc 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15439,6 +15439,171 @@ static void test_effect_blob_property(BOOL d3d11) release_test_context(&ctx); }
+static void test_get_dxgi_device(BOOL d3d11) +{ + D2D1_HWND_RENDER_TARGET_PROPERTIES hwnd_rt_desc; + D2D1_RENDER_TARGET_PROPERTIES rt_desc; + D2D1_RENDER_TARGET_PROPERTIES desc; + IWICImagingFactory *wic_factory; + ID2D1HwndRenderTarget *hwnd_rt; + struct d2d1_test_context ctx; + ID2D1DeviceContext *context; + IDXGIDevice *dxgi_device; + IWICBitmap *wic_bitmap; + ID2D1Device2 *device2; + ID2D1RenderTarget *rt; + ID2D1Device *device; + HRESULT hr; + + if (!init_test_context(&ctx, d3d11)) + return; + + if (!ctx.factory1) + { + win_skip("ID2D1Factory1 is not supported.\n"); + release_test_context(&ctx); + return; + } + + /* Test user-provided DXGI device */ + hr = ID2D1Factory1_CreateDevice(ctx.factory1, ctx.device, &device); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1Device_QueryInterface(device, &IID_ID2D1Device2, (void **)&device2); + if (FAILED(hr)) + { + win_skip("ID2D1Device2 is not supported.\n"); + ID2D1Device_Release(device); + release_test_context(&ctx); + return; + } + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); + todo_wine + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(dxgi_device == ctx.device, "Got unexpected IDXGIDevice.\n"); + IDXGIDevice_Release(dxgi_device); + } + + ID2D1Device2_Release(device2); + ID2D1Device_Release(device); + + /* WIC target */ + rt_desc.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; + rt_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + rt_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; + rt_desc.dpiX = 96.0f; + rt_desc.dpiY = 96.0f; + rt_desc.usage = D2D1_RENDER_TARGET_USAGE_NONE; + rt_desc.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&wic_factory); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IWICImagingFactory_CreateBitmap(wic_factory, 16, 16, &GUID_WICPixelFormat32bppPBGRA, + WICBitmapCacheOnDemand, &wic_bitmap); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1Factory1_CreateWicBitmapRenderTarget(ctx.factory1, wic_bitmap, &rt_desc, &rt); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1RenderTarget_QueryInterface(rt, &IID_ID2D1DeviceContext, (void **)&context); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID2D1DeviceContext_GetDevice(context, &device); + hr = ID2D1Device_QueryInterface(device, &IID_ID2D1Device2, (void **)&device2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); + todo_wine + ok(hr == D2DERR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + ID2D1Device2_Release(device2); + ID2D1Device_Release(device); + ID2D1DeviceContext_Release(context); + ID2D1RenderTarget_Release(rt); + IWICBitmap_Release(wic_bitmap); + IWICImagingFactory_Release(wic_factory); + CoUninitialize(); + + /* HWND target */ + desc.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; + desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; + desc.dpiX = 0.0f; + desc.dpiY = 0.0f; + desc.usage = D2D1_RENDER_TARGET_USAGE_NONE; + desc.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; + + hwnd_rt_desc.hwnd = create_window(); + hwnd_rt_desc.pixelSize.width = 64; + hwnd_rt_desc.pixelSize.height = 64; + hwnd_rt_desc.presentOptions = D2D1_PRESENT_OPTIONS_NONE; + + hr = ID2D1Factory_CreateHwndRenderTarget(ctx.factory, &desc, &hwnd_rt_desc, &hwnd_rt); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1HwndRenderTarget_QueryInterface(hwnd_rt, &IID_ID2D1DeviceContext, (void **)&context); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID2D1DeviceContext_GetDevice(context, &device); + hr = ID2D1Device_QueryInterface(device, &IID_ID2D1Device2, (void **)&device2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); + todo_wine + ok(hr == D2DERR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + ID2D1Device2_Release(device2); + ID2D1Device_Release(device); + ID2D1DeviceContext_Release(context); + ID2D1HwndRenderTarget_Release(hwnd_rt); + DestroyWindow(hwnd_rt_desc.hwnd); + + /* DXGI surface target */ + ID2D1DeviceContext_GetDevice(ctx.context, &device); + hr = ID2D1Device_QueryInterface(device, &IID_ID2D1Device2, (void **)&device2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); + todo_wine + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(dxgi_device == ctx.device, "Got unexpected IDXGIDevice.\n"); + IDXGIDevice_Release(dxgi_device); + } + + ID2D1Device2_Release(device2); + ID2D1Device_Release(device); + + /* DC target */ + rt_desc.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; + rt_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + rt_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; + rt_desc.dpiX = 96.0f; + rt_desc.dpiY = 96.0f; + rt_desc.usage = D2D1_RENDER_TARGET_USAGE_NONE; + rt_desc.minLevel = D2D1_FEATURE_LEVEL_DEFAULT; + + hr = ID2D1Factory1_CreateDCRenderTarget(ctx.factory1, &rt_desc, (ID2D1DCRenderTarget **)&rt); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1RenderTarget_QueryInterface(rt, &IID_ID2D1DeviceContext, (void **)&context); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ID2D1DeviceContext_GetDevice(context, &device); + hr = ID2D1Device_QueryInterface(device, &IID_ID2D1Device2, (void **)&device2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); + todo_wine + ok(hr == D2DERR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + ID2D1Device2_Release(device2); + ID2D1Device_Release(device); + ID2D1DeviceContext_Release(context); + ID2D1RenderTarget_Release(rt); + + release_test_context(&ctx); +} + START_TEST(d2d1) { HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); @@ -15536,6 +15701,7 @@ START_TEST(d2d1) queue_test(test_compute_geometry_area); queue_test(test_wic_target_format); queue_test(test_effect_blob_property); + queue_test(test_get_dxgi_device);
run_queued_tests(); }
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/d2d1/device.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 75da15c99a5..ce0175966b1 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -3458,7 +3458,6 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, struct d2d_device *device, IUnknown *outer_unknown, const struct d2d_device_context_ops *ops) { D3D11_SUBRESOURCE_DATA buffer_data; - struct d2d_device *device_impl; IDWriteFactory *dwrite_factory; D3D11_RASTERIZER_DESC rs_desc; D3D11_BUFFER_DESC buffer_desc; @@ -3986,8 +3985,7 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, render_target->outer_unknown = outer_unknown ? outer_unknown : &render_target->IUnknown_iface; render_target->ops = ops;
- device_impl = unsafe_impl_from_ID2D1Device((ID2D1Device1 *)device); - if (FAILED(hr = IDXGIDevice_QueryInterface(device_impl->dxgi_device, + if (FAILED(hr = IDXGIDevice_QueryInterface(device->dxgi_device, &IID_ID3D11Device1, (void **)&render_target->d3d_device))) { WARN("Failed to query ID3D11Device1 interface, hr %#lx.\n", hr);
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/d2d1/d2d1_private.h | 1 + dlls/d2d1/device.c | 15 +++++++++++++-- dlls/d2d1/tests/d2d1.c | 19 ++++--------------- 3 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 58507fd2c0b..e9a279e4c7a 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -613,6 +613,7 @@ struct d2d_device LONG refcount; ID2D1Factory1 *factory; IDXGIDevice *dxgi_device; + BOOL allow_get_dxgi_device;
struct d2d_indexed_objects shaders; }; diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index ce0175966b1..ff2734d04bd 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -3992,6 +3992,9 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, goto err; }
+ if (!d2d_device_context_is_dxgi_target(render_target)) + device->allow_get_dxgi_device = FALSE; + if (FAILED(hr = ID3D11Device1_CreateDeviceContextState(render_target->d3d_device, 0, &feature_levels, 1, D3D11_SDK_VERSION, &IID_ID3D11Device1, NULL, &render_target->d3d_state))) @@ -4426,9 +4429,16 @@ static void STDMETHODCALLTYPE d2d_device_FlushDeviceContexts(ID2D1Device6 *iface static HRESULT STDMETHODCALLTYPE d2d_device_GetDxgiDevice(ID2D1Device6 *iface, IDXGIDevice **dxgi_device) { - FIXME("iface %p, dxgi_device %p stub!\n", iface, dxgi_device); + struct d2d_device *device = impl_from_ID2D1Device(iface);
- return E_NOTIMPL; + TRACE("iface %p, dxgi_device %p.\n", iface, dxgi_device); + + if (!device->allow_get_dxgi_device) + return D2DERR_INVALID_CALL; + + IDXGIDevice_AddRef(device->dxgi_device); + *dxgi_device = device->dxgi_device; + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_device_ID2D1Device3_CreateDeviceContext(ID2D1Device6 *iface, @@ -4525,6 +4535,7 @@ void d2d_device_init(struct d2d_device *device, struct d2d_factory *factory, IDX ID2D1Factory1_AddRef(device->factory); device->dxgi_device = dxgi_device; IDXGIDevice_AddRef(device->dxgi_device); + device->allow_get_dxgi_device = TRUE; }
HRESULT d2d_device_add_indexed_object(struct d2d_indexed_objects *objects, diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 011e1d51ccc..bc9d9f75935 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15479,14 +15479,10 @@ static void test_get_dxgi_device(BOOL d3d11) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(dxgi_device == ctx.device, "Got unexpected IDXGIDevice.\n"); - IDXGIDevice_Release(dxgi_device); - } + ok(dxgi_device == ctx.device, "Got unexpected IDXGIDevice.\n");
+ IDXGIDevice_Release(dxgi_device); ID2D1Device2_Release(device2); ID2D1Device_Release(device);
@@ -15515,7 +15511,6 @@ static void test_get_dxgi_device(BOOL d3d11) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); - todo_wine ok(hr == D2DERR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
ID2D1Device2_Release(device2); @@ -15549,7 +15544,6 @@ static void test_get_dxgi_device(BOOL d3d11) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); - todo_wine ok(hr == D2DERR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
ID2D1Device2_Release(device2); @@ -15564,14 +15558,10 @@ static void test_get_dxgi_device(BOOL d3d11) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(dxgi_device == ctx.device, "Got unexpected IDXGIDevice.\n"); - IDXGIDevice_Release(dxgi_device); - } + ok(dxgi_device == ctx.device, "Got unexpected IDXGIDevice.\n");
+ IDXGIDevice_Release(dxgi_device); ID2D1Device2_Release(device2); ID2D1Device_Release(device);
@@ -15593,7 +15583,6 @@ static void test_get_dxgi_device(BOOL d3d11) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
hr = ID2D1Device2_GetDxgiDevice(device2, &dxgi_device); - todo_wine ok(hr == D2DERR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
ID2D1Device2_Release(device2);
Nikolay Sivov (@nsivov) commented about dlls/d2d1/d2d1_private.h:
LONG refcount; ID2D1Factory1 *factory; IDXGIDevice *dxgi_device;
- BOOL allow_get_dxgi_device;
We can use "bool" type for new changes.
Nikolay Sivov (@nsivov) commented about dlls/d2d1/device.c:
goto err; }
- if (!d2d_device_context_is_dxgi_target(render_target))
device->allow_get_dxgi_device = FALSE;
This is backwards. Having a flag is fine, but what I suggest is to add a helper replacing ID2D1Factory1_CreateDevice(), that would take another argument for this flag.
Nikolay Sivov (@nsivov) commented about dlls/d2d1/device.c:
static HRESULT STDMETHODCALLTYPE d2d_device_GetDxgiDevice(ID2D1Device6 *iface, IDXGIDevice **dxgi_device) {
- FIXME("iface %p, dxgi_device %p stub!\n", iface, dxgi_device);
- struct d2d_device *device = impl_from_ID2D1Device(iface);
- return E_NOTIMPL;
- TRACE("iface %p, dxgi_device %p.\n", iface, dxgi_device);
- if (!device->allow_get_dxgi_device)
return D2DERR_INVALID_CALL;
Please add some tests to see if out argument is reset to null or not on this error path. It does happen sometimes in d3d api, and it's easy to imagine pattern like "GetDxgiDevice(&device); if (device) {};".
Nikolay Sivov (@nsivov) commented about dlls/d2d1/tests/d2d1.c:
release_test_context(&ctx);
return;
- }
- /* Test user-provided DXGI device */
- hr = ID2D1Factory1_CreateDevice(ctx.factory1, ctx.device, &device);
- ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
- hr = ID2D1Device_QueryInterface(device, &IID_ID2D1Device2, (void **)&device2);
- if (FAILED(hr))
- {
win_skip("ID2D1Device2 is not supported.\n");
ID2D1Device_Release(device);
release_test_context(&ctx);
return;
- }
- ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
Here you could check for factory3 being null, ID2D1Device2 won't be supported without ID2D1Factory3.
A test for CreateCompatibleRenderTarget() is also interesting, but probably only for dxgi context, to see if dxgi device is accessible through compatible target instance. For other targets it would be weird if it was suddenly exposed for compatible target, but not for the target it's created from. But who knows.