[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