From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/effect.c | 272 ++++++++++++++++++++++++++++++++++++++--- dlls/d2d1/tests/d2d1.c | 16 --- 2 files changed, 252 insertions(+), 36 deletions(-)
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 80f2f68b517..d6159055cbc 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -940,6 +940,8 @@ struct d2d_effect_impl { ID2D1EffectImpl ID2D1EffectImpl_iface; LONG refcount; + + /* Followed by properties block, its size and format depends on particular effect. */ };
static inline struct d2d_effect_impl *impl_from_ID2D1EffectImpl(ID2D1EffectImpl *iface) @@ -1007,21 +1009,98 @@ static const ID2D1EffectImplVtbl d2d_effect_impl_vtbl = d2d_effect_impl_SetGraph, };
-static HRESULT d2d_effect_create_impl(IUnknown **effect_impl) +static HRESULT d2d_effect_create_impl(IUnknown **effect_impl, const void *props, + size_t props_size) { struct d2d_effect_impl *object;
- if (!(object = calloc(1, sizeof(*object)))) + if (!(object = calloc(1, sizeof(*object) + props_size))) return E_OUTOFMEMORY;
object->ID2D1EffectImpl_iface.lpVtbl = &d2d_effect_impl_vtbl; object->refcount = 1; + if (props_size) memcpy(object + 1, props, props_size);
*effect_impl = (IUnknown *)&object->ID2D1EffectImpl_iface;
return S_OK; }
+static UINT32 effect_property_type_size(D2D1_PROPERTY_TYPE prop_type) +{ + static const UINT32 sizes[D2D1_PROPERTY_TYPE_MATRIX_5X4 + 1] = + { + [D2D1_PROPERTY_TYPE_BOOL] = sizeof(BOOL), + [D2D1_PROPERTY_TYPE_UINT32] = sizeof(UINT32), + [D2D1_PROPERTY_TYPE_INT32] = sizeof(INT32), + [D2D1_PROPERTY_TYPE_FLOAT] = sizeof(float), + [D2D1_PROPERTY_TYPE_VECTOR2] = sizeof(D2D_VECTOR_2F), + [D2D1_PROPERTY_TYPE_VECTOR3] = sizeof(D2D_VECTOR_3F), + [D2D1_PROPERTY_TYPE_VECTOR4] = sizeof(D2D_VECTOR_4F), + [D2D1_PROPERTY_TYPE_ENUM] = sizeof(UINT32), + [D2D1_PROPERTY_TYPE_MATRIX_3X2] = sizeof(D2D_MATRIX_3X2_F), + [D2D1_PROPERTY_TYPE_MATRIX_4X3] = sizeof(D2D_MATRIX_4X3_F), + [D2D1_PROPERTY_TYPE_MATRIX_4X4] = sizeof(D2D_MATRIX_4X4_F), + [D2D1_PROPERTY_TYPE_MATRIX_5X4] = sizeof(D2D_MATRIX_5X4_F), + }; + + if (prop_type >= ARRAY_SIZE(sizes)) + return 0; + + return sizes[prop_type]; +} + +static HRESULT effect_impl_prop_get_helper(const void *prop_data, D2D1_PROPERTY_TYPE prop_type, + BYTE *data, UINT32 data_size, UINT32 *actual_size) +{ + UINT32 size = effect_property_type_size(prop_type); + + if (actual_size) + *actual_size = size; + + if (data && data_size) + { + if (data_size < size) + return E_NOT_SUFFICIENT_BUFFER; + memcpy(data, prop_data, size); + } + + return S_OK; +} + +static HRESULT effect_impl_prop_set_helper(void *prop_data, D2D1_PROPERTY_TYPE prop_type, + const BYTE *data, UINT32 data_size) +{ + if (data_size != effect_property_type_size(prop_type)) + return E_INVALIDARG; + + memcpy(prop_data, data, data_size); + return S_OK; +} + +#define EFFECT_PROPERTY_SET(name, prop, type) \ + static HRESULT __stdcall name##_##prop##_set(IUnknown *iface, const BYTE *data, UINT32 data_size) \ + { \ + struct d2d_effect_impl *effect = impl_from_ID2D1EffectImpl((ID2D1EffectImpl *)iface); \ + struct name##_properties *props = (struct name##_properties *)(effect + 1); \ + return effect_impl_prop_set_helper(&props->prop, D2D1_PROPERTY_TYPE_##type, data, data_size); \ + } \ + +#define EFFECT_PROPERTY_GET(name, prop, type) \ + static HRESULT __stdcall name##_##prop##_get(const IUnknown *iface, BYTE *data, \ + UINT32 data_size, UINT32 *actual_size) \ + { \ + struct d2d_effect_impl *effect = impl_from_ID2D1EffectImpl((ID2D1EffectImpl *)iface); \ + struct name##_properties *props = (struct name##_properties *)(effect + 1); \ + return effect_impl_prop_get_helper(&props->prop, D2D1_PROPERTY_TYPE_##type, data, data_size, actual_size); \ + } \ + +#define EFFECT_PROPERTY_RW(name, prop, type) \ + EFFECT_PROPERTY_SET(name, prop, type) \ + EFFECT_PROPERTY_GET(name, prop, type) + +#define BINDING_RW(name, prop) name##_##prop##_set, name##_##prop##_get + static const WCHAR _2d_affine_transform_description[] = L"<?xml version='1.0'?> \ <Effect> \ @@ -1038,9 +1117,36 @@ L"<?xml version='1.0'?> \ <Property name='Sharpness' type='float' /> \ </Effect>";
+struct _2d_affine_transform_properties +{ + D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE interpolation_mode; + D2D1_BORDER_MODE border_mode; + D2D1_MATRIX_3X2_F transform_matrix; + float sharpness; +}; + +EFFECT_PROPERTY_RW(_2d_affine_transform, interpolation_mode, ENUM) +EFFECT_PROPERTY_RW(_2d_affine_transform, border_mode, ENUM) +EFFECT_PROPERTY_RW(_2d_affine_transform, transform_matrix, MATRIX_3X2) +EFFECT_PROPERTY_RW(_2d_affine_transform, sharpness, FLOAT) + +static const D2D1_PROPERTY_BINDING _2d_affine_transform_bindings[] = +{ + { L"InterpolationMode", BINDING_RW(_2d_affine_transform, interpolation_mode) }, + { L"BorderMode", BINDING_RW(_2d_affine_transform, border_mode) }, + { L"TransformMatrix", BINDING_RW(_2d_affine_transform, transform_matrix) }, + { L"Sharpness", BINDING_RW(_2d_affine_transform, sharpness) }, +}; + static HRESULT __stdcall _2d_affine_transform_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + static const struct _2d_affine_transform_properties properties = + { + .interpolation_mode = D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR, + .border_mode = D2D1_BORDER_MODE_SOFT, + .transform_matrix = { ._11 = 1.0f, ._22 = 1.0f }, + }; + return d2d_effect_create_impl(effect, &properties, sizeof(properties)); }
static const WCHAR _3d_perspective_transform_description[] = @@ -1057,7 +1163,7 @@ L"<?xml version='1.0'?>
static HRESULT __stdcall _3d_perspective_transform_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + return d2d_effect_create_impl(effect, NULL, 0); }
static const WCHAR composite_description[] = @@ -1075,7 +1181,7 @@ L"<?xml version='1.0'?> \
static HRESULT __stdcall composite_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + return d2d_effect_create_impl(effect, NULL, 0); }
static const WCHAR crop_description[] = @@ -1093,7 +1199,7 @@ L"<?xml version='1.0'?> \
static HRESULT __stdcall crop_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + return d2d_effect_create_impl(effect, NULL, 0); }
static const WCHAR shadow_description[] = @@ -1111,9 +1217,33 @@ L"<?xml version='1.0'?> \ <Property name='Optimization' type='enum' /> \ </Effect>";
+struct shadow_properties +{ + float blur_standard_deviation; + D2D_VECTOR_4F color; + D2D1_SHADOW_OPTIMIZATION optimization; +}; + +EFFECT_PROPERTY_RW(shadow, blur_standard_deviation, FLOAT) +EFFECT_PROPERTY_RW(shadow, color, VECTOR4) +EFFECT_PROPERTY_RW(shadow, optimization, ENUM) + +static const D2D1_PROPERTY_BINDING shadow_bindings[] = +{ + { L"BlurStandardDeviation", BINDING_RW(shadow, blur_standard_deviation) }, + { L"Color", BINDING_RW(shadow, color) }, + { L"Optimization", BINDING_RW(shadow, optimization) }, +}; + static HRESULT __stdcall shadow_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + static const struct shadow_properties properties = + { + .blur_standard_deviation = 3.0f, + .color = { 0.0f, 0.0f, 0.0f, 1.0f }, + .optimization = D2D1_SHADOW_OPTIMIZATION_BALANCED, + }; + return d2d_effect_create_impl(effect, &properties, sizeof(properties)); }
static const WCHAR grayscale_description[] = @@ -1130,7 +1260,7 @@ L"<?xml version='1.0'?> \
static HRESULT __stdcall grayscale_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + return d2d_effect_create_impl(effect, NULL, 0); }
static const WCHAR color_matrix_description[] = @@ -1147,7 +1277,7 @@ L"<?xml version='1.0'?> \
static HRESULT __stdcall color_matrix_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + return d2d_effect_create_impl(effect, NULL, 0); }
static const WCHAR flood_description[] = @@ -1162,9 +1292,25 @@ L"<?xml version='1.0'?> \ <Property name='Color' type='vector4' /> \ </Effect>";
+struct flood_properties +{ + D2D_VECTOR_4F color; +}; + +EFFECT_PROPERTY_RW(flood, color, VECTOR4) + +static const D2D1_PROPERTY_BINDING flood_bindings[] = +{ + { L"Color", BINDING_RW(flood, color) }, +}; + static HRESULT __stdcall flood_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + static const struct flood_properties properties = + { + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }; + return d2d_effect_create_impl(effect, &properties, sizeof(properties)); }
static const WCHAR gaussian_blur_description[] = @@ -1182,9 +1328,33 @@ L"<?xml version='1.0'?> \ <Property name='BorderMode' type='enum' /> \ </Effect>";
+struct gaussian_blur_properties +{ + float standard_deviation; + D2D1_GAUSSIANBLUR_OPTIMIZATION optimization; + D2D1_BORDER_MODE border_mode; +}; + +EFFECT_PROPERTY_RW(gaussian_blur, standard_deviation, FLOAT) +EFFECT_PROPERTY_RW(gaussian_blur, optimization, ENUM) +EFFECT_PROPERTY_RW(gaussian_blur, border_mode, ENUM) + +static const D2D1_PROPERTY_BINDING gaussian_blur_bindings[] = +{ + { L"StandardDeviation", BINDING_RW(gaussian_blur, standard_deviation) }, + { L"Optimization", BINDING_RW(gaussian_blur, optimization) }, + { L"BorderMode", BINDING_RW(gaussian_blur, border_mode) }, +}; + static HRESULT __stdcall gaussian_blur_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + static const struct gaussian_blur_properties properties = + { + .standard_deviation = 3.0f, + .optimization = D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED, + .border_mode = D2D1_BORDER_MODE_SOFT, + }; + return d2d_effect_create_impl(effect, &properties, sizeof(properties)); }
static const WCHAR point_specular_description[] = @@ -1206,9 +1376,48 @@ L"<?xml version='1.0'?> \ <Property name='ScaleMode' type='enum' /> \ </Effect>";
+struct point_specular_properties +{ + D2D_VECTOR_3F light_position; + float specular_exponent; + float specular_constant; + float surface_scale; + D2D_VECTOR_3F color; + D2D_VECTOR_2F kernel_unit_length; + D2D1_POINTSPECULAR_SCALE_MODE scale_mode; +}; + +EFFECT_PROPERTY_RW(point_specular, light_position, VECTOR3) +EFFECT_PROPERTY_RW(point_specular, specular_exponent, FLOAT) +EFFECT_PROPERTY_RW(point_specular, specular_constant, FLOAT) +EFFECT_PROPERTY_RW(point_specular, surface_scale, FLOAT) +EFFECT_PROPERTY_RW(point_specular, color, VECTOR3) +EFFECT_PROPERTY_RW(point_specular, kernel_unit_length, VECTOR2) +EFFECT_PROPERTY_RW(point_specular, scale_mode, ENUM) + +static const D2D1_PROPERTY_BINDING point_specular_bindings[] = +{ + { L"LightPosition", BINDING_RW(point_specular, light_position) }, + { L"SpecularExponent", BINDING_RW(point_specular, specular_exponent) }, + { L"SpecularConstant", BINDING_RW(point_specular, specular_constant) }, + { L"SurfaceScale", BINDING_RW(point_specular, surface_scale) }, + { L"Color", BINDING_RW(point_specular, color) }, + { L"KernelUnitLength", BINDING_RW(point_specular, kernel_unit_length) }, + { L"ScaleMode", BINDING_RW(point_specular, scale_mode) }, +}; + static HRESULT __stdcall point_specular_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + static const struct point_specular_properties properties = + { + .specular_exponent = 1.0f, + .specular_constant = 1.0f, + .surface_scale = 1.0f, + .color = { 1.0f, 1.0f, 1.0f }, + .kernel_unit_length = { 1.0f, 1.0f }, + .scale_mode = D2D1_POINTSPECULAR_SCALE_MODE_LINEAR, + }; + return d2d_effect_create_impl(effect, &properties, sizeof(properties)); }
static const WCHAR arithmetic_composite_description[] = @@ -1226,9 +1435,28 @@ L"<?xml version='1.0'?> \ <Property name='ClampOutput' type='bool' /> \ </Effect>";
+struct arithmetic_composite_properties +{ + D2D_VECTOR_4F coefficients; + BOOL clamp_output; +}; + +EFFECT_PROPERTY_RW(arithmetic_composite, coefficients, VECTOR4) +EFFECT_PROPERTY_RW(arithmetic_composite, clamp_output, BOOL) + +static const D2D1_PROPERTY_BINDING arithmetic_composite_bindings[] = +{ + { L"Coefficients", BINDING_RW(arithmetic_composite, coefficients) }, + { L"ClampOutput", BINDING_RW(arithmetic_composite, clamp_output) }, +}; + static HRESULT __stdcall arithmetic_composite_factory(IUnknown **effect) { - return d2d_effect_create_impl(effect); + static const struct arithmetic_composite_properties properties = + { + .coefficients = { 1.0f, 0.0f, 0.0f, 0.0f }, + }; + return d2d_effect_create_impl(effect, &properties, sizeof(properties)); }
void d2d_effects_init_builtins(struct d2d_factory *factory) @@ -1238,21 +1466,25 @@ void d2d_effects_init_builtins(struct d2d_factory *factory) const CLSID *clsid; const WCHAR *description; PD2D1_EFFECT_FACTORY factory; + const D2D1_PROPERTY_BINDING *bindings; + UINT32 binding_count; } builtin_effects[] = { #define X(name) name##_description, name##_factory - { &CLSID_D2D12DAffineTransform, X(_2d_affine_transform) }, +#define X2(name) name##_description, name##_factory, name##_bindings, ARRAY_SIZE(name##_bindings) + { &CLSID_D2D12DAffineTransform, X2(_2d_affine_transform) }, { &CLSID_D2D13DPerspectiveTransform, X(_3d_perspective_transform) }, { &CLSID_D2D1Composite, X(composite) }, { &CLSID_D2D1Crop, X(crop) }, - { &CLSID_D2D1Shadow, X(shadow) }, + { &CLSID_D2D1Shadow, X2(shadow) }, { &CLSID_D2D1Grayscale, X(grayscale) }, { &CLSID_D2D1ColorMatrix, X(color_matrix) }, - { &CLSID_D2D1Flood, X(flood) }, - { &CLSID_D2D1GaussianBlur, X(gaussian_blur) }, - { &CLSID_D2D1PointSpecular, X(point_specular) }, - { &CLSID_D2D1ArithmeticComposite, X(arithmetic_composite) }, + { &CLSID_D2D1Flood, X2(flood) }, + { &CLSID_D2D1GaussianBlur, X2(gaussian_blur) }, + { &CLSID_D2D1PointSpecular, X2(point_specular) }, + { &CLSID_D2D1ArithmeticComposite, X2(arithmetic_composite) }, +#undef X2 #undef X }; unsigned int i; @@ -1263,7 +1495,7 @@ void d2d_effects_init_builtins(struct d2d_factory *factory) const struct builtin_description *desc = &builtin_effects[i];
if (FAILED(hr = d2d_factory_register_builtin_effect(factory, desc->clsid, desc->description, - NULL, 0, desc->factory))) + desc->bindings, desc->binding_count, desc->factory))) { WARN("Failed to register the effect %s, hr %#lx.\n", wine_dbgstr_guid(desc->clsid), hr); } diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 87e5e76ad73..d5aa8783060 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -13146,7 +13146,6 @@ static void test_effect_2d_affine(BOOL d3d11) hr = ID2D1Effect_GetValue(effect, D2D1_2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE, D2D1_PROPERTY_TYPE_ENUM, (BYTE *)&value, sizeof(value)); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - todo_wine ok(value == D2D1_2DAFFINETRANSFORM_INTERPOLATION_MODE_LINEAR, "Unexpected value %u.\n", value); check_enum_property(effect, D2D1_2DAFFINETRANSFORM_PROP_INTERPOLATION_MODE, interp_modes, ARRAY_SIZE(interp_modes)); @@ -13177,7 +13176,6 @@ static void test_effect_2d_affine(BOOL d3d11) ID2D1Effect_SetInput(effect, 0, (ID2D1Image *)bitmap, FALSE); hr = ID2D1Effect_SetValue(effect, D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, D2D1_PROPERTY_TYPE_MATRIX_3X2, (const BYTE *)test->matrix, sizeof(*test->matrix)); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); if (hr == D2DERR_INVALID_PROPERTY) { @@ -13459,11 +13457,9 @@ static void test_effect_gaussian_blur(BOOL d3d11) }
f = effect_get_float_prop(effect, D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION); - todo_wine ok(f == 3.0f, "Unexpected value %.8e.\n", f);
v = effect_get_enum_prop(effect, D2D1_GAUSSIANBLUR_PROP_OPTIMIZATION); - todo_wine ok(v == D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED, "Unexpected value %u.\n", v);
v = effect_get_enum_prop(effect, D2D1_GAUSSIANBLUR_PROP_BORDER_MODE); @@ -13521,28 +13517,22 @@ static void test_effect_point_specular(BOOL d3d11) vec3.x, vec3.y, vec3.z);
f = effect_get_float_prop(effect, D2D1_POINTSPECULAR_PROP_SPECULAR_EXPONENT); - todo_wine ok(f == 1.0f, "Unexpected value %.8e.\n", f);
f = effect_get_float_prop(effect, D2D1_POINTSPECULAR_PROP_SPECULAR_CONSTANT); - todo_wine ok(f == 1.0f, "Unexpected value %.8e.\n", f);
f = effect_get_float_prop(effect, D2D1_POINTSPECULAR_PROP_SURFACE_SCALE); - todo_wine ok(f == 1.0f, "Unexpected value %.8e.\n", f);
vec3 = effect_get_vec3_prop(effect, D2D1_POINTSPECULAR_PROP_COLOR); - todo_wine ok(vec3.x == 1.0f && vec3.y == 1.0f && vec3.z == 1.0f, "Unexpected value {%.8e,%.8e,%.8e}.\n", vec3.x, vec3.y, vec3.z);
vec2 = effect_get_vec2_prop(effect, D2D1_POINTSPECULAR_PROP_KERNEL_UNIT_LENGTH); - todo_wine ok(vec2.x == 1.0f && vec2.y == 1.0f, "Unexpected value {%.8e,%.8e}.\n", vec2.x, vec2.y);
v = effect_get_enum_prop(effect, D2D1_POINTSPECULAR_PROP_SCALE_MODE); - todo_wine ok(v == D2D1_POINTSPECULAR_SCALE_MODE_LINEAR, "Unexpected value %u.\n", v);
ID2D1Effect_Release(effect); @@ -13586,7 +13576,6 @@ static void test_effect_arithmetic_composite(BOOL d3d11) }
vec4 = effect_get_vec4_prop(effect, D2D1_ARITHMETICCOMPOSITE_PROP_COEFFICIENTS); - todo_wine ok(vec4.x == 1.0f && vec4.y == 0.0f && vec4.z == 0.0f && vec4.w == 0.0f, "Unexpected value {%.8e,%.8e,%.8e,%.8e}.\n", vec4.x, vec4.y, vec4.z, vec4.w);
@@ -13636,16 +13625,13 @@ static void test_effect_shadow(BOOL d3d11) }
f = effect_get_float_prop(effect, D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION); - todo_wine ok(f == 3.0f, "Unexpected value %.8e.\n", f);
vec4 = effect_get_vec4_prop(effect, D2D1_SHADOW_PROP_COLOR); - todo_wine ok(vec4.x == 0.0f && vec4.y == 0.0f && vec4.z == 0.0f && vec4.w == 1.0f, "Unexpected value {%.8e,%.8e,%.8e,%.8e}.\n", vec4.x, vec4.y, vec4.z, vec4.w);
v = effect_get_enum_prop(effect, D2D1_SHADOW_PROP_OPTIMIZATION); - todo_wine ok(v == D2D1_SHADOW_OPTIMIZATION_BALANCED, "Unexpected value %#x.\n", v);
ID2D1Effect_Release(effect); @@ -13692,7 +13678,6 @@ static void test_effect_flood(BOOL d3d11) }
vec4 = effect_get_vec4_prop(effect, D2D1_FLOOD_PROP_COLOR); - todo_wine ok(vec4.x == 0.0f && vec4.y == 0.0f && vec4.z == 0.0f && vec4.w == 1.0f, "Unexpected value {%.8e,%.8e,%.8e,%.8e}.\n", vec4.x, vec4.y, vec4.z, vec4.w);
@@ -13709,7 +13694,6 @@ static void test_effect_flood(BOOL d3d11) set_color(&color, 0.0f, 0.0f, 1.0f, 1.0f); hr = ID2D1Effect_SetValue(effect, D2D1_FLOOD_PROP_COLOR, D2D1_PROPERTY_TYPE_VECTOR4, (const BYTE *)&color, sizeof(color)); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
ID2D1DeviceContext_BeginDraw(context);