From: Henri Verbeet Subject: [PATCH 3/5] d2d1: Implement d2d_d3d_render_target_CreateSharedBitmap(). Message-Id: <1438671209-27903-3-git-send-email-hverbeet@codeweavers.com> Date: Tue, 4 Aug 2015 08:53:27 +0200 --- dlls/d2d1/bitmap.c | 108 +++++++++++++++++++++--------- dlls/d2d1/d2d1_private.h | 4 +- dlls/d2d1/render_target.c | 25 +++++-- dlls/d2d1/tests/Makefile.in | 2 +- dlls/d2d1/tests/d2d1.c | 155 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 259 insertions(+), 35 deletions(-) diff --git a/dlls/d2d1/bitmap.c b/dlls/d2d1/bitmap.c index 2627501..b3348c6 100644 --- a/dlls/d2d1/bitmap.c +++ b/dlls/d2d1/bitmap.c @@ -163,15 +163,9 @@ static const struct ID2D1BitmapVtbl d2d_bitmap_vtbl = d2d_bitmap_CopyFromMemory, }; -HRESULT d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target *render_target, - D2D1_SIZE_U size, const void *src_data, UINT32 pitch, const D2D1_BITMAP_PROPERTIES *desc) +static BOOL format_supported(const D2D1_PIXEL_FORMAT *format) { - D3D10_SUBRESOURCE_DATA resource_data; - D3D10_TEXTURE2D_DESC texture_desc; - ID3D10Texture2D *texture; - BOOL supported = FALSE; unsigned int i; - HRESULT hr; static const D2D1_PIXEL_FORMAT supported_formats[] = { @@ -196,27 +190,49 @@ HRESULT d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target for (i = 0; i < sizeof(supported_formats) / sizeof(*supported_formats); ++i) { - if (supported_formats[i].format == desc->pixelFormat.format - && supported_formats[i].alphaMode == desc->pixelFormat.alphaMode) - { - supported = TRUE; - break; - } + if (supported_formats[i].format == format->format + && supported_formats[i].alphaMode == format->alphaMode) + return TRUE; } - if (!supported) + return FALSE; +} + +static void d2d_bitmap_init(struct d2d_bitmap *bitmap, ID2D1Factory *factory, + ID3D10ShaderResourceView *view, D2D1_SIZE_U size, const D2D1_BITMAP_PROPERTIES *desc) +{ + bitmap->ID2D1Bitmap_iface.lpVtbl = &d2d_bitmap_vtbl; + bitmap->refcount = 1; + ID2D1Factory_AddRef(bitmap->factory = factory); + ID3D10ShaderResourceView_AddRef(bitmap->view = view); + bitmap->pixel_size = size; + bitmap->format = desc->pixelFormat; + bitmap->dpi_x = desc->dpiX; + bitmap->dpi_y = desc->dpiY; + + if (bitmap->dpi_x == 0.0f && bitmap->dpi_y == 0.0f) + { + bitmap->dpi_x = 96.0f; + bitmap->dpi_y = 96.0f; + } +} + +HRESULT d2d_bitmap_init_memory(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target *render_target, + D2D1_SIZE_U size, const void *src_data, UINT32 pitch, const D2D1_BITMAP_PROPERTIES *desc) +{ + D3D10_SUBRESOURCE_DATA resource_data; + D3D10_TEXTURE2D_DESC texture_desc; + ID3D10ShaderResourceView *view; + ID3D10Texture2D *texture; + HRESULT hr; + + if (!format_supported(&desc->pixelFormat)) { WARN("Tried to create bitmap with unsupported format {%#x / %#x}.\n", desc->pixelFormat.format, desc->pixelFormat.alphaMode); return D2DERR_UNSUPPORTED_PIXEL_FORMAT; } - FIXME("Ignoring bitmap properties.\n"); - - bitmap->ID2D1Bitmap_iface.lpVtbl = &d2d_bitmap_vtbl; - bitmap->refcount = 1; - ID2D1Factory_AddRef(bitmap->factory = render_target->factory); - texture_desc.Width = size.width; texture_desc.Height = size.height; texture_desc.MipLevels = 1; @@ -239,7 +255,7 @@ HRESULT d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target return hr; } - hr = ID3D10Device_CreateShaderResourceView(render_target->device, (ID3D10Resource *)texture, NULL, &bitmap->view); + hr = ID3D10Device_CreateShaderResourceView(render_target->device, (ID3D10Resource *)texture, NULL, &view); ID3D10Texture2D_Release(texture); if (FAILED(hr)) { @@ -247,18 +263,52 @@ HRESULT d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target return hr; } - bitmap->pixel_size = size; - bitmap->format = desc->pixelFormat; - bitmap->dpi_x = desc->dpiX; - bitmap->dpi_y = desc->dpiY; + d2d_bitmap_init(bitmap, render_target->factory, view, size, desc); + ID3D10ShaderResourceView_Release(view); - if (bitmap->dpi_x == 0.0f && bitmap->dpi_y == 0.0f) + return S_OK; +} + +HRESULT d2d_bitmap_init_shared(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target *render_target, + REFIID iid, void *data, const D2D1_BITMAP_PROPERTIES *desc) +{ + if (IsEqualGUID(iid, &IID_ID2D1Bitmap)) { - bitmap->dpi_x = 96.0f; - bitmap->dpi_y = 96.0f; + struct d2d_bitmap *src_impl = unsafe_impl_from_ID2D1Bitmap(data); + D2D1_BITMAP_PROPERTIES d; + ID3D10Device *device; + + if (src_impl->factory != render_target->factory) + return D2DERR_WRONG_FACTORY; + + ID3D10ShaderResourceView_GetDevice(src_impl->view, &device); + ID3D10Device_Release(device); + if (device != render_target->device) + return D2DERR_UNSUPPORTED_OPERATION; + + if (!desc) + { + d.pixelFormat = src_impl->format; + d.dpiX = src_impl->dpi_x; + d.dpiY = src_impl->dpi_y; + desc = &d; + } + + if (!format_supported(&desc->pixelFormat)) + { + WARN("Tried to create bitmap with unsupported format {%#x / %#x}.\n", + desc->pixelFormat.format, desc->pixelFormat.alphaMode); + return D2DERR_UNSUPPORTED_PIXEL_FORMAT; + } + + d2d_bitmap_init(bitmap, render_target->factory, src_impl->view, src_impl->pixel_size, desc); + + return S_OK; } - return S_OK; + WARN("Unhandled interface %s.\n", debugstr_guid(iid)); + + return E_INVALIDARG; } struct d2d_bitmap *unsafe_impl_from_ID2D1Bitmap(ID2D1Bitmap *iface) diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 08e0b3f..6553eeb 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -196,8 +196,10 @@ struct d2d_bitmap float dpi_y; }; -HRESULT d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target *render_target, +HRESULT d2d_bitmap_init_memory(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target *render_target, D2D1_SIZE_U size, const void *src_data, UINT32 pitch, const D2D1_BITMAP_PROPERTIES *desc) DECLSPEC_HIDDEN; +HRESULT d2d_bitmap_init_shared(struct d2d_bitmap *bitmap, struct d2d_d3d_render_target *render_target, + REFIID iid, void *data, const D2D1_BITMAP_PROPERTIES *desc) DECLSPEC_HIDDEN; struct d2d_bitmap *unsafe_impl_from_ID2D1Bitmap(ID2D1Bitmap *iface) DECLSPEC_HIDDEN; struct d2d_state_block diff --git a/dlls/d2d1/render_target.c b/dlls/d2d1/render_target.c index 99cb7c8..df9a898 100644 --- a/dlls/d2d1/render_target.c +++ b/dlls/d2d1/render_target.c @@ -284,7 +284,7 @@ static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmap(ID2D1RenderT if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) return E_OUTOFMEMORY; - if (FAILED(hr = d2d_bitmap_init(object, render_target, size, src_data, pitch, desc))) + if (FAILED(hr = d2d_bitmap_init_memory(object, render_target, size, src_data, pitch, desc))) { WARN("Failed to initialize bitmap, hr %#x.\n", hr); HeapFree(GetProcessHeap(), 0, object); @@ -406,10 +406,27 @@ static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmapFromWicBitmap static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateSharedBitmap(ID2D1RenderTarget *iface, REFIID iid, void *data, const D2D1_BITMAP_PROPERTIES *desc, ID2D1Bitmap **bitmap) { - FIXME("iface %p, iid %s, data %p, desc %p, bitmap %p stub!\n", - iface, debugstr_guid(iid), data, desc, bitmap); + struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); + struct d2d_bitmap *object; + HRESULT hr; - return E_NOTIMPL; + TRACE("iface %p, iid %s, data %p, desc %p, bitmap %p.\n", + iface, debugstr_guid(iid), data, desc, bitmap); + + if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = d2d_bitmap_init_shared(object, render_target, iid, data, desc))) + { + WARN("Failed to initialize bitmap, hr %#x.\n", hr); + HeapFree(GetProcessHeap(), 0, object); + return hr; + } + + TRACE("Created bitmap %p.\n", object); + *bitmap = &object->ID2D1Bitmap_iface; + + return S_OK; } static HRESULT STDMETHODCALLTYPE d2d_d3d_render_target_CreateBitmapBrush(ID2D1RenderTarget *iface, diff --git a/dlls/d2d1/tests/Makefile.in b/dlls/d2d1/tests/Makefile.in index 83406c1..28b741f 100644 --- a/dlls/d2d1/tests/Makefile.in +++ b/dlls/d2d1/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = d2d1.dll -IMPORTS = d2d1 d3d10_1 dwrite dxguid uuid user32 advapi32 +IMPORTS = d2d1 d3d10_1 dwrite dxguid uuid user32 advapi32 ole32 C_SRCS = \ d2d1.c diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index a0c9b11..739e2fb 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -23,6 +23,7 @@ #include "wine/test.h" #include "initguid.h" #include "dwrite.h" +#include "wincodec.h" struct figure { @@ -1844,6 +1845,159 @@ static void test_alpha_mode(void) DestroyWindow(window); } +static void test_shared_bitmap(void) +{ + IDXGISwapChain *swapchain1, *swapchain2; + IWICBitmap *wic_bitmap1, *wic_bitmap2; + D2D1_RENDER_TARGET_PROPERTIES desc; + D2D1_BITMAP_PROPERTIES bitmap_desc; + IDXGISurface *surface1, *surface2; + ID2D1Factory *factory1, *factory2; + ID3D10Device1 *device1, *device2; + IWICImagingFactory *wic_factory; + ID2D1Bitmap *bitmap1, *bitmap2; + ID2D1RenderTarget *rt1, *rt2; + D2D1_SIZE_U size = {4, 4}; + HWND window1, window2; + HRESULT hr; + + if (!(device1 = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + + window1 = CreateWindowA("static", "d2d1_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 0, 0, 640, 480, NULL, NULL, NULL, NULL); + window2 = CreateWindowA("static", "d2d1_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 0, 0, 640, 480, NULL, NULL, NULL, NULL); + swapchain1 = create_swapchain(device1, window1, TRUE); + swapchain2 = create_swapchain(device1, window2, TRUE); + hr = IDXGISwapChain_GetBuffer(swapchain1, 0, &IID_IDXGISurface, (void **)&surface1); + ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr); + hr = IDXGISwapChain_GetBuffer(swapchain2, 0, &IID_IDXGISurface, (void **)&surface2); + ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr); + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&wic_factory); + ok(SUCCEEDED(hr), "Failed to create WIC imaging factory, hr %#x.\n", hr); + hr = IWICImagingFactory_CreateBitmap(wic_factory, 640, 480, + &GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnDemand, &wic_bitmap1); + ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr); + hr = IWICImagingFactory_CreateBitmap(wic_factory, 640, 480, + &GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnDemand, &wic_bitmap2); + ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr); + IWICImagingFactory_Release(wic_factory); + + desc.type = D2D1_RENDER_TARGET_TYPE_DEFAULT; + desc.pixelFormat.format = DXGI_FORMAT_UNKNOWN; + 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; + + bitmap_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; + bitmap_desc.dpiX = 96.0f; + bitmap_desc.dpiY = 96.0f; + + hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, NULL, (void **)&factory1); + ok(SUCCEEDED(hr), "Failed to create factory, hr %#x.\n", hr); + hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, NULL, (void **)&factory2); + ok(SUCCEEDED(hr), "Failed to create factory, hr %#x.\n", hr); + + /* DXGI surface render targets with the same device and factory. */ + hr = ID2D1Factory_CreateDxgiSurfaceRenderTarget(factory1, surface1, &desc, &rt1); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateBitmap(rt1, size, NULL, 0, &bitmap_desc, &bitmap1); + ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr); + + hr = ID2D1Factory_CreateDxgiSurfaceRenderTarget(factory1, surface2, &desc, &rt2); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_ID2D1Bitmap, bitmap1, NULL, &bitmap2); + ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr); + ID2D1Bitmap_Release(bitmap2); + hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_IUnknown, bitmap1, NULL, &bitmap2); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + ID2D1RenderTarget_Release(rt2); + + /* DXGI surface render targets with the same device but different factories. */ + hr = ID2D1Factory_CreateDxgiSurfaceRenderTarget(factory2, surface2, &desc, &rt2); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_ID2D1Bitmap, bitmap1, NULL, &bitmap2); + ok(hr == D2DERR_WRONG_FACTORY, "Got unexpected hr %#x.\n", hr); + ID2D1RenderTarget_Release(rt2); + + /* DXGI surface render targets with different devices but the same factory. */ + IDXGISurface_Release(surface2); + IDXGISwapChain_Release(swapchain2); + device2 = create_device(); + ok(!!device2, "Failed to create device.\n"); + swapchain2 = create_swapchain(device2, window2, TRUE); + hr = IDXGISwapChain_GetBuffer(swapchain2, 0, &IID_IDXGISurface, (void **)&surface2); + ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr); + + hr = ID2D1Factory_CreateDxgiSurfaceRenderTarget(factory1, surface2, &desc, &rt2); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_ID2D1Bitmap, bitmap1, NULL, &bitmap2); + ok(hr == D2DERR_UNSUPPORTED_OPERATION, "Got unexpected hr %#x.\n", hr); + ID2D1RenderTarget_Release(rt2); + + /* DXGI surface render targets with different devices and different factories. */ + hr = ID2D1Factory_CreateDxgiSurfaceRenderTarget(factory2, surface2, &desc, &rt2); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_ID2D1Bitmap, bitmap1, NULL, &bitmap2); + ok(hr == D2DERR_WRONG_FACTORY, "Got unexpected hr %#x.\n", hr); + ID2D1RenderTarget_Release(rt2); + + /* DXGI surface render target and WIC bitmap render target, same factory. */ + hr = ID2D1Factory_CreateWicBitmapRenderTarget(factory1, wic_bitmap2, &desc, &rt2); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_ID2D1Bitmap, bitmap1, NULL, &bitmap2); + ok(hr == D2DERR_UNSUPPORTED_OPERATION, "Got unexpected hr %#x.\n", hr); + ID2D1RenderTarget_Release(rt2); + + /* WIC bitmap render targets on different D2D factories. */ + ID2D1Bitmap_Release(bitmap1); + ID2D1RenderTarget_Release(rt1); + hr = ID2D1Factory_CreateWicBitmapRenderTarget(factory1, wic_bitmap1, &desc, &rt1); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateBitmap(rt1, size, NULL, 0, &bitmap_desc, &bitmap1); + ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr); + + hr = ID2D1Factory_CreateWicBitmapRenderTarget(factory2, wic_bitmap2, &desc, &rt2); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_ID2D1Bitmap, bitmap1, NULL, &bitmap2); + ok(hr == D2DERR_WRONG_FACTORY, "Got unexpected hr %#x.\n", hr); + ID2D1RenderTarget_Release(rt2); + + /* WIC bitmap render targets on the same D2D factory. */ + hr = ID2D1Factory_CreateWicBitmapRenderTarget(factory1, wic_bitmap2, &desc, &rt2); + ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr); + hr = ID2D1RenderTarget_CreateSharedBitmap(rt2, &IID_ID2D1Bitmap, bitmap1, NULL, &bitmap2); + ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr); + ID2D1Bitmap_Release(bitmap2); + ID2D1RenderTarget_Release(rt2); + + ID2D1Bitmap_Release(bitmap1); + ID2D1RenderTarget_Release(rt1); + ID2D1Factory_Release(factory2); + ID2D1Factory_Release(factory1); + IWICBitmap_Release(wic_bitmap2); + IWICBitmap_Release(wic_bitmap1); + IDXGISurface_Release(surface2); + IDXGISurface_Release(surface1); + IDXGISwapChain_Release(swapchain2); + IDXGISwapChain_Release(swapchain1); + ID3D10Device1_Release(device2); + ID3D10Device1_Release(device1); + DestroyWindow(window2); + DestroyWindow(window1); + CoUninitialize(); +} + START_TEST(d2d1) { test_clip(); @@ -1853,4 +2007,5 @@ START_TEST(d2d1) test_path_geometry(); test_bitmap_formats(); test_alpha_mode(); + test_shared_bitmap(); } -- 2.1.4