Signed-off-by: Nikolay Sivov nsivov@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);