Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/d2d1_private.h | 23 ++++ dlls/d2d1/effect.c | 256 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 278 insertions(+), 1 deletion(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index aa8e8569455..98092d80951 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -34,6 +34,7 @@ #include "initguid.h" #endif #include "dwrite_2.h" +#include "d2d1effectauthor.h"
enum d2d_brush_type { @@ -567,6 +568,14 @@ struct d2d_device
void d2d_device_init(struct d2d_device *device, ID2D1Factory1 *factory, IDXGIDevice *dxgi_device) DECLSPEC_HIDDEN;
+struct d2d_effect_context +{ + ID2D1EffectContext ID2D1EffectContext_iface; + LONG refcount; +}; + +void d2d_effect_context_init(struct d2d_effect_context *effect_context) DECLSPEC_HIDDEN; + struct d2d_effect_info { const CLSID *clsid; @@ -694,6 +703,13 @@ static inline const char *debug_d2d_point_2f(const D2D1_POINT_2F *point) return wine_dbg_sprintf("{%.8e, %.8e}", point->x, point->y); }
+static inline const char *debug_d2d_point_2l(const D2D1_POINT_2L *point) +{ + if (!point) + return "(null)"; + return wine_dbg_sprintf("{%ld, %ld}", point->x, point->y); +} + static inline const char *debug_d2d_rect_f(const D2D1_RECT_F *rect) { if (!rect) @@ -701,6 +717,13 @@ static inline const char *debug_d2d_rect_f(const D2D1_RECT_F *rect) return wine_dbg_sprintf("(%.8e, %.8e)-(%.8e, %.8e)", rect->left, rect->top, rect->right, rect->bottom); }
+static inline const char *debug_d2d_rect_l(const D2D1_RECT_L *rect) +{ + if (!rect) + return "(null)"; + return wine_dbg_sprintf("(%ld, %ld)-(%ld, %ld)", rect->left, rect->top, rect->right, rect->bottom); +} + static inline const char *debug_d2d_rounded_rect(const D2D1_ROUNDED_RECT *rounded_rect) { if (!rounded_rect) diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 350ac3c7bbf..5709afed7a5 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -17,7 +17,6 @@ */
#include "d2d1_private.h" -#include "d2d1effectauthor.h"
WINE_DEFAULT_DEBUG_CHANNEL(d2d);
@@ -31,6 +30,261 @@ static const struct d2d_effect_info builtin_effects[] = {&CLSID_D2D1Grayscale, 1, 1, 1}, };
+static inline struct d2d_effect_context *impl_from_ID2D1EffectContext(ID2D1EffectContext *iface) +{ + return CONTAINING_RECORD(iface, struct d2d_effect_context, ID2D1EffectContext_iface); +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_QueryInterface(ID2D1EffectContext *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_ID2D1EffectContext) + || IsEqualGUID(iid, &IID_IUnknown)) + { + ID2D1EffectContext_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE d2d_effect_context_AddRef(ID2D1EffectContext *iface) +{ + struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface); + ULONG refcount = InterlockedIncrement(&effect_context->refcount); + + TRACE("%p increasing refcount to %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE d2d_effect_context_Release(ID2D1EffectContext *iface) +{ + struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface); + ULONG refcount = InterlockedDecrement(&effect_context->refcount); + + TRACE("%p decreasing refcount to %lu.\n", iface, refcount); + + if (!refcount) + { + heap_free(effect_context); + } + + return refcount; +} + +static void STDMETHODCALLTYPE d2d_effect_context_GetDpi(ID2D1EffectContext *iface, float *dpi_x, float *dpi_y) +{ + FIXME("iface %p, dpi_x %p, dpi_y %p stub!\n", iface, dpi_x, dpi_y); +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateEffect(ID2D1EffectContext *iface, + REFCLSID clsid, ID2D1Effect **effect) +{ + FIXME("iface %p, clsid %s, effect %p stub!\n", iface, debugstr_guid(clsid), effect); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_GetMaximumSupportedFeatureLevel(ID2D1EffectContext *iface, + const D3D_FEATURE_LEVEL *levels, UINT32 level_count, D3D_FEATURE_LEVEL *max_level) +{ + FIXME("iface %p, levels %p, level_count %u, max_level %p stub!\n", iface, levels, level_count, max_level); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateTransformNodeFromEffect(ID2D1EffectContext *iface, + ID2D1Effect *effect, ID2D1TransformNode **node) +{ + FIXME("iface %p, effect %p, node %p stub!\n", iface, effect, node); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateBlendTransform(ID2D1EffectContext *iface, + UINT32 num_inputs, const D2D1_BLEND_DESCRIPTION *description, ID2D1BlendTransform **transform) +{ + FIXME("iface %p, num_inputs %u, description %p, transform %p stub!\n", iface, num_inputs, description, transform); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateBorderTransform(ID2D1EffectContext *iface, + D2D1_EXTEND_MODE mode_x, D2D1_EXTEND_MODE mode_y, ID2D1BorderTransform **transform) +{ + FIXME("iface %p, mode_x %#x, mode_y %#x, transform %p stub!\n", iface, mode_x, mode_y, transform); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateOffsetTransform(ID2D1EffectContext *iface, + D2D1_POINT_2L offset, ID2D1OffsetTransform **transform) +{ + FIXME("iface %p, offset %s, transform %p stub!\n", iface, debug_d2d_point_2l(&offset), transform); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateBoundsAdjustmentTransform(ID2D1EffectContext *iface, + const D2D1_RECT_L *output_rect, ID2D1BoundsAdjustmentTransform **transform) +{ + FIXME("iface %p, output_rect %s, transform %p stub!\n", iface, debug_d2d_rect_l(output_rect), transform); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadPixelShader(ID2D1EffectContext *iface, + REFGUID shader_id, const BYTE *buffer, UINT32 buffer_size) +{ + FIXME("iface %p, shader_id %s, buffer %p, buffer_size %u stub!\n", + iface, debugstr_guid(shader_id), buffer, buffer_size); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadVertexShader(ID2D1EffectContext *iface, + REFGUID shader_id, const BYTE *buffer, UINT32 buffer_size) +{ + FIXME("iface %p, shader_id %s, buffer %p, buffer_size %u stub!\n", + iface, debugstr_guid(shader_id), buffer, buffer_size); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadComputeShader(ID2D1EffectContext *iface, + REFGUID shader_id, const BYTE *buffer, UINT32 buffer_size) +{ + FIXME("iface %p, shader_id %s, buffer %p, buffer_size %u stub!\n", + iface, debugstr_guid(shader_id), buffer, buffer_size); + + return E_NOTIMPL; +} + +static BOOL STDMETHODCALLTYPE d2d_effect_context_IsShaderLoaded(ID2D1EffectContext *iface, REFGUID shader_id) +{ + FIXME("iface %p, shader_id %s stub!\n", iface, debugstr_guid(shader_id)); + + return FALSE; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateResourceTexture(ID2D1EffectContext *iface, + const GUID *id, const D2D1_RESOURCE_TEXTURE_PROPERTIES *texture_properties, + const BYTE *data, const UINT32 *strides, UINT32 data_size, ID2D1ResourceTexture **texture) +{ + FIXME("iface %p, id %s, texture_properties %p, data %p, strides %s, data_size %u, texture %p stub!\n", + iface, debugstr_guid(id), texture_properties, data, + strides ? wine_dbg_sprintf("%u", *strides) : "(null)", data_size, texture); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_FindResourceTexture(ID2D1EffectContext *iface, + const GUID *id, ID2D1ResourceTexture **texture) +{ + FIXME("iface %p, id %s, texture %p stub!\n", iface, debugstr_guid(id), texture); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateVertexBuffer(ID2D1EffectContext *iface, + const D2D1_VERTEX_BUFFER_PROPERTIES *buffer_properties, const GUID *id, + const D2D1_CUSTOM_VERTEX_BUFFER_PROPERTIES *custom_buffer_properties, ID2D1VertexBuffer **buffer) +{ + FIXME("iface %p, buffer_properties %p, id %s, custom_buffer_properties %p, buffer %p stub!\n", + iface, buffer_properties, debugstr_guid(id), custom_buffer_properties, buffer); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_FindVertexBuffer(ID2D1EffectContext *iface, + const GUID *id, ID2D1VertexBuffer **buffer) +{ + FIXME("iface %p, id %s, buffer %p stub!\n", iface, debugstr_guid(id), buffer); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateColorContext(ID2D1EffectContext *iface, + D2D1_COLOR_SPACE space, const BYTE *profile, UINT32 profile_size, ID2D1ColorContext **color_context) +{ + FIXME("iface %p, space %#x, profile %p, profile_size %u, color_context %p stub!\n", + iface, space, profile, profile_size, color_context); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateColorContextFromFilename(ID2D1EffectContext *iface, + const WCHAR *filename, ID2D1ColorContext **color_context) +{ + FIXME("iface %p, filename %s, color_context %p stub!\n", iface, debugstr_w(filename), color_context); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateColorContextFromWicColorContext(ID2D1EffectContext *iface, + IWICColorContext *wic_color_context, ID2D1ColorContext **color_context) +{ + FIXME("iface %p, wic_color_context %p, color_context %p stub!\n", iface, wic_color_context, color_context); + + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE d2d_effect_context_CheckFeatureSupport(ID2D1EffectContext *iface, + D2D1_FEATURE feature, void *data, UINT32 data_size) +{ + FIXME("iface %p, feature %#x, data %p, data_size %u stub!\n", iface, feature, data, data_size); + + return E_NOTIMPL; +} + +static BOOL STDMETHODCALLTYPE d2d_effect_context_IsBufferPrecisionSupported(ID2D1EffectContext *iface, + D2D1_BUFFER_PRECISION precision) +{ + FIXME("iface %p, precision %#x stub!\n", iface, precision); + + return FALSE; +} + +static const ID2D1EffectContextVtbl d2d_effect_context_vtbl = +{ + d2d_effect_context_QueryInterface, + d2d_effect_context_AddRef, + d2d_effect_context_Release, + d2d_effect_context_GetDpi, + d2d_effect_context_CreateEffect, + d2d_effect_context_GetMaximumSupportedFeatureLevel, + d2d_effect_context_CreateTransformNodeFromEffect, + d2d_effect_context_CreateBlendTransform, + d2d_effect_context_CreateBorderTransform, + d2d_effect_context_CreateOffsetTransform, + d2d_effect_context_CreateBoundsAdjustmentTransform, + d2d_effect_context_LoadPixelShader, + d2d_effect_context_LoadVertexShader, + d2d_effect_context_LoadComputeShader, + d2d_effect_context_IsShaderLoaded, + d2d_effect_context_CreateResourceTexture, + d2d_effect_context_FindResourceTexture, + d2d_effect_context_CreateVertexBuffer, + d2d_effect_context_FindVertexBuffer, + d2d_effect_context_CreateColorContext, + d2d_effect_context_CreateColorContextFromFilename, + d2d_effect_context_CreateColorContextFromWicColorContext, + d2d_effect_context_CheckFeatureSupport, + d2d_effect_context_IsBufferPrecisionSupported, +}; + +void d2d_effect_context_init(struct d2d_effect_context *effect_context) +{ + effect_context->ID2D1EffectContext_iface.lpVtbl = &d2d_effect_context_vtbl; + effect_context->refcount = 1; +} + static inline struct d2d_effect *impl_from_ID2D1Effect(ID2D1Effect *iface) { return CONTAINING_RECORD(iface, struct d2d_effect, ID2D1Effect_iface);
Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/d2d1_private.h | 5 ++++- dlls/d2d1/effect.c | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 98092d80951..bc07378bd20 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -572,9 +572,12 @@ struct d2d_effect_context { ID2D1EffectContext ID2D1EffectContext_iface; LONG refcount; + + ID2D1DeviceContext *device_context; };
-void d2d_effect_context_init(struct d2d_effect_context *effect_context) DECLSPEC_HIDDEN; +void d2d_effect_context_init(struct d2d_effect_context *effect_context, + ID2D1DeviceContext *device_context) DECLSPEC_HIDDEN;
struct d2d_effect_info { diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 5709afed7a5..74878a620b4 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -72,6 +72,7 @@ static ULONG STDMETHODCALLTYPE d2d_effect_context_Release(ID2D1EffectContext *if
if (!refcount) { + ID2D1DeviceContext_Release(effect_context->device_context); heap_free(effect_context); }
@@ -279,10 +280,11 @@ static const ID2D1EffectContextVtbl d2d_effect_context_vtbl = d2d_effect_context_IsBufferPrecisionSupported, };
-void d2d_effect_context_init(struct d2d_effect_context *effect_context) +void d2d_effect_context_init(struct d2d_effect_context *effect_context, ID2D1DeviceContext *device_context) { effect_context->ID2D1EffectContext_iface.lpVtbl = &d2d_effect_context_vtbl; effect_context->refcount = 1; + ID2D1DeviceContext_AddRef(effect_context->device_context = device_context); }
static inline struct d2d_effect *impl_from_ID2D1Effect(ID2D1Effect *iface)
Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/effect.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 74878a620b4..ec12375cd9c 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -81,7 +81,11 @@ static ULONG STDMETHODCALLTYPE d2d_effect_context_Release(ID2D1EffectContext *if
static void STDMETHODCALLTYPE d2d_effect_context_GetDpi(ID2D1EffectContext *iface, float *dpi_x, float *dpi_y) { - FIXME("iface %p, dpi_x %p, dpi_y %p stub!\n", iface, dpi_x, dpi_y); + struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface); + + TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y); + + return ID2D1DeviceContext_GetDpi(effect_context->device_context, dpi_x, dpi_y); }
static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateEffect(ID2D1EffectContext *iface,
On 4/28/22 13:40, Ziqing Hui wrote:
static void STDMETHODCALLTYPE d2d_effect_context_GetDpi(ID2D1EffectContext *iface, float *dpi_x, float *dpi_y) {
- FIXME("iface %p, dpi_x %p, dpi_y %p stub!\n", iface, dpi_x, dpi_y);
struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
return ID2D1DeviceContext_GetDpi(effect_context->device_context, dpi_x, dpi_y); }
static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateEffect(ID2D1EffectContext *iface,
Were you able to test this? I realize it requires a minimal custom effect to access context object. It makes sense I guess to forward it like you did, as opposed to returning dpi at the time of CreateEffect() call, but it not obvious just from this patch.
Note that you don't need "return" here.
On 4/29/22 3:39 PM, Nikolay Sivov wrote:
On 4/28/22 13:40, Ziqing Hui wrote:
static void STDMETHODCALLTYPE d2d_effect_context_GetDpi(ID2D1EffectContext *iface, float *dpi_x, float *dpi_y) { - FIXME("iface %p, dpi_x %p, dpi_y %p stub!\n", iface, dpi_x, dpi_y); + struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface);
+ TRACE("iface %p, dpi_x %p, dpi_y %p.\n", iface, dpi_x, dpi_y);
+ return ID2D1DeviceContext_GetDpi(effect_context->device_context, dpi_x, dpi_y); } static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateEffect(ID2D1EffectContext *iface,
Were you able to test this? I realize it requires a minimal custom effect to access context object. It makes sense I guess to forward it like you did, as opposed to returning dpi at the time of CreateEffect() call, but it not obvious just from this patch.
Note that you don't need "return" here.
Yeah, it can be tested. I can construct a custom effect and test effect context functions in its implementation.
In fact I have already had some custom effect test code in my local branch.
Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/d2d1_private.h | 1 + dlls/d2d1/effect.c | 2 ++ 2 files changed, 3 insertions(+)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index bc07378bd20..eb2f71f7c03 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -573,6 +573,7 @@ struct d2d_effect_context ID2D1EffectContext ID2D1EffectContext_iface; LONG refcount;
+ ID2D1Factory *factory; ID2D1DeviceContext *device_context; };
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index ec12375cd9c..bfb2e9d16d9 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -73,6 +73,7 @@ static ULONG STDMETHODCALLTYPE d2d_effect_context_Release(ID2D1EffectContext *if if (!refcount) { ID2D1DeviceContext_Release(effect_context->device_context); + ID2D1Factory_Release(effect_context->factory); heap_free(effect_context); }
@@ -288,6 +289,7 @@ void d2d_effect_context_init(struct d2d_effect_context *effect_context, ID2D1Dev { effect_context->ID2D1EffectContext_iface.lpVtbl = &d2d_effect_context_vtbl; effect_context->refcount = 1; + ID2D1DeviceContext_GetFactory(device_context, &effect_context->factory); ID2D1DeviceContext_AddRef(effect_context->device_context = device_context); }
Signed-off-by: Ziqing Hui zhui@codeweavers.com ---
We hold an effect context reference in effect.
See https://docs.microsoft.com/en-us/windows/win32/api/d2d1effectauthor/nn-d2d1e...
"Each call to ID2D1EffectImpl::Initialize will be provided a different ID2D1EffectContext interface."
This means that device context and effect context are not one-on-one. And each effect has an effect context.
"This interface tracks resource allocations for the effect. When the effect is released, the corresponding allocations will also be released."
dlls/d2d1/d2d1_private.h | 4 +++- dlls/d2d1/device.c | 18 ++++++------------ dlls/d2d1/effect.c | 27 +++++++++++++++++++++++---- 3 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index eb2f71f7c03..8f8ffc5fd0e 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -597,12 +597,14 @@ struct d2d_effect const struct d2d_effect_info *info;
ID2D1Factory *factory; + ID2D1EffectContext *effect_context; ID2D1Image **inputs; size_t inputs_size; size_t input_count; };
-HRESULT d2d_effect_init(struct d2d_effect *effect, ID2D1Factory *factory, const CLSID *effect_id) DECLSPEC_HIDDEN; +HRESULT d2d_effect_init(struct d2d_effect *effect, + struct d2d_effect_context *effect_context, const CLSID *effect_id) DECLSPEC_HIDDEN;
static inline BOOL d2d_array_reserve(void **elements, size_t *capacity, size_t count, size_t size) { diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 13c99458cfa..03195c8c557 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -1890,25 +1890,19 @@ static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateEffect(ID2D1DeviceCont REFCLSID effect_id, ID2D1Effect **effect) { struct d2d_device_context *context = impl_from_ID2D1DeviceContext(iface); - struct d2d_effect *object; + struct d2d_effect_context *effect_context; HRESULT hr;
FIXME("iface %p, effect_id %s, effect %p stub!\n", iface, debugstr_guid(effect_id), effect);
- if (!(object = heap_alloc_zero(sizeof(*object)))) + if (!(effect_context = heap_alloc_zero(sizeof(*effect_context)))) return E_OUTOFMEMORY; + d2d_effect_context_init(effect_context, iface);
- if (FAILED(hr = d2d_effect_init(object, context->factory, effect_id))) - { - WARN("Failed to initialise effect, hr %#lx.\n", hr); - heap_free(object); - return hr; - } + hr = ID2D1EffectContext_CreateEffect(&effect_context->ID2D1EffectContext_iface, effect_id, effect);
- TRACE("Created effect %p.\n", object); - *effect = &object->ID2D1Effect_iface; - - return S_OK; + ID2D1EffectContext_Release(&effect_context->ID2D1EffectContext_iface); + return hr; }
static HRESULT STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_CreateGradientStopCollection( diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index bfb2e9d16d9..b14c2fae373 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -92,9 +92,26 @@ static void STDMETHODCALLTYPE d2d_effect_context_GetDpi(ID2D1EffectContext *ifac static HRESULT STDMETHODCALLTYPE d2d_effect_context_CreateEffect(ID2D1EffectContext *iface, REFCLSID clsid, ID2D1Effect **effect) { - FIXME("iface %p, clsid %s, effect %p stub!\n", iface, debugstr_guid(clsid), effect); + struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface); + struct d2d_effect *object; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, clsid %s, effect %p.\n", iface, debugstr_guid(clsid), effect); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = d2d_effect_init(object, effect_context, clsid))) + { + WARN("Failed to initialise effect, hr %#lx.\n", hr); + heap_free(object); + return hr; + } + + TRACE("Created effect %p.\n", object); + *effect = &object->ID2D1Effect_iface; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_effect_context_GetMaximumSupportedFeatureLevel(ID2D1EffectContext *iface, @@ -308,6 +325,7 @@ static void d2d_effect_cleanup(struct d2d_effect *effect) ID2D1Image_Release(effect->inputs[i]); } heap_free(effect->inputs); + ID2D1EffectContext_Release(effect->effect_context); ID2D1Factory_Release(effect->factory); }
@@ -635,7 +653,7 @@ static const ID2D1ImageVtbl d2d_effect_image_vtbl = d2d_effect_image_GetFactory, };
-HRESULT d2d_effect_init(struct d2d_effect *effect, ID2D1Factory *factory, const CLSID *effect_id) +HRESULT d2d_effect_init(struct d2d_effect *effect, struct d2d_effect_context *effect_context, const CLSID *effect_id) { unsigned int i;
@@ -649,7 +667,8 @@ HRESULT d2d_effect_init(struct d2d_effect *effect, ID2D1Factory *factory, const { effect->info = &builtin_effects[i]; d2d_effect_SetInputCount(&effect->ID2D1Effect_iface, effect->info->default_input_count); - ID2D1Factory_AddRef(effect->factory = factory); + ID2D1Factory_AddRef(effect->factory = effect_context->factory); + ID2D1EffectContext_AddRef(effect->effect_context = &effect_context->ID2D1EffectContext_iface); return S_OK; } }
Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/effect.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index b14c2fae373..566a4cf1523 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -35,6 +35,12 @@ static inline struct d2d_effect_context *impl_from_ID2D1EffectContext(ID2D1Effec return CONTAINING_RECORD(iface, struct d2d_effect_context, ID2D1EffectContext_iface); }
+static void d2d_effect_context_cleanup(struct d2d_effect_context *effect_context) +{ + ID2D1DeviceContext_Release(effect_context->device_context); + ID2D1Factory_Release(effect_context->factory); +} + static HRESULT STDMETHODCALLTYPE d2d_effect_context_QueryInterface(ID2D1EffectContext *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -72,8 +78,7 @@ static ULONG STDMETHODCALLTYPE d2d_effect_context_Release(ID2D1EffectContext *if
if (!refcount) { - ID2D1DeviceContext_Release(effect_context->device_context); - ID2D1Factory_Release(effect_context->factory); + d2d_effect_context_cleanup(effect_context); heap_free(effect_context); }
Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/d2d1_private.h | 3 ++- dlls/d2d1/device.c | 2 +- dlls/d2d1/effect.c | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 8f8ffc5fd0e..8b7b0b7a3d5 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -575,10 +575,11 @@ struct d2d_effect_context
ID2D1Factory *factory; ID2D1DeviceContext *device_context; + ID3D11Device1 *d3d_device; };
void d2d_effect_context_init(struct d2d_effect_context *effect_context, - ID2D1DeviceContext *device_context) DECLSPEC_HIDDEN; + struct d2d_device_context *device_context) DECLSPEC_HIDDEN;
struct d2d_effect_info { diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 03195c8c557..80badcddaac 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -1897,7 +1897,7 @@ static HRESULT STDMETHODCALLTYPE d2d_device_context_CreateEffect(ID2D1DeviceCont
if (!(effect_context = heap_alloc_zero(sizeof(*effect_context)))) return E_OUTOFMEMORY; - d2d_effect_context_init(effect_context, iface); + d2d_effect_context_init(effect_context, context);
hr = ID2D1EffectContext_CreateEffect(&effect_context->ID2D1EffectContext_iface, effect_id, effect);
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 566a4cf1523..60597919c91 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -37,6 +37,7 @@ static inline struct d2d_effect_context *impl_from_ID2D1EffectContext(ID2D1Effec
static void d2d_effect_context_cleanup(struct d2d_effect_context *effect_context) { + ID3D11Device1_Release(effect_context->d3d_device); ID2D1DeviceContext_Release(effect_context->device_context); ID2D1Factory_Release(effect_context->factory); } @@ -307,12 +308,13 @@ static const ID2D1EffectContextVtbl d2d_effect_context_vtbl = d2d_effect_context_IsBufferPrecisionSupported, };
-void d2d_effect_context_init(struct d2d_effect_context *effect_context, ID2D1DeviceContext *device_context) +void d2d_effect_context_init(struct d2d_effect_context *effect_context, struct d2d_device_context *device_context) { effect_context->ID2D1EffectContext_iface.lpVtbl = &d2d_effect_context_vtbl; effect_context->refcount = 1; - ID2D1DeviceContext_GetFactory(device_context, &effect_context->factory); - ID2D1DeviceContext_AddRef(effect_context->device_context = device_context); + ID2D1Factory_AddRef(effect_context->factory = device_context->factory); + ID2D1DeviceContext_AddRef(effect_context->device_context = &device_context->ID2D1DeviceContext_iface); + ID3D11Device1_AddRef(effect_context->d3d_device = device_context->d3d_device); }
static inline struct d2d_effect *impl_from_ID2D1Effect(ID2D1Effect *iface)
Signed-off-by: Ziqing Hui zhui@codeweavers.com --- dlls/d2d1/d2d1_private.h | 10 ++++++++++ dlls/d2d1/effect.c | 41 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 8b7b0b7a3d5..cc275de47ec 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -568,6 +568,12 @@ struct d2d_device
void d2d_device_init(struct d2d_device *device, ID2D1Factory1 *factory, IDXGIDevice *dxgi_device) DECLSPEC_HIDDEN;
+struct d2d_shader +{ + const GUID *id; + void *shader; +}; + struct d2d_effect_context { ID2D1EffectContext ID2D1EffectContext_iface; @@ -576,6 +582,10 @@ struct d2d_effect_context ID2D1Factory *factory; ID2D1DeviceContext *device_context; ID3D11Device1 *d3d_device; + + struct d2d_shader *shaders; + size_t shaders_size; + size_t shader_count; };
void d2d_effect_context_init(struct d2d_effect_context *effect_context, diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 60597919c91..fda1a64ea70 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -37,6 +37,15 @@ static inline struct d2d_effect_context *impl_from_ID2D1EffectContext(ID2D1Effec
static void d2d_effect_context_cleanup(struct d2d_effect_context *effect_context) { + unsigned int i; + + for (i = 0; i < effect_context->shader_count; ++i) + { + if (effect_context->shaders[i].shader) + IUnknown_Release((IUnknown *)effect_context->shaders[i].shader); + } + heap_free(effect_context->shaders); + ID3D11Device1_Release(effect_context->d3d_device); ID2D1DeviceContext_Release(effect_context->device_context); ID2D1Factory_Release(effect_context->factory); @@ -180,10 +189,38 @@ static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadPixelShader(ID2D1EffectC static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadVertexShader(ID2D1EffectContext *iface, REFGUID shader_id, const BYTE *buffer, UINT32 buffer_size) { - FIXME("iface %p, shader_id %s, buffer %p, buffer_size %u stub!\n", + struct d2d_effect_context *effect_context = impl_from_ID2D1EffectContext(iface); + ID3D11VertexShader *vertex_shader; + struct d2d_shader *shader; + HRESULT hr; + + TRACE("iface %p, shader_id %s, buffer %p, buffer_size %u.\n", iface, debugstr_guid(shader_id), buffer, buffer_size);
- return E_NOTIMPL; + if (FAILED(hr = ID3D11Device1_CreateVertexShader(effect_context->d3d_device, + buffer, buffer_size, NULL, &vertex_shader))) + { + WARN("Failed to create vertex shader, hr %#lx.\n", hr); + return hr; + } + + effect_context->shader_count++; + if (effect_context->shaders_size < effect_context->shader_count) + { + if (!d2d_array_reserve((void **)&effect_context->shaders, &effect_context->shaders_size, + effect_context->shader_count, sizeof(*effect_context->shaders))) + { + ERR("Failed to resize shaders array.\n"); + ID3D11VertexShader_Release(vertex_shader); + return E_OUTOFMEMORY; + } + } + + shader = &effect_context->shaders[effect_context->shader_count - 1]; + shader->id = shader_id; + shader->shader = vertex_shader; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_effect_context_LoadComputeShader(ID2D1EffectContext *iface,
On 4/28/22 13:40, Ziqing Hui wrote:
+struct d2d_shader +{
- const GUID *id;
- void *shader;
+};
This could at least use IUnknown, you can probably use a union later to avoid casts.
- effect_context->shader_count++;
- if (effect_context->shaders_size < effect_context->shader_count)
- {
if (!d2d_array_reserve((void **)&effect_context->shaders, &effect_context->shaders_size,
effect_context->shader_count, sizeof(*effect_context->shaders)))
{
ERR("Failed to resize shaders array.\n");
ID3D11VertexShader_Release(vertex_shader);
return E_OUTOFMEMORY;
}
- }
You should call this to reserve "effect_context->shader_count + 1", no need to check size < count explicitly.
Since this is using GUIDs for keys, I suspect it should check for duplicates? IsShaderLoaded() takes just a GUID, so that implies all shader types are in the same list most likely.
By the way, have you figured out how shader objects are used later?
On 4/29/22 2:02 PM, Nikolay Sivov wrote:
On 4/28/22 13:40, Ziqing Hui wrote:
+struct d2d_shader +{ + const GUID *id; + void *shader; +};
This could at least use IUnknown, you can probably use a union later to avoid casts.
+ effect_context->shader_count++; + if (effect_context->shaders_size < effect_context->shader_count) + { + if (!d2d_array_reserve((void **)&effect_context->shaders, &effect_context->shaders_size, + effect_context->shader_count, sizeof(*effect_context->shaders))) + { + ERR("Failed to resize shaders array.\n"); + ID3D11VertexShader_Release(vertex_shader); + return E_OUTOFMEMORY; + } + }
You should call this to reserve "effect_context->shader_count + 1", no need to check size < count explicitly.
Since this is using GUIDs for keys, I suspect it should check for duplicates? IsShaderLoaded() takes just a GUID, so that implies all shader types are in the same list most likely.
By the way, have you figured out how shader objects are used later?
Shader objects will be used in ID2D1DrawTransform to create custom transforms which have custom shaders.
ID2D1DrawTransfrom use ID2D1DrawInfo that has functions like SetPixelShader() which accept shader GUID as an input argument. And that's where the loaded shader objects are used.
On 4/29/22 09:50, Ziqing Hui wrote:
On 4/29/22 2:02 PM, Nikolay Sivov wrote:
On 4/28/22 13:40, Ziqing Hui wrote:
+struct d2d_shader +{ + const GUID *id; + void *shader; +};
This could at least use IUnknown, you can probably use a union later to avoid casts.
+ effect_context->shader_count++; + if (effect_context->shaders_size < effect_context->shader_count) + { + if (!d2d_array_reserve((void **)&effect_context->shaders, &effect_context->shaders_size, + effect_context->shader_count, sizeof(*effect_context->shaders))) + { + ERR("Failed to resize shaders array.\n"); + ID3D11VertexShader_Release(vertex_shader); + return E_OUTOFMEMORY; + } + }
You should call this to reserve "effect_context->shader_count + 1", no need to check size < count explicitly.
Since this is using GUIDs for keys, I suspect it should check for duplicates? IsShaderLoaded() takes just a GUID, so that implies all shader types are in the same list most likely.
By the way, have you figured out how shader objects are used later?
Shader objects will be used in ID2D1DrawTransform to create custom transforms which have custom shaders.
ID2D1DrawTransfrom use ID2D1DrawInfo that has functions like SetPixelShader() which accept shader GUID as an input argument. And that's where the loaded shader objects are used.
I see, thanks. Maybe it is a good idea to have dummy custom effect in our tests to see how these methods work. Specifically calling with same (or null) GUID, and where you can reuse GUID across shader types (I suspect you can't).
Later for SetPixelShader() we'll see if it returns meaningful error code if you set e.g. compute shader to it, or only forwards d3d error. But anyway, IUnknown* should be good for now, instead of void*.
On 4/28/22 13:40, Ziqing Hui wrote:
+void d2d_effect_context_init(struct d2d_effect_context *effect_context) +{
- effect_context->ID2D1EffectContext_iface.lpVtbl = &d2d_effect_context_vtbl;
- effect_context->refcount = 1;
+}
This patch introduces unused code. To avoid that I would move existing device_context->CreateEffect() to effect_context->CreateEffect() right away in the first patch.
Regarding init helper and patches 2, 4, 7, it seems easier to keep "struct d2d_device_context *" in effect context instead. It provides access to the factory and d3d device.
On 4/29/22 1:54 PM, Nikolay Sivov wrote:
On 4/28/22 13:40, Ziqing Hui wrote:
+void d2d_effect_context_init(struct d2d_effect_context *effect_context) +{ + effect_context->ID2D1EffectContext_iface.lpVtbl = &d2d_effect_context_vtbl; + effect_context->refcount = 1; +}
This patch introduces unused code. To avoid that I would move existing device_context->CreateEffect() to effect_context->CreateEffect() right away in the first patch.
Regarding init helper and patches 2, 4, 7, it seems easier to keep "struct d2d_device_context *" in effect context instead. It provides access to the factory and d3d device.
Thanks for reply.
OK, I'll send a v3 version later following your advice.