[PATCH 3/4] d2d1: Implement SetTarget() for bitmap targets.

Nikolay Sivov nsivov at codeweavers.com
Tue Sep 25 19:34:49 CDT 2018


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/d2d1/d2d1_private.h |  14 ++-
 dlls/d2d1/device.c       | 245 +++++++++++++++++++++++++--------------
 dlls/d2d1/tests/d2d1.c   |   5 +-
 3 files changed, 170 insertions(+), 94 deletions(-)

diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h
index 726d143d86..ac42f7cf25 100644
--- a/dlls/d2d1/d2d1_private.h
+++ b/dlls/d2d1/d2d1_private.h
@@ -136,7 +136,6 @@ struct d2d_device_context
     ID2D1Factory *factory;
     ID2D1Device *device;
     ID3D10Device *d3d_device;
-    ID3D10RenderTargetView *view;
     ID3D10StateBlock *stateblock;
     struct d2d_shape_resources shape_resources[D2D_SHAPE_TYPE_COUNT];
     ID3D10PixelShader *ps;
@@ -146,6 +145,19 @@ struct d2d_device_context
     ID3D10RasterizerState *rs;
     ID3D10BlendState *bs;
 
+    struct
+    {
+        union
+        {
+            ID2D1Image *image;
+            struct
+            {
+                ID2D1Bitmap *bitmap;
+                ID3D10RenderTargetView *view;
+            } bitmap;
+        } u;
+    } target;
+
     struct d2d_error_state error;
     D2D1_DRAWING_STATE_DESCRIPTION1 drawing_state;
     IDWriteRenderingParams *text_rendering_params;
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c
index be31ecafc8..212e9c0df9 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.u.bitmap.view, 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,8 +275,11 @@ 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);
         ID3D10Device_Release(context->d3d_device);
+        if (context->target.u.bitmap.view)
+            ID3D10RenderTargetView_Release(context->target.u.bitmap.view);
+        if (context->target.u.image)
+            ID2D1Image_Release(context->target.u.image);
         ID2D1Factory_Release(context->factory);
         ID2D1Device_Release(context->device);
         heap_free(context);
@@ -1971,14 +1977,100 @@ 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.u.image)
+        return;
+
+    ID2D1Image_Release(context->target.u.image);
+    context->target.u.image = 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;
+
+    ID3D10RenderTargetView_Release(context->target.u.bitmap.view);
+    context->target.u.bitmap.view = 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;
+    ID3D10Resource *resource;
+    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_ID2D1Bitmap1, (void **)&bitmap)))
+    {
+        FIXME("Only bitmap targets are supported.\n");
+        return;
+    }
+
+    d2d_device_context_reset_target(context);
+
+    context->target.u.bitmap.bitmap = bitmap;
+
+    /* Set sizes and pixel format. */
+    ID2D1Bitmap_GetDpi(bitmap, &context->desc.dpiX, &context->desc.dpiY);
+    context->pixel_size = ID2D1Bitmap_GetPixelSize(bitmap);
+    context->desc.pixelFormat = ID2D1Bitmap_GetPixelFormat(bitmap);
+
+    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);
+        return;
+    }
+
+    bitmap_impl = unsafe_impl_from_ID2D1Bitmap(bitmap);
+    ID3D10ShaderResourceView_GetResource(bitmap_impl->view, &resource);
+
+    hr = ID3D10Device_CreateRenderTargetView(context->d3d_device, resource, NULL, &context->target.u.bitmap.view);
+    ID3D10Resource_Release(resource);
+    if (FAILED(hr))
+        WARN("Failed to create rendertarget view, 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.u.image;
+    if (*target)
+        ID2D1Image_AddRef(*target);
 }
 
 static void STDMETHODCALLTYPE d2d_device_context_SetRenderingControls(ID2D1DeviceContext *iface,
@@ -2530,7 +2622,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.u.bitmap.view, &resource);
     hr = ID3D10Resource_QueryInterface(resource, &IID_IDXGISurface1, (void **)surface);
     ID3D10Resource_Release(resource);
     if (FAILED(hr))
@@ -2592,17 +2684,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;
 
@@ -3452,25 +3541,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;
@@ -3484,27 +3554,15 @@ 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);
@@ -3589,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)))
     {
@@ -3627,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))
@@ -3645,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)
@@ -3672,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);
@@ -3684,19 +3706,55 @@ 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;
     }
 
+    bitmap_desc.pixelFormat = desc->pixelFormat;
+    bitmap_desc.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
+    bitmap_desc.colorContext = NULL;
+
+    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;
+    }
+
+    ID2D1DeviceContext_SetTarget(&object->ID2D1DeviceContext_iface, (ID2D1Image *)bitmap);
+    ID2D1Bitmap1_Release(bitmap);
+
     TRACE("Created render target %p.\n", object);
     *render_target = outer_unknown ? &object->IUnknown_iface : (IUnknown *)&object->ID2D1DeviceContext_iface;
 
@@ -3713,8 +3771,9 @@ HRESULT d2d_d3d_render_target_create_rtv(ID2D1RenderTarget *iface, IDXGISurface1
 
     if (!surface)
     {
-        ID3D10RenderTargetView_Release(render_target->view);
-        render_target->view = NULL;
+        if (render_target->target.u.bitmap.view)
+            ID3D10RenderTargetView_Release(render_target->target.u.bitmap.view);
+        render_target->target.u.bitmap.view = NULL;
         return S_OK;
     }
 
@@ -3740,9 +3799,9 @@ HRESULT d2d_d3d_render_target_create_rtv(ID2D1RenderTarget *iface, IDXGISurface1
 
     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;
+    if (render_target->target.u.bitmap.view)
+        ID3D10RenderTargetView_Release(render_target->target.u.bitmap.view);
+    render_target->target.u.bitmap.view = view;
 
     return S_OK;
 }
@@ -3853,6 +3912,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/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index 3005b43e44..c2e0ab2a08 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -6943,14 +6943,11 @@ 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);
-- 
2.19.0




More information about the wine-devel mailing list