-- v2: d2d1: Implement nodes connection for ID2D1TransformGraph. d2d1: Implement nodes adding and removal for ID2D1TransformGraph. d2d1/tests: Add more tests for ID2D1TransformGraph.
From: Ziqing Hui zhui@codeweavers.com
--- dlls/d2d1/tests/d2d1.c | 55 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 08c7bc05224..546cb46f9ad 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -12038,6 +12038,7 @@ static void test_registered_effects(BOOL d3d11)
static void test_transform_graph(BOOL d3d11) { + UINT i, effect_input_count, transform_input_count; ID2D1OffsetTransform *offset_transform = NULL; ID2D1BlendTransform *blend_transform = NULL; D2D1_BLEND_DESCRIPTION blend_desc = {0}; @@ -12047,7 +12048,6 @@ static void test_transform_graph(BOOL d3d11) ID2D1Factory1 *factory; POINT point = {0 ,0}; ID2D1Effect *effect; - UINT i, count; HRESULT hr;
const D2D1_PROPERTY_BINDING binding[] = @@ -12104,6 +12104,15 @@ static void test_transform_graph(BOOL d3d11) hr = ID2D1TransformGraph_RemoveNode(graph, (ID2D1TransformNode *)blend_transform); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+ /* Clear nodes */ + hr = ID2D1TransformGraph_AddNode(graph, (ID2D1TransformNode *)offset_transform); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_AddNode(graph, (ID2D1TransformNode *)offset_transform); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + ID2D1TransformGraph_Clear(graph); + hr = ID2D1TransformGraph_AddNode(graph, (ID2D1TransformNode *)offset_transform); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + /* Connect nodes which are both un-added */ ID2D1TransformGraph_Clear(graph); hr = ID2D1TransformGraph_ConnectNode(graph, @@ -12126,13 +12135,13 @@ static void test_transform_graph(BOOL d3d11) ok(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Got unexpected hr %#lx.\n", hr);
/* Connect nodes */ + transform_input_count = ID2D1BlendTransform_GetInputCount(blend_transform); ID2D1TransformGraph_Clear(graph); hr = ID2D1TransformGraph_AddNode(graph, (ID2D1TransformNode *)offset_transform); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ID2D1TransformGraph_AddNode(graph, (ID2D1TransformNode *)blend_transform); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - count = ID2D1BlendTransform_GetInputCount(blend_transform); - for (i = 0; i < count; ++i) + for (i = 0; i < transform_input_count; ++i) { hr = ID2D1TransformGraph_ConnectNode(graph, (ID2D1TransformNode *)offset_transform, (ID2D1TransformNode *)blend_transform, i); @@ -12141,7 +12150,45 @@ static void test_transform_graph(BOOL d3d11)
/* Connect node to out-of-bounds index */ hr = ID2D1TransformGraph_ConnectNode(graph, - (ID2D1TransformNode *)offset_transform, (ID2D1TransformNode *)blend_transform, count); + (ID2D1TransformNode *)offset_transform, (ID2D1TransformNode *)blend_transform, transform_input_count); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + /* Set output */ + hr = ID2D1TransformGraph_SetOutputNode(graph, (ID2D1TransformNode *)blend_transform); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_SetOutputNode(graph, (ID2D1TransformNode *)offset_transform); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* Single node transform graph */ + effect_input_count = ID2D1TransformGraph_GetInputCount(graph); + + transform_input_count = ID2D1BlendTransform_GetInputCount(blend_transform); + ok(transform_input_count != effect_input_count, "Input count should not be equal.\n"); + hr = ID2D1TransformGraph_SetSingleTransformNode(graph, (ID2D1TransformNode *)blend_transform); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_RemoveNode(graph, (ID2D1TransformNode *)blend_transform); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_RemoveNode(graph, (ID2D1TransformNode *)offset_transform); + ok(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Got unexpected hr %#lx.\n", hr); + + transform_input_count = ID2D1OffsetTransform_GetInputCount(offset_transform); + ok(transform_input_count == effect_input_count, "Input count should be equal.\n"); + hr = ID2D1TransformGraph_SetSingleTransformNode(graph, (ID2D1TransformNode *)offset_transform); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_RemoveNode(graph, (ID2D1TransformNode *)offset_transform); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_RemoveNode(graph, (ID2D1TransformNode *)blend_transform); + ok(hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Got unexpected hr %#lx.\n", hr); + + /* Connect effect inputs to node inputs */ + transform_input_count = ID2D1BlendTransform_GetInputCount(blend_transform); + hr = ID2D1TransformGraph_AddNode(graph, (ID2D1TransformNode *)blend_transform); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_ConnectToEffectInput(graph, 0, (ID2D1TransformNode *)blend_transform, 0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_ConnectToEffectInput(graph, 0, (ID2D1TransformNode *)blend_transform, transform_input_count); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + hr = ID2D1TransformGraph_ConnectToEffectInput(graph, effect_input_count, (ID2D1TransformNode *)blend_transform, 0); ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
done:
From: Ziqing Hui zhui@codeweavers.com
--- dlls/d2d1/d2d1_private.h | 7 +++++ dlls/d2d1/effect.c | 61 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 085febe95e7..8de2f6de79f 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -674,10 +674,17 @@ struct d2d_effect_registration * d2d_factory_get_registered_effect(ID2D1Factory void d2d_factory_register_effect(struct d2d_factory *factory, struct d2d_effect_registration *effect) DECLSPEC_HIDDEN;
+struct d2d_transform_node +{ + ID2D1TransformNode *node; + struct list entry; +}; + struct d2d_transform_graph { ID2D1TransformGraph ID2D1TransformGraph_iface; LONG refcount; + struct list nodes; };
struct d2d_effect diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 7b086e20b9b..0ac2d4b3ade 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -20,6 +20,26 @@
WINE_DEFAULT_DEBUG_CHANNEL(d2d);
+static struct d2d_transform_node *d2d_transform_graph_find_node(const struct d2d_transform_graph *graph, + const ID2D1TransformNode *node) +{ + struct d2d_transform_node *entry; + + LIST_FOR_EACH_ENTRY_REV(entry, &graph->nodes, struct d2d_transform_node, entry) + { + if (entry->node == node) + return entry; + } + return NULL; +} + +static void d2d_transform_graph_remove_node(struct d2d_transform_graph *graph, struct d2d_transform_node *node) +{ + list_remove(&node->entry); + ID2D1TransformNode_Release(node->node); + free(node); +} + static inline struct d2d_transform_graph *impl_from_ID2D1TransformGraph(ID2D1TransformGraph *iface) { return CONTAINING_RECORD(iface, struct d2d_transform_graph, ID2D1TransformGraph_iface); @@ -59,7 +79,10 @@ static ULONG STDMETHODCALLTYPE d2d_transform_graph_Release(ID2D1TransformGraph * TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
if (!refcount) + { + ID2D1TransformGraph_Clear(iface); free(graph); + }
return refcount; } @@ -81,16 +104,35 @@ static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetSingleTransformNode(ID2D
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_AddNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) { - FIXME("iface %p, node %p stub!\n", iface, node); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *entry;
- return E_NOTIMPL; + TRACE("iface %p, node %p.\n", iface, node); + + if (d2d_transform_graph_find_node(graph, node)) + return E_INVALIDARG; + + if (!(entry = calloc(1, sizeof(*entry)))) + return E_OUTOFMEMORY; + + ID2D1TransformNode_AddRef(entry->node = node); + list_add_tail(&graph->nodes, &entry->entry); + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_RemoveNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) { - FIXME("iface %p, node %p stub!\n", iface, node); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *entry;
- return E_NOTIMPL; + TRACE("iface %p, node %p.\n", iface, node); + + if (!(entry = d2d_transform_graph_find_node(graph, node))) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + + d2d_transform_graph_remove_node(graph, entry); + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetOutputNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) @@ -118,7 +160,15 @@ static HRESULT STDMETHODCALLTYPE d2d_transform_graph_ConnectToEffectInput(ID2D1T
static void STDMETHODCALLTYPE d2d_transform_graph_Clear(ID2D1TransformGraph *iface) { - FIXME("iface %p stub!\n", iface); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *entry, *entry2; + + TRACE("iface %p.\n", iface); + + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &graph->nodes, struct d2d_transform_node, entry) + { + d2d_transform_graph_remove_node(graph, entry); + } }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetPassthroughGraph(ID2D1TransformGraph *iface, UINT32 index) @@ -148,6 +198,7 @@ static void d2d_transform_graph_init(struct d2d_transform_graph *graph) { graph->ID2D1TransformGraph_iface.lpVtbl = &d2d_transform_graph_vtbl; graph->refcount = 1; + list_init(&graph->nodes); }
static HRESULT STDMETHODCALLTYPE d2d_effect_impl_QueryInterface(ID2D1EffectImpl *iface, REFIID iid, void **out)
From: Ziqing Hui zhui@codeweavers.com
--- dlls/d2d1/d2d1_private.h | 7 +++ dlls/d2d1/effect.c | 108 +++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 10 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 8de2f6de79f..a43d166091f 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -677,6 +677,10 @@ void d2d_factory_register_effect(struct d2d_factory *factory, struct d2d_transform_node { ID2D1TransformNode *node; + struct d2d_transform_node **inputs; + UINT32 input_count; + struct d2d_transform_node *output; + UINT32 output_to_index; struct list entry; };
@@ -684,6 +688,9 @@ struct d2d_transform_graph { ID2D1TransformGraph ID2D1TransformGraph_iface; LONG refcount; + struct d2d_transform_node *input_nodes; + UINT32 input_count; + struct d2d_transform_node *output_node; struct list nodes; };
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c index 0ac2d4b3ade..ded80b1d51d 100644 --- a/dlls/d2d1/effect.c +++ b/dlls/d2d1/effect.c @@ -35,8 +35,26 @@ static struct d2d_transform_node *d2d_transform_graph_find_node(const struct d2d
static void d2d_transform_graph_remove_node(struct d2d_transform_graph *graph, struct d2d_transform_node *node) { + UINT32 i; + + for (i = 0; i < graph->input_count; ++i) + { + if (graph->input_nodes[i].output == node) + graph->input_nodes[i].output = NULL; + } + if (graph->output_node == node) + graph->output_node = NULL; + for (i = 0; i < node->input_count; ++i) + { + if (node->inputs[i]) + node->inputs[i]->output = NULL; + } + if (node->output) + node->output->inputs[node->output_to_index] = NULL; list_remove(&node->entry); + ID2D1TransformNode_Release(node->node); + free(node->inputs); free(node); }
@@ -81,6 +99,7 @@ static ULONG STDMETHODCALLTYPE d2d_transform_graph_Release(ID2D1TransformGraph * if (!refcount) { ID2D1TransformGraph_Clear(iface); + free(graph->input_nodes); free(graph); }
@@ -89,17 +108,39 @@ static ULONG STDMETHODCALLTYPE d2d_transform_graph_Release(ID2D1TransformGraph *
static UINT32 STDMETHODCALLTYPE d2d_transform_graph_GetInputCount(ID2D1TransformGraph *iface) { - FIXME("iface %p stub!\n", iface); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface);
- return 0; + TRACE("iface %p\n", iface); + + return graph->input_count; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetSingleTransformNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) { - FIXME("iface %p, node %p stub!\n", iface, node); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + UINT32 input_count, i; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, node %p.\n", iface, node); + + input_count = ID2D1TransformNode_GetInputCount(node); + if (input_count != graph->input_count) + return E_INVALIDARG; + + ID2D1TransformGraph_Clear(iface); + + if (FAILED(hr = ID2D1TransformGraph_AddNode(iface, node))) + return hr; + if (FAILED(hr = ID2D1TransformGraph_SetOutputNode(iface, node))) + return hr; + for (i = 0; i < input_count; ++i) + { + if (FAILED(hr = ID2D1TransformGraph_ConnectToEffectInput(iface, i, node, i))) + return hr; + } + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_AddNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) @@ -115,6 +156,12 @@ static HRESULT STDMETHODCALLTYPE d2d_transform_graph_AddNode(ID2D1TransformGraph if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY;
+ entry->input_count = ID2D1TransformNode_GetInputCount(node); + if (!(entry->inputs = calloc(entry->input_count, sizeof(*entry->inputs)))) + { + free(entry); + return E_OUTOFMEMORY; + } ID2D1TransformNode_AddRef(entry->node = node); list_add_tail(&graph->nodes, &entry->entry);
@@ -137,25 +184,58 @@ static HRESULT STDMETHODCALLTYPE d2d_transform_graph_RemoveNode(ID2D1TransformGr
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_SetOutputNode(ID2D1TransformGraph *iface, ID2D1TransformNode *node) { - FIXME("iface %p, node %p stub!\n", iface, node); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *entry;
- return E_NOTIMPL; + TRACE("iface %p, node %p.\n", iface, node); + + if (!(entry = d2d_transform_graph_find_node(graph, node))) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + + graph->output_node = entry; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_ConnectNode(ID2D1TransformGraph *iface, ID2D1TransformNode *from_node, ID2D1TransformNode *to_node, UINT32 index) { - FIXME("iface %p, from_node %p, to_node %p, index %u stub!\n", iface, from_node, to_node, index); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *from, *to;
- return E_NOTIMPL; + TRACE("iface %p, from_node %p, to_node %p, index %u.\n", iface, from_node, to_node, index); + + if (!(from = d2d_transform_graph_find_node(graph, from_node)) + || !(to = d2d_transform_graph_find_node(graph, to_node))) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + if (index >= to->input_count) + return E_INVALIDARG; + + from->output = to; + from->output_to_index = index; + to->inputs[index] = from; + + return S_OK; }
static HRESULT STDMETHODCALLTYPE d2d_transform_graph_ConnectToEffectInput(ID2D1TransformGraph *iface, UINT32 input_index, ID2D1TransformNode *node, UINT32 node_index) { - FIXME("iface %p, input_index %u, node %p, node_index %u stub!\n", iface, input_index, node, node_index); + struct d2d_transform_graph *graph = impl_from_ID2D1TransformGraph(iface); + struct d2d_transform_node *entry;
- return E_NOTIMPL; + TRACE("iface %p, input_index %u, node %p, node_index %u.\n", iface, input_index, node, node_index); + + if (!(entry = d2d_transform_graph_find_node(graph, node))) + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); + if (input_index >= graph->input_count || node_index >= entry->input_count) + return E_INVALIDARG; + + graph->input_nodes[input_index].output = entry; + graph->input_nodes[input_index].output_to_index = node_index; + entry->inputs[node_index] = &graph->input_nodes[input_index]; + + return S_OK; }
static void STDMETHODCALLTYPE d2d_transform_graph_Clear(ID2D1TransformGraph *iface) @@ -1258,6 +1338,7 @@ static HRESULT STDMETHODCALLTYPE d2d_effect_SetInputCount(ID2D1Effect *iface, UI { struct d2d_effect *effect = impl_from_ID2D1Effect(iface); unsigned int i, min_inputs, max_inputs; + struct d2d_transform_graph *graph;
TRACE("iface %p, count %u.\n", iface, count);
@@ -1292,6 +1373,13 @@ static HRESULT STDMETHODCALLTYPE d2d_effect_SetInputCount(ID2D1Effect *iface, UI memset(&effect->inputs[effect->input_count], 0, sizeof(*effect->inputs) * (count - effect->input_count)); effect->input_count = count;
+ /* Allocate input nodes for transform graph. */ + graph = effect->graph; + if (!(graph->input_nodes = realloc(graph->input_nodes, sizeof(*graph->input_nodes) * count))) + return E_OUTOFMEMORY; + memset(graph->input_nodes, 0, sizeof(*graph->input_nodes) * count); + graph->input_count = count; + return S_OK; }
On Thu Sep 8 03:30:34 2022 +0000, Ziqing Hui wrote:
Do you mean `output_to_index`? `output_to_index` is used in `d2d_transform_graph_remove_node()`. If we don't record the index to which our node connects, in `d2d_transform_graph_remove_node()`, we have to replace:
if (node->output) node->output->inputs[node->output_to_index] = NULL;
with
if (node->output) { for (i = 0; i < node->output->input_count; ++i) { if (node->output->inputs[i] == node) { node->output->inputs[i] = NULL; break; } } }
Which one would be better? Remove `output_to_index` or not?
(I didn't change this in v2.)
On Thu Sep 8 03:48:13 2022 +0000, Ziqing Hui wrote:
Node input count is a constant. And `AddNode()` is the place where we create `d2d_transform_node`. `d2d_transform_node` is not node object itself. In fact it is a wrapper of `ID2D1TransformNode` and holds a reference to it. `ID2D1TransformNode` is the real node object. I think `d2d_transform_node` should relies on `ID2D1TransformNode` interface, instead of concrete implementation of `ID2D1TransformNode`. So this array should be in `d2d_transform_node`, not in implementation of `ID2D1TransformNode`. And we create this array in `AddNode()` where we create our `d2d_transform_node`.
(I didn't change this in v2.)
This merge request was closed by Ziqing Hui.