[v2 PATCH 5/5] d2d1: Implement SetTarget() for bitmap targets.

Nikolay Sivov nsivov at codeweavers.com
Fri Sep 28 03:58:00 CDT 2018


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/d2d1/bitmap.c               |  23 ++-
 dlls/d2d1/bitmap_render_target.c |  74 +++------
 dlls/d2d1/d2d1_private.h         |   6 +-
 dlls/d2d1/dc_render_target.c     |  96 +++++------
 dlls/d2d1/device.c               | 269 +++++++++++++++++--------------
 dlls/d2d1/hwnd_render_target.c   |  19 ++-
 dlls/d2d1/tests/d2d1.c           |  64 +++++---
 7 files changed, 290 insertions(+), 261 deletions(-)

diff --git a/dlls/d2d1/bitmap.c b/dlls/d2d1/bitmap.c
index fde348fa1c..dd15714153 100644
--- a/dlls/d2d1/bitmap.c
+++ b/dlls/d2d1/bitmap.c
@@ -70,6 +70,8 @@ static ULONG STDMETHODCALLTYPE d2d_bitmap_Release(ID2D1Bitmap1 *iface)
     if (!refcount)
     {
         ID3D10ShaderResourceView_Release(bitmap->view);
+        if (bitmap->rtv)
+            ID3D10RenderTargetView_Release(bitmap->rtv);
         if (bitmap->surface)
             IDXGISurface_Release(bitmap->surface);
         ID2D1Factory_Release(bitmap->factory);
@@ -274,6 +276,10 @@ static BOOL format_supported(const D2D1_PIXEL_FORMAT *format)
 static void d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_device_context *context,
         ID3D10ShaderResourceView *view, D2D1_SIZE_U size, const D2D1_BITMAP_PROPERTIES1 *desc)
 {
+    ID3D10Resource *resource;
+    ID3D10Device *d3d_device;
+    HRESULT hr;
+
     bitmap->ID2D1Bitmap1_iface.lpVtbl = &d2d_bitmap_vtbl;
     bitmap->refcount = 1;
     ID2D1Factory_AddRef(bitmap->factory = context->factory);
@@ -283,15 +289,22 @@ static void d2d_bitmap_init(struct d2d_bitmap *bitmap, struct d2d_device_context
     bitmap->dpi_x = desc->dpiX;
     bitmap->dpi_y = desc->dpiY;
     bitmap->options = desc->bitmapOptions;
-    if (d2d_device_context_is_dxgi_target(context))
-    {
-        ID3D10Resource *resource;
 
-        ID3D10ShaderResourceView_GetResource(bitmap->view, &resource);
+    ID3D10ShaderResourceView_GetResource(bitmap->view, &resource);
+
+    if (d2d_device_context_is_dxgi_target(context))
         ID3D10Resource_QueryInterface(resource, &IID_IDXGISurface, (void **)&bitmap->surface);
-        ID3D10Resource_Release(resource);
+
+    if (bitmap->options & D2D1_BITMAP_OPTIONS_TARGET)
+    {
+        ID3D10Resource_GetDevice(resource, &d3d_device);
+        if (FAILED(hr = ID3D10Device_CreateRenderTargetView(d3d_device, resource, NULL, &bitmap->rtv)))
+            WARN("Failed to create rtv, hr %#x.\n", hr);
+        ID3D10Device_Release(d3d_device);
     }
 
+    ID3D10Resource_Release(resource);
+
     if (bitmap->dpi_x == 0.0f && bitmap->dpi_y == 0.0f)
     {
         bitmap->dpi_x = 96.0f;
diff --git a/dlls/d2d1/bitmap_render_target.c b/dlls/d2d1/bitmap_render_target.c
index df5b013a0b..836fa567e7 100644
--- a/dlls/d2d1/bitmap_render_target.c
+++ b/dlls/d2d1/bitmap_render_target.c
@@ -69,7 +69,8 @@ static ULONG STDMETHODCALLTYPE d2d_bitmap_render_target_Release(ID2D1BitmapRende
     if (!refcount)
     {
         IUnknown_Release(render_target->dxgi_inner);
-        ID2D1Bitmap_Release(render_target->bitmap);
+        if (render_target->bitmap)
+            ID2D1Bitmap_Release(render_target->bitmap);
         heap_free(render_target);
     }
 
@@ -733,10 +734,9 @@ HRESULT d2d_bitmap_render_target_init(struct d2d_bitmap_render_target *render_ta
         D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS options)
 {
     D2D1_RENDER_TARGET_PROPERTIES dxgi_rt_desc;
-    D2D1_BITMAP_PROPERTIES bitmap_desc;
-    D3D10_TEXTURE2D_DESC texture_desc;
-    IDXGISurface *dxgi_surface;
-    ID3D10Texture2D *texture;
+    D2D1_BITMAP_PROPERTIES1 bitmap_desc;
+    ID2D1DeviceContext *context;
+    D2D1_SIZE_U bitmap_size;
     HRESULT hr;
 
     if (options)
@@ -750,24 +750,24 @@ HRESULT d2d_bitmap_render_target_init(struct d2d_bitmap_render_target *render_ta
 
     if (pixel_size)
     {
-        texture_desc.Width = pixel_size->width;
-        texture_desc.Height = pixel_size->height;
+        bitmap_size.width = pixel_size->width;
+        bitmap_size.height = pixel_size->height;
     }
     else if (size)
     {
-        texture_desc.Width = ceilf((size->width * parent_target->desc.dpiX) / 96.0f);
-        texture_desc.Height = ceilf((size->height * parent_target->desc.dpiY) / 96.0f);
+        bitmap_size.width = ceilf((size->width * parent_target->desc.dpiX) / 96.0f);
+        bitmap_size.height = ceilf((size->height * parent_target->desc.dpiY) / 96.0f);
     }
     else
     {
-        texture_desc.Width = parent_target->pixel_size.width;
-        texture_desc.Height = parent_target->pixel_size.height;
+        bitmap_size.width = parent_target->pixel_size.width;
+        bitmap_size.height = parent_target->pixel_size.height;
     }
 
-    if (size)
+    if (size && size->width != 0.0f && size->height != 0.0f)
     {
-        dxgi_rt_desc.dpiX = (texture_desc.Width * 96.0f) / size->width;
-        dxgi_rt_desc.dpiY = (texture_desc.Height * 96.0f) / size->height;
+        dxgi_rt_desc.dpiX = (bitmap_size.width * 96.0f) / size->width;
+        dxgi_rt_desc.dpiY = (bitmap_size.height * 96.0f) / size->height;
     }
     else
     {
@@ -776,46 +776,21 @@ HRESULT d2d_bitmap_render_target_init(struct d2d_bitmap_render_target *render_ta
     }
 
     if (!pixel_format || pixel_format->format == DXGI_FORMAT_UNKNOWN)
-        texture_desc.Format = parent_target->desc.pixelFormat.format;
+        dxgi_rt_desc.pixelFormat.format = parent_target->desc.pixelFormat.format;
     else
-        texture_desc.Format = pixel_format->format;
-    dxgi_rt_desc.pixelFormat.format = texture_desc.Format;
+        dxgi_rt_desc.pixelFormat.format = pixel_format->format;
 
     if (!pixel_format || pixel_format->alphaMode == D2D1_ALPHA_MODE_UNKNOWN)
         dxgi_rt_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
     else
         dxgi_rt_desc.pixelFormat.alphaMode = pixel_format->alphaMode;
 
-    texture_desc.MipLevels = 1;
-    texture_desc.ArraySize = 1;
-    texture_desc.SampleDesc.Count = 1;
-    texture_desc.SampleDesc.Quality = 0;
-    texture_desc.Usage = D3D10_USAGE_DEFAULT;
-    texture_desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
-    texture_desc.CPUAccessFlags = 0;
-    texture_desc.MiscFlags = 0;
-
-    if (FAILED(hr = ID3D10Device_CreateTexture2D(parent_target->d3d_device, &texture_desc, NULL, &texture)))
-    {
-        WARN("Failed to create texture, hr %#x.\n", hr);
-        return hr;
-    }
-
-    hr = ID3D10Texture2D_QueryInterface(texture, &IID_IDXGISurface, (void **)&dxgi_surface);
-    ID3D10Texture2D_Release(texture);
-    if (FAILED(hr))
-    {
-        WARN("Failed to get DXGI surface interface, hr %#x.\n", hr);
-        return hr;
-    }
-
-    if (FAILED(hr = d2d_d3d_create_render_target(parent_target->device, dxgi_surface,
+    if (FAILED(hr = d2d_d3d_create_render_target(parent_target->device, NULL,
             (IUnknown *)&render_target->ID2D1BitmapRenderTarget_iface,
             parent_target->ops ? &d2d_bitmap_render_target_ops : NULL,
             &dxgi_rt_desc, (void **)&render_target->dxgi_inner)))
     {
         WARN("Failed to create DXGI surface render target, hr %#x.\n", hr);
-        IDXGISurface_Release(dxgi_surface);
         return hr;
     }
 
@@ -824,20 +799,23 @@ HRESULT d2d_bitmap_render_target_init(struct d2d_bitmap_render_target *render_ta
     {
         WARN("Failed to retrieve ID2D1RenderTarget interface, hr %#x.\n", hr);
         IUnknown_Release(render_target->dxgi_inner);
-        IDXGISurface_Release(dxgi_surface);
         return hr;
     }
 
     bitmap_desc.pixelFormat = dxgi_rt_desc.pixelFormat;
     bitmap_desc.dpiX = dxgi_rt_desc.dpiX;
     bitmap_desc.dpiY = dxgi_rt_desc.dpiY;
-
-    hr = ID2D1RenderTarget_CreateSharedBitmap(render_target->dxgi_target, &IID_IDXGISurface, dxgi_surface,
-            &bitmap_desc, &render_target->bitmap);
-    IDXGISurface_Release(dxgi_surface);
+    bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
+    bitmap_desc.colorContext = NULL;
+
+    ID2D1RenderTarget_QueryInterface(render_target->dxgi_target, &IID_ID2D1DeviceContext, (void **)&context);
+    hr = ID2D1DeviceContext_CreateBitmap(context, bitmap_size, NULL, 0, &bitmap_desc,
+            (ID2D1Bitmap1 **)&render_target->bitmap);
+    ID2D1DeviceContext_SetTarget(context, (ID2D1Image *)render_target->bitmap);
+    ID2D1DeviceContext_Release(context);
     if (FAILED(hr))
     {
-        WARN("Failed to create shared bitmap, hr %#x.\n", hr);
+        WARN("Failed to create target bitmap, hr %#x.\n", hr);
         ID2D1RenderTarget_Release(render_target->dxgi_target);
         IUnknown_Release(render_target->dxgi_inner);
         return hr;
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index 726d143d86..0a5bc36c9a 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -136,7 +136,7 @@ struct d2d_device_context
     ID2D1Factory *factory;
     ID2D1Device *device;
     ID3D10Device *d3d_device;
-    ID3D10RenderTargetView *view;
+    struct d2d_bitmap *target;
     ID3D10StateBlock *stateblock;
     struct d2d_shape_resources shape_resources[D2D_SHAPE_TYPE_COUNT];
     ID3D10PixelShader *ps;
@@ -159,7 +159,6 @@ struct d2d_device_context
 HRESULT d2d_d3d_create_render_target(ID2D1Device *device, IDXGISurface *surface, IUnknown *outer_unknown,
         const struct d2d_device_context_ops *ops, const D2D1_RENDER_TARGET_PROPERTIES *desc,
         void **render_target) DECLSPEC_HIDDEN;
-HRESULT d2d_d3d_render_target_create_rtv(ID2D1RenderTarget *render_target, IDXGISurface1 *surface) DECLSPEC_HIDDEN;
 
 static inline BOOL d2d_device_context_is_dxgi_target(const struct d2d_device_context *context)
 {
@@ -191,6 +190,8 @@ struct d2d_dc_render_target
     LONG refcount;
 
     IDXGISurface1 *dxgi_surface;
+    D2D1_PIXEL_FORMAT pixel_format;
+    ID3D10Device1 *d3d_device;
     ID2D1RenderTarget *dxgi_target;
     IUnknown *dxgi_inner;
 
@@ -345,6 +346,7 @@ struct d2d_bitmap
 
     ID2D1Factory *factory;
     ID3D10ShaderResourceView *view;
+    ID3D10RenderTargetView *rtv;
     IDXGISurface *surface;
     D2D1_SIZE_U pixel_size;
     D2D1_PIXEL_FORMAT format;
diff --git a/dlls/d2d1/dc_render_target.c b/dlls/d2d1/dc_render_target.c
index 9a0f458faf..b4306fb2fe 100644
--- a/dlls/d2d1/dc_render_target.c
+++ b/dlls/d2d1/dc_render_target.c
@@ -99,7 +99,9 @@ static ULONG STDMETHODCALLTYPE d2d_dc_render_target_Release(ID2D1DCRenderTarget
     if (!refcount)
     {
         IUnknown_Release(render_target->dxgi_inner);
-        IDXGISurface1_Release(render_target->dxgi_surface);
+        if (render_target->dxgi_surface)
+            IDXGISurface1_Release(render_target->dxgi_surface);
+        ID3D10Device1_Release(render_target->d3d_device);
         heap_free(render_target);
     }
 
@@ -686,8 +688,9 @@ static HRESULT STDMETHODCALLTYPE d2d_dc_render_target_BindDC(ID2D1DCRenderTarget
     struct d2d_dc_render_target *render_target = impl_from_ID2D1DCRenderTarget(iface);
     D3D10_TEXTURE2D_DESC texture_desc;
     IDXGISurface1 *dxgi_surface;
+    ID2D1DeviceContext *context;
     ID3D10Texture2D *texture;
-    ID3D10Device *device;
+    ID2D1Bitmap1 *bitmap;
     HRESULT hr;
 
     TRACE("iface %p, hdc %p, rect %s.\n", iface, hdc, wine_dbgstr_rect(rect));
@@ -695,27 +698,19 @@ static HRESULT STDMETHODCALLTYPE d2d_dc_render_target_BindDC(ID2D1DCRenderTarget
     if (!hdc)
         return E_INVALIDARG;
 
-    /* Recreate surface using specified size and original texture description. */
-    if (FAILED(hr = IDXGISurface1_QueryInterface(render_target->dxgi_surface, &IID_ID3D10Texture2D, (void **)&texture)))
-    {
-        WARN("Failed to get texture interface, hr %#x.\n", hr);
-        return hr;
-    }
-
-    ID3D10Texture2D_GetDesc(texture, &texture_desc);
-    ID3D10Texture2D_Release(texture);
     texture_desc.Width = rect->right - rect->left;
     texture_desc.Height = rect->bottom - rect->top;
+    texture_desc.MipLevels = 1;
+    texture_desc.ArraySize = 1;
+    texture_desc.Format = render_target->pixel_format.format;
+    texture_desc.SampleDesc.Count = 1;
+    texture_desc.SampleDesc.Quality = 0;
+    texture_desc.Usage = D3D10_USAGE_DEFAULT;
+    texture_desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
+    texture_desc.CPUAccessFlags = 0;
+    texture_desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
 
-    if (FAILED(hr = IDXGISurface1_GetDevice(render_target->dxgi_surface, &IID_ID3D10Device, (void **)&device)))
-    {
-        WARN("Failed to get device from dxgi surface, hr %#x.\n", hr);
-        return hr;
-    }
-
-    hr = ID3D10Device_CreateTexture2D(device, &texture_desc, NULL, &texture);
-    ID3D10Device_Release(device);
-    if (FAILED(hr))
+    if (FAILED(hr = ID3D10Device1_CreateTexture2D(render_target->d3d_device, &texture_desc, NULL, &texture)))
     {
         WARN("Failed to create texture, hr %#x.\n", hr);
         return hr;
@@ -730,14 +725,24 @@ static HRESULT STDMETHODCALLTYPE d2d_dc_render_target_BindDC(ID2D1DCRenderTarget
     }
 
     /* Switch dxgi target to new surface. */
-    if (FAILED(hr = d2d_d3d_render_target_create_rtv(render_target->dxgi_target, dxgi_surface)))
+    ID2D1RenderTarget_QueryInterface(render_target->dxgi_target, &IID_ID2D1DeviceContext, (void **)&context);
+    hr = ID2D1DeviceContext_CreateBitmapFromDxgiSurface(context, (IDXGISurface *)dxgi_surface, NULL, &bitmap);
+    if (SUCCEEDED(hr))
     {
-        WARN("Failed to set new surface, hr %#x.\n", hr);
+        ID2D1DeviceContext_SetTarget(context, (ID2D1Image *)bitmap);
+        ID2D1Bitmap1_Release(bitmap);
+    }
+    ID2D1DeviceContext_Release(context);
+
+    if (FAILED(hr))
+    {
+        WARN("Failed to create new target bitmap, hr %#x.\n", hr);
         IDXGISurface1_Release(dxgi_surface);
         return hr;
     }
 
-    IDXGISurface1_Release(render_target->dxgi_surface);
+    if (render_target->dxgi_surface)
+        IDXGISurface1_Release(render_target->dxgi_surface);
     render_target->dxgi_surface = dxgi_surface;
 
     render_target->hdc = hdc;
@@ -816,8 +821,6 @@ static const struct d2d_device_context_ops d2d_dc_render_target_ops =
 HRESULT d2d_dc_render_target_init(struct d2d_dc_render_target *render_target, ID2D1Factory1 *factory,
         ID3D10Device1 *d3d_device, const D2D1_RENDER_TARGET_PROPERTIES *desc)
 {
-    D3D10_TEXTURE2D_DESC texture_desc;
-    ID3D10Texture2D *texture;
     IDXGIDevice *dxgi_device;
     ID2D1Device *device;
     HRESULT hr;
@@ -828,14 +831,8 @@ HRESULT d2d_dc_render_target_init(struct d2d_dc_render_target *render_target, ID
     SetRectEmpty(&render_target->dst_rect);
     render_target->hdc = NULL;
 
-    /* Dummy 1x1 texture, recreated on BindDC(). */
-    texture_desc.Width = 1;
-    texture_desc.Height = 1;
-    texture_desc.MipLevels = 1;
-    texture_desc.ArraySize = 1;
-
-    texture_desc.Format = desc->pixelFormat.format;
-    switch (texture_desc.Format)
+    render_target->pixel_format = desc->pixelFormat;
+    switch (desc->pixelFormat.format)
     {
         case DXGI_FORMAT_B8G8R8A8_UNORM:
             if (desc->pixelFormat.alphaMode == D2D1_ALPHA_MODE_PREMULTIPLIED
@@ -843,31 +840,10 @@ HRESULT d2d_dc_render_target_init(struct d2d_dc_render_target *render_target, ID
                 break;
 
         default:
-            FIXME("Unhandled format %#x, alpha mode %u.\n", texture_desc.Format, desc->pixelFormat.alphaMode);
+            FIXME("Unhandled format %#x, alpha mode %u.\n", desc->pixelFormat.format, desc->pixelFormat.alphaMode);
             return D2DERR_UNSUPPORTED_PIXEL_FORMAT;
     }
 
-    texture_desc.SampleDesc.Count = 1;
-    texture_desc.SampleDesc.Quality = 0;
-    texture_desc.Usage = D3D10_USAGE_DEFAULT;
-    texture_desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
-    texture_desc.CPUAccessFlags = 0;
-    texture_desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
-
-    if (FAILED(hr = ID3D10Device1_CreateTexture2D(d3d_device, &texture_desc, NULL, &texture)))
-    {
-        WARN("Failed to create texture, hr %#x.\n", hr);
-        return hr;
-    }
-
-    hr = ID3D10Texture2D_QueryInterface(texture, &IID_IDXGISurface1, (void **)&render_target->dxgi_surface);
-    ID3D10Texture2D_Release(texture);
-    if (FAILED(hr))
-    {
-        WARN("Failed to get DXGI surface interface, hr %#x.\n", hr);
-        return hr;
-    }
-
     if (FAILED(hr = ID3D10Device1_QueryInterface(d3d_device, &IID_IDXGIDevice, (void **)&dxgi_device)))
     {
         WARN("Failed to get DXGI device interface, hr %#x.\n", hr);
@@ -882,14 +858,12 @@ HRESULT d2d_dc_render_target_init(struct d2d_dc_render_target *render_target, ID
         return hr;
     }
 
-    hr = d2d_d3d_create_render_target(device, (IDXGISurface *)render_target->dxgi_surface,
-            (IUnknown *)&render_target->ID2D1DCRenderTarget_iface, &d2d_dc_render_target_ops,
-            desc, (void **)&render_target->dxgi_inner);
+    hr = d2d_d3d_create_render_target(device, NULL, (IUnknown *)&render_target->ID2D1DCRenderTarget_iface,
+            &d2d_dc_render_target_ops, desc, (void **)&render_target->dxgi_inner);
     ID2D1Device_Release(device);
     if (FAILED(hr))
     {
         WARN("Failed to create DXGI surface render target, hr %#x.\n", hr);
-        IDXGISurface1_Release(render_target->dxgi_surface);
         return hr;
     }
 
@@ -898,9 +872,11 @@ HRESULT d2d_dc_render_target_init(struct d2d_dc_render_target *render_target, ID
     {
         WARN("Failed to retrieve ID2D1RenderTarget interface, hr %#x.\n", hr);
         IUnknown_Release(render_target->dxgi_inner);
-        IDXGISurface1_Release(render_target->dxgi_surface);
         return hr;
     }
 
+    render_target->d3d_device = d3d_device;
+    ID3D10Device1_AddRef(render_target->d3d_device);
+
     return S_OK;
 }
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c
index 9bf8ef65ac..04d58ae8d1 100644
--- a/dlls/d2d1/device.c
+++ b/dlls/d2d1/device.c
@@ -43,6 +43,8 @@ static inline struct d2d_device *impl_from_ID2D1Device(ID2D1Device *iface)
     return CONTAINING_RECORD(iface, struct d2d_device, ID2D1Device_iface);
 }
 
+static struct d2d_device *unsafe_impl_from_ID2D1Device(ID2D1Device *iface);
+
 static ID2D1Brush *d2d_draw_get_text_brush(struct d2d_draw_text_layout_ctx *context, IUnknown *effect)
 {
     ID2D1Brush *brush = NULL;
@@ -175,7 +177,7 @@ static void d2d_device_context_draw(struct d2d_device_context *render_target, en
     }
     ID3D10Device_RSSetScissorRects(device, 1, &scissor_rect);
     ID3D10Device_RSSetState(device, render_target->rs);
-    ID3D10Device_OMSetRenderTargets(device, 1, &render_target->view, NULL);
+    ID3D10Device_OMSetRenderTargets(device, 1, &render_target->target->rtv, NULL);
     if (brush)
     {
         ID3D10Device_OMSetBlendState(device, render_target->bs, blend_factor, D3D10_DEFAULT_SAMPLE_MASK);
@@ -261,7 +263,8 @@ static ULONG STDMETHODCALLTYPE d2d_device_context_inner_Release(IUnknown *iface)
         IDWriteRenderingParams_Release(context->default_text_rendering_params);
         if (context->text_rendering_params)
             IDWriteRenderingParams_Release(context->text_rendering_params);
-        ID3D10BlendState_Release(context->bs);
+        if (context->bs)
+            ID3D10BlendState_Release(context->bs);
         ID3D10RasterizerState_Release(context->rs);
         ID3D10Buffer_Release(context->vb);
         ID3D10Buffer_Release(context->ib);
@@ -272,7 +275,8 @@ static ULONG STDMETHODCALLTYPE d2d_device_context_inner_Release(IUnknown *iface)
             ID3D10InputLayout_Release(context->shape_resources[i].il);
         }
         context->stateblock->lpVtbl->Release(context->stateblock);
-        ID3D10RenderTargetView_Release(context->view);
+        if (context->target)
+            ID2D1Bitmap1_Release(&context->target->ID2D1Bitmap1_iface);
         ID3D10Device_Release(context->d3d_device);
         ID2D1Factory_Release(context->factory);
         ID2D1Device_Release(context->device);
@@ -1979,14 +1983,95 @@ static void STDMETHODCALLTYPE d2d_device_context_GetDevice(ID2D1DeviceContext *i
     ID2D1Device_AddRef(*device);
 }
 
+static void d2d_device_context_reset_target(struct d2d_device_context *context)
+{
+    if (!context->target)
+        return;
+
+    ID2D1Bitmap1_Release(&context->target->ID2D1Bitmap1_iface);
+    context->target = NULL;
+
+    context->desc.dpiX = 96.0f;
+    context->desc.dpiY = 96.0f;
+
+    memset(&context->desc.pixelFormat, 0, sizeof(context->desc.pixelFormat));
+    memset(&context->pixel_size, 0, sizeof(context->pixel_size));
+
+    ID3D10BlendState_Release(context->bs);
+    context->bs = NULL;
+}
+
 static void STDMETHODCALLTYPE d2d_device_context_SetTarget(ID2D1DeviceContext *iface, ID2D1Image *target)
 {
-    FIXME("iface %p, target %p stub!\n", iface, target);
+    struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
+    struct d2d_bitmap *bitmap_impl;
+    D3D10_BLEND_DESC blend_desc;
+    ID2D1Bitmap *bitmap;
+    HRESULT hr;
+
+    TRACE("iface %p, target %p.\n", iface, target);
+
+    if (!target)
+    {
+        d2d_device_context_reset_target(context);
+        return;
+    }
+
+    if (FAILED(ID2D1Image_QueryInterface(target, &IID_ID2D1Bitmap, (void **)&bitmap)))
+    {
+        FIXME("Only bitmap targets are supported.\n");
+        return;
+    }
+
+    bitmap_impl = unsafe_impl_from_ID2D1Bitmap(bitmap);
+
+    if (!(bitmap_impl->options & D2D1_BITMAP_OPTIONS_TARGET))
+    {
+        context->error.code = D2DERR_INVALID_TARGET;
+        context->error.tag1 = context->drawing_state.tag1;
+        context->error.tag2 = context->drawing_state.tag2;
+        return;
+    }
+
+    d2d_device_context_reset_target(context);
+
+    /* Set sizes and pixel format. */
+    context->desc.dpiX = bitmap_impl->dpi_x;
+    context->desc.dpiY = bitmap_impl->dpi_y;
+    context->pixel_size = bitmap_impl->pixel_size;
+    context->desc.pixelFormat = bitmap_impl->format;
+    context->target = bitmap_impl;
+
+    memset(&blend_desc, 0, sizeof(blend_desc));
+    blend_desc.BlendEnable[0] = TRUE;
+    blend_desc.SrcBlend = D3D10_BLEND_ONE;
+    blend_desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
+    blend_desc.BlendOp = D3D10_BLEND_OP_ADD;
+    if (context->desc.pixelFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE)
+    {
+        blend_desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
+        blend_desc.DestBlendAlpha = D3D10_BLEND_ONE;
+    }
+    else
+    {
+        blend_desc.SrcBlendAlpha = D3D10_BLEND_ONE;
+        blend_desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
+    }
+    blend_desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
+    blend_desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
+    if (FAILED(hr = ID3D10Device_CreateBlendState(context->d3d_device, &blend_desc, &context->bs)))
+        WARN("Failed to create blend state, hr %#x.\n", hr);
 }
 
 static void STDMETHODCALLTYPE d2d_device_context_GetTarget(ID2D1DeviceContext *iface, ID2D1Image **target)
 {
-    FIXME("iface %p, target %p stub!\n", iface, target);
+    struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface);
+
+    TRACE("iface %p, target %p.\n", iface, target);
+
+    *target = context->target ? (ID2D1Image *)&context->target->ID2D1Bitmap1_iface : NULL;
+    if (*target)
+        ID2D1Image_AddRef(*target);
 }
 
 static void STDMETHODCALLTYPE d2d_device_context_SetRenderingControls(ID2D1DeviceContext *iface,
@@ -2538,7 +2623,7 @@ static HRESULT d2d_device_context_get_surface(struct d2d_device_context *render_
     ID3D10Resource *resource;
     HRESULT hr;
 
-    ID3D10RenderTargetView_GetResource(render_target->view, &resource);
+    ID3D10RenderTargetView_GetResource(render_target->target->rtv, &resource);
     hr = ID3D10Resource_QueryInterface(resource, &IID_IDXGISurface1, (void **)surface);
     ID3D10Resource_Release(resource);
     if (FAILED(hr))
@@ -2600,17 +2685,14 @@ static const struct ID2D1GdiInteropRenderTargetVtbl d2d_gdi_interop_render_targe
 };
 
 static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, ID2D1Device *device,
-        IDXGISurface *surface, IUnknown *outer_unknown, const struct d2d_device_context_ops *ops,
-        const D2D1_RENDER_TARGET_PROPERTIES *desc)
+        IUnknown *outer_unknown, const struct d2d_device_context_ops *ops)
 {
     D3D10_SUBRESOURCE_DATA buffer_data;
     D3D10_STATE_BLOCK_MASK state_mask;
-    DXGI_SURFACE_DESC surface_desc;
+    struct d2d_device *device_impl;
     IDWriteFactory *dwrite_factory;
     D3D10_RASTERIZER_DESC rs_desc;
     D3D10_BUFFER_DESC buffer_desc;
-    D3D10_BLEND_DESC blend_desc;
-    ID3D10Resource *resource;
     unsigned int i;
     HRESULT hr;
 
@@ -3460,25 +3542,6 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target,
         { 1.0f, -1.0f},
     };
     static const UINT16 indices[] = {0, 1, 2, 2, 1, 3};
-    float dpi_x, dpi_y;
-
-    dpi_x = desc->dpiX;
-    dpi_y = desc->dpiY;
-
-    if (dpi_x == 0.0f && dpi_y == 0.0f)
-    {
-        dpi_x = 96.0f;
-        dpi_y = 96.0f;
-    }
-    else if (dpi_x <= 0.0f || dpi_y <= 0.0f)
-        return E_INVALIDARG;
-
-    if (desc->type != D2D1_RENDER_TARGET_TYPE_DEFAULT && desc->type != D2D1_RENDER_TARGET_TYPE_HARDWARE)
-        WARN("Ignoring render target type %#x.\n", desc->type);
-    if (desc->usage != D2D1_RENDER_TARGET_USAGE_NONE)
-        FIXME("Ignoring render target usage %#x.\n", desc->usage);
-    if (desc->minLevel != D2D1_FEATURE_LEVEL_DEFAULT)
-        WARN("Ignoring feature level %#x.\n", desc->minLevel);
 
     render_target->ID2D1DeviceContext_iface.lpVtbl = &d2d_device_context_vtbl;
     render_target->ID2D1GdiInteropRenderTarget_iface.lpVtbl = &d2d_gdi_interop_render_target_vtbl;
@@ -3492,27 +3555,14 @@ 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;
 
-    if (FAILED(hr = IDXGISurface_GetDevice(surface, &IID_ID3D10Device, (void **)&render_target->d3d_device)))
+    device_impl = unsafe_impl_from_ID2D1Device(device);
+    if (FAILED(hr = IDXGIDevice_QueryInterface(device_impl->dxgi_device, &IID_ID3D10Device, (void **)&render_target->d3d_device)))
     {
         WARN("Failed to get device interface, hr %#x.\n", hr);
         ID2D1Factory_Release(render_target->factory);
         return hr;
     }
 
-    if (FAILED(hr = IDXGISurface_QueryInterface(surface, &IID_ID3D10Resource, (void **)&resource)))
-    {
-        WARN("Failed to get ID3D10Resource interface, hr %#x.\n", hr);
-        goto err;
-    }
-
-    hr = ID3D10Device_CreateRenderTargetView(render_target->d3d_device, resource, NULL, &render_target->view);
-    ID3D10Resource_Release(resource);
-    if (FAILED(hr))
-    {
-        WARN("Failed to create rendertarget view, hr %#x.\n", hr);
-        goto err;
-    }
-
     if (FAILED(hr = D3D10StateBlockMaskEnableAll(&state_mask)))
     {
         WARN("Failed to create stateblock mask, hr %#x.\n", hr);
@@ -3597,29 +3647,6 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target,
         goto err;
     }
 
-    memset(&blend_desc, 0, sizeof(blend_desc));
-    blend_desc.BlendEnable[0] = TRUE;
-    blend_desc.SrcBlend = D3D10_BLEND_ONE;
-    blend_desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
-    blend_desc.BlendOp = D3D10_BLEND_OP_ADD;
-    if (desc->pixelFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE)
-    {
-        blend_desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
-        blend_desc.DestBlendAlpha = D3D10_BLEND_ONE;
-    }
-    else
-    {
-        blend_desc.SrcBlendAlpha = D3D10_BLEND_ONE;
-        blend_desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
-    }
-    blend_desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
-    blend_desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
-    if (FAILED(hr = ID3D10Device_CreateBlendState(render_target->d3d_device, &blend_desc, &render_target->bs)))
-    {
-        WARN("Failed to create blend state, hr %#x.\n", hr);
-        goto err;
-    }
-
     if (FAILED(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
             &IID_IDWriteFactory, (IUnknown **)&dwrite_factory)))
     {
@@ -3635,15 +3662,6 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target,
         goto err;
     }
 
-    if (FAILED(hr = IDXGISurface_GetDesc(surface, &surface_desc)))
-    {
-        WARN("Failed to get surface desc, hr %#x.\n", hr);
-        goto err;
-    }
-
-    render_target->desc.pixelFormat = desc->pixelFormat;
-    render_target->pixel_size.width = surface_desc.Width;
-    render_target->pixel_size.height = surface_desc.Height;
     render_target->drawing_state.transform = identity;
 
     if (!d2d_clip_stack_init(&render_target->clip_stack))
@@ -3653,16 +3671,14 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target,
         goto err;
     }
 
-    render_target->desc.dpiX = dpi_x;
-    render_target->desc.dpiY = dpi_y;
+    render_target->desc.dpiX = 96.0f;
+    render_target->desc.dpiY = 96.0f;
 
     return S_OK;
 
 err:
     if (render_target->default_text_rendering_params)
         IDWriteRenderingParams_Release(render_target->default_text_rendering_params);
-    if (render_target->bs)
-        ID3D10BlendState_Release(render_target->bs);
     if (render_target->rs)
         ID3D10RasterizerState_Release(render_target->rs);
     if (render_target->vb)
@@ -3680,8 +3696,6 @@ err:
     }
     if (render_target->stateblock)
         render_target->stateblock->lpVtbl->Release(render_target->stateblock);
-    if (render_target->view)
-        ID3D10RenderTargetView_Release(render_target->view);
     if (render_target->d3d_device)
         ID3D10Device_Release(render_target->d3d_device);
     ID2D1Device_Release(render_target->device);
@@ -3692,65 +3706,62 @@ err:
 HRESULT d2d_d3d_create_render_target(ID2D1Device *device, IDXGISurface *surface, IUnknown *outer_unknown,
         const struct d2d_device_context_ops *ops, const D2D1_RENDER_TARGET_PROPERTIES *desc, void **render_target)
 {
+    D2D1_BITMAP_PROPERTIES1 bitmap_desc;
     struct d2d_device_context *object;
+    ID2D1Bitmap1 *bitmap;
     HRESULT hr;
 
+    if (desc->type != D2D1_RENDER_TARGET_TYPE_DEFAULT && desc->type != D2D1_RENDER_TARGET_TYPE_HARDWARE)
+        WARN("Ignoring render target type %#x.\n", desc->type);
+    if (desc->usage != D2D1_RENDER_TARGET_USAGE_NONE)
+        FIXME("Ignoring render target usage %#x.\n", desc->usage);
+    if (desc->minLevel != D2D1_FEATURE_LEVEL_DEFAULT)
+        WARN("Ignoring feature level %#x.\n", desc->minLevel);
+
+    bitmap_desc.dpiX = desc->dpiX;
+    bitmap_desc.dpiY = desc->dpiY;
+
+    if (bitmap_desc.dpiX == 0.0f && bitmap_desc.dpiY == 0.0f)
+    {
+        bitmap_desc.dpiX = 96.0f;
+        bitmap_desc.dpiY = 96.0f;
+    }
+    else if (bitmap_desc.dpiX <= 0.0f || bitmap_desc.dpiY <= 0.0f)
+        return E_INVALIDARG;
+
     if (!(object = heap_alloc_zero(sizeof(*object))))
         return E_OUTOFMEMORY;
 
-    if (FAILED(hr = d2d_device_context_init(object, device, surface, outer_unknown, ops, desc)))
+    if (FAILED(hr = d2d_device_context_init(object, device, outer_unknown, ops)))
     {
         WARN("Failed to initialize render target, hr %#x.\n", hr);
         heap_free(object);
         return hr;
     }
 
-    TRACE("Created render target %p.\n", object);
-    *render_target = outer_unknown ? &object->IUnknown_iface : (IUnknown *)&object->ID2D1DeviceContext_iface;
-
-    return S_OK;
-}
-
-HRESULT d2d_d3d_render_target_create_rtv(ID2D1RenderTarget *iface, IDXGISurface1 *surface)
-{
-    struct d2d_device_context *render_target = impl_from_ID2D1RenderTarget(iface);
-    DXGI_SURFACE_DESC surface_desc;
-    ID3D10RenderTargetView *view;
-    ID3D10Resource *resource;
-    HRESULT hr;
-
-    if (!surface)
+    if (surface)
     {
-        ID3D10RenderTargetView_Release(render_target->view);
-        render_target->view = NULL;
-        return S_OK;
-    }
-
-    if (FAILED(hr = IDXGISurface1_GetDesc(surface, &surface_desc)))
-    {
-        WARN("Failed to get surface desc, hr %#x.\n", hr);
-        return hr;
-    }
+        bitmap_desc.pixelFormat = desc->pixelFormat;
+        bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
+        bitmap_desc.colorContext = NULL;
 
-    if (FAILED(hr = IDXGISurface1_QueryInterface(surface, &IID_ID3D10Resource, (void **)&resource)))
-    {
-        WARN("Failed to get ID3D10Resource interface, hr %#x.\n", hr);
-        return hr;
-    }
+        if (FAILED(hr = ID2D1DeviceContext_CreateBitmapFromDxgiSurface(&object->ID2D1DeviceContext_iface, surface,
+                &bitmap_desc, &bitmap)))
+        {
+            WARN("Failed to create target bitmap, hr %#x.\n", hr);
+            ID2D1DeviceContext_Release(&object->ID2D1DeviceContext_iface);
+            heap_free(object);
+            return hr;
+        }
 
-    hr = ID3D10Device_CreateRenderTargetView(render_target->d3d_device, resource, NULL, &view);
-    ID3D10Resource_Release(resource);
-    if (FAILED(hr))
-    {
-        WARN("Failed to create rendertarget view, hr %#x.\n", hr);
-        return hr;
+        ID2D1DeviceContext_SetTarget(&object->ID2D1DeviceContext_iface, (ID2D1Image *)bitmap);
+        ID2D1Bitmap1_Release(bitmap);
     }
+    else
+        object->desc.pixelFormat = desc->pixelFormat;
 
-    render_target->pixel_size.width = surface_desc.Width;
-    render_target->pixel_size.height = surface_desc.Height;
-    if (render_target->view)
-        ID3D10RenderTargetView_Release(render_target->view);
-    render_target->view = view;
+    TRACE("Created render target %p.\n", object);
+    *render_target = outer_unknown ? &object->IUnknown_iface : (IUnknown *)&object->ID2D1DeviceContext_iface;
 
     return S_OK;
 }
@@ -3861,6 +3872,14 @@ static const struct ID2D1DeviceVtbl d2d_device_vtbl =
     d2d_device_ClearResources,
 };
 
+static struct d2d_device *unsafe_impl_from_ID2D1Device(ID2D1Device *iface)
+{
+    if (!iface)
+        return NULL;
+    assert(iface->lpVtbl == &d2d_device_vtbl);
+    return CONTAINING_RECORD(iface, struct d2d_device, ID2D1Device_iface);
+}
+
 void d2d_device_init(struct d2d_device *device, ID2D1Factory1 *iface, IDXGIDevice *dxgi_device)
 {
     device->ID2D1Device_iface.lpVtbl = &d2d_device_vtbl;
diff --git a/dlls/d2d1/hwnd_render_target.c b/dlls/d2d1/hwnd_render_target.c
index 9b8771f895..d0b9695933 100644
--- a/dlls/d2d1/hwnd_render_target.c
+++ b/dlls/d2d1/hwnd_render_target.c
@@ -675,11 +675,14 @@ static HRESULT STDMETHODCALLTYPE d2d_hwnd_render_target_Resize(ID2D1HwndRenderTa
 {
     struct d2d_hwnd_render_target *render_target = impl_from_ID2D1HwndRenderTarget(iface);
     IDXGISurface1 *dxgi_surface;
+    ID2D1DeviceContext *context;
+    ID2D1Bitmap1 *bitmap;
     HRESULT hr;
 
     TRACE("iface %p, width %u, height %u.\n", iface, size->width, size->height);
 
-    d2d_d3d_render_target_create_rtv(render_target->dxgi_target, NULL);
+    ID2D1RenderTarget_QueryInterface(render_target->dxgi_target, &IID_ID2D1DeviceContext, (void **)&context);
+    ID2D1DeviceContext_SetTarget(context, NULL);
 
     if (SUCCEEDED(hr = IDXGISwapChain_ResizeBuffers(render_target->swapchain, 1, size->width, size->height,
         DXGI_FORMAT_UNKNOWN, 0)))
@@ -688,13 +691,25 @@ static HRESULT STDMETHODCALLTYPE d2d_hwnd_render_target_Resize(ID2D1HwndRenderTa
                 (void **)&dxgi_surface)))
         {
             WARN("Failed to get buffer, hr %#x.\n", hr);
+            ID2D1DeviceContext_Release(context);
             return hr;
         }
 
-        hr = d2d_d3d_render_target_create_rtv(render_target->dxgi_target, dxgi_surface);
+        hr = ID2D1DeviceContext_CreateBitmapFromDxgiSurface(context, (IDXGISurface *)dxgi_surface, NULL, &bitmap);
         IDXGISurface1_Release(dxgi_surface);
+        if (FAILED(hr))
+        {
+            WARN("Failed to create target bitmap, hr %#x.\n", hr);
+            ID2D1DeviceContext_Release(context);
+            return hr;
+        }
+
+        ID2D1DeviceContext_SetTarget(context, (ID2D1Image *)bitmap);
+        ID2D1Bitmap1_Release(bitmap);
     }
 
+    ID2D1DeviceContext_Release(context);
+
     return hr;
 }
 
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index f4e2f1c39d..fd9b4de1af 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -821,6 +821,7 @@ static void check_bitmap_surface_(unsigned int line, ID2D1Bitmap *bitmap, BOOL h
                 break;
         }
 
+    todo_wine_if(options == D2D1_BITMAP_OPTIONS_TARGET)
         ok_(__FILE__, line)(desc.BindFlags == bind_flags, "Unexpected bind flags %#x, bitmap options %#x.\n",
                 desc.BindFlags, options);
         ok_(__FILE__, line)(desc.CPUAccessFlags == 0, "Unexpected cpu access flags %#x.\n", desc.CPUAccessFlags);
@@ -5289,10 +5290,7 @@ static void test_compatible_target_size(ID2D1RenderTarget *rt)
     {
         hr = ID2D1RenderTarget_CreateCompatibleRenderTarget(rt, size_tests[i].size, size_tests[i].pixel_size, NULL,
                 D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE, &bitmap_rt);
-    todo_wine
-        ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
-        if (FAILED(hr))
-            return;
+        ok(SUCCEEDED(hr), "%u: failed to create render target, hr %#x.\n", i, hr);
 
         if (size_tests[i].pixel_size)
             expected_size = *size_tests[i].pixel_size;
@@ -5521,13 +5519,11 @@ static void test_bitmap_target(void)
     ok(SUCCEEDED(hr), "Failed to create render target, hr %#x.\n", hr);
 
     pixel_size = ID2D1BitmapRenderTarget_GetPixelSize(rt);
-todo_wine
     ok(pixel_size.width == 0 && pixel_size.height == 0, "Got wrong size\n");
 
     hr = ID2D1BitmapRenderTarget_GetBitmap(rt, &bitmap);
     ok(SUCCEEDED(hr), "GetBitmap() failed, hr %#x.\n", hr);
     pixel_size = ID2D1Bitmap_GetPixelSize(bitmap);
-todo_wine
     ok(pixel_size.width == 0 && pixel_size.height == 0, "Got wrong size\n");
     ID2D1Bitmap_Release(bitmap);
 
@@ -6990,15 +6986,10 @@ static void check_rt_bitmap_surface_(unsigned int line, ID2D1RenderTarget *rt, B
 
         bitmap2 = NULL;
         ID2D1DeviceContext_GetTarget(context2, (ID2D1Image **)&bitmap2);
-    todo_wine
         ok_(__FILE__, line)(bitmap2 == bitmap, "Unexpected bitmap.\n");
 
-        if (bitmap2)
-        {
-            check_bitmap_surface_(line, bitmap, has_surface, D2D1_BITMAP_OPTIONS_TARGET);
-
-            ID2D1Bitmap_Release(bitmap2);
-        }
+        check_bitmap_surface_(line, bitmap, has_surface, D2D1_BITMAP_OPTIONS_TARGET);
+        ID2D1Bitmap_Release(bitmap2);
         ID2D1Bitmap_Release(bitmap);
 
         ID2D1BitmapRenderTarget_Release(compatible_rt);
@@ -7095,6 +7086,8 @@ static void test_bitmap_surface(void)
     ID2D1Bitmap1 *bitmap;
     ID2D1Device *device;
     ID2D1Image *target;
+    D2D1_SIZE_U size;
+    D2D1_TAG t1, t2;
     unsigned int i;
     HWND window;
     HRESULT hr;
@@ -7128,14 +7121,10 @@ static void test_bitmap_surface(void)
 
     bitmap = NULL;
     ID2D1DeviceContext_GetTarget(device_context, (ID2D1Image **)&bitmap);
-todo_wine
     ok(!!bitmap, "Unexpected target.\n");
-
-if (bitmap)
-{
     check_bitmap_surface((ID2D1Bitmap *)bitmap, TRUE, D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW);
     ID2D1Bitmap1_Release(bitmap);
-}
+
     check_rt_bitmap_surface(rt, TRUE, D2D1_BITMAP_OPTIONS_NONE);
 
     ID2D1DeviceContext_Release(device_context);
@@ -7213,8 +7202,45 @@ if (SUCCEEDED(hr))
 
     check_rt_bitmap_surface((ID2D1RenderTarget *)device_context, TRUE, D2D1_BITMAP_OPTIONS_NONE);
 
-    ID2D1DeviceContext_Release(device_context);
     ID2D1Bitmap1_Release(bitmap);
+
+    /* Without D2D1_BITMAP_OPTIONS_TARGET. */
+    memset(&bitmap_desc, 0, sizeof(bitmap_desc));
+    bitmap_desc.pixelFormat = ID2D1DeviceContext_GetPixelFormat(device_context);
+    size.width = size.height = 4;
+    hr = ID2D1DeviceContext_CreateBitmap(device_context, size, NULL, 0, &bitmap_desc, &bitmap);
+    ok(SUCCEEDED(hr), "Failed to create a bitmap, hr %#x.\n", hr);
+    check_bitmap_surface((ID2D1Bitmap *)bitmap, TRUE, D2D1_BITMAP_OPTIONS_NONE);
+    ID2D1DeviceContext_SetTags(device_context, 1, 2);
+
+    ID2D1DeviceContext_BeginDraw(device_context);
+    ID2D1DeviceContext_SetTarget(device_context, (ID2D1Image *)bitmap);
+    hr = ID2D1DeviceContext_EndDraw(device_context, &t1, &t2);
+    ok(hr == D2DERR_INVALID_TARGET, "Unexpected hr %#x.\n", hr);
+    ok(t1 == 1 && t2 == 2, "Unexpected tags.\n");
+
+    ID2D1Bitmap1_Release(bitmap);
+
+    ID2D1DeviceContext_GetTarget(device_context, (ID2D1Image **)&bitmap);
+    ok(!!bitmap, "Expected target bitmap.\n");
+    ID2D1Bitmap1_Release(bitmap);
+
+    bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
+    hr = ID2D1DeviceContext_CreateBitmap(device_context, size, NULL, 0, &bitmap_desc, &bitmap);
+    ok(SUCCEEDED(hr), "Failed to create a bitmap, hr %#x.\n", hr);
+    check_bitmap_surface((ID2D1Bitmap *)bitmap, TRUE, D2D1_BITMAP_OPTIONS_TARGET);
+    ID2D1DeviceContext_SetTarget(device_context, NULL);
+    ID2D1DeviceContext_SetTags(device_context, 3, 4);
+
+    ID2D1DeviceContext_BeginDraw(device_context);
+    ID2D1DeviceContext_SetTarget(device_context, (ID2D1Image *)bitmap);
+    hr = ID2D1DeviceContext_EndDraw(device_context, &t1, &t2);
+    ok(SUCCEEDED(hr), "EndDraw() failed, hr %#x.\n", hr);
+    ok(t1 == 0 && t2 == 0, "Unexpected tags.\n");
+
+    ID2D1Bitmap1_Release(bitmap);
+
+    ID2D1DeviceContext_Release(device_context);
 }
     ID2D1Device_Release(device);
     IDXGIDevice_Release(dxgi_device);
-- 
2.19.0




More information about the wine-devel mailing list