Beispiel #1
0
        public void CanUseGraphValueResolver_ToResolveValues_InAJob(NodeSet.RenderExecutionModel computeType)
        {
            using (var results = new NativeArray <float>(1, Allocator.Persistent))
                using (var set = new RenderGraphTests.PotentiallyJobifiedNodeSet(computeType))
                {
                    var root = set.Create <RenderPipe>();

                    GraphValue <float> rootValue = set.CreateGraphValue(root, RenderPipe.KernelPorts.Output);

                    for (int i = 0; i < 100; ++i)
                    {
                        set.SendMessage(root, RenderPipe.SimulationPorts.Input, i);

                        set.Update();

                        GraphValueReadbackJob job;

                        job.Value    = rootValue;
                        job.Result   = results;
                        job.Resolver = set.GetGraphValueResolver(out var valueResolverDependency);

                        set.InjectDependencyFromConsumer(job.Schedule(valueResolverDependency));

                        // Automatically fences before CopyWorlds. Results is accessible now.
                        set.Update();

                        Assert.AreEqual(i, results[0]);
                        Assert.AreEqual(i, set.GetValueBlocking(rootValue));
                    }

                    set.Destroy(root);
                    set.ReleaseGraphValue(rootValue);
                }
        }
Beispiel #2
0
        public void FeedbackTraversalOrder_IsCoherent([Values] NodeSet.RenderExecutionModel model)
        {
            using (var set = new NodeSet())
            {
                set.RendererModel = model;

                var node1 = set.Create <KernelAdderNode>();
                var node2 = set.Create <KernelAdderNode>();
                GraphValue <int> node1GV = set.CreateGraphValue(node1, KernelAdderNode.KernelPorts.Output);
                GraphValue <int> node2GV = set.CreateGraphValue(node2, KernelAdderNode.KernelPorts.Output);

                set.Connect(node1, KernelAdderNode.KernelPorts.Output, node2, KernelAdderNode.KernelPorts.Input, NodeSet.ConnectionType.Feedback);

                for (int i = 0; i < 10; ++i)
                {
                    set.SetData(node1, KernelAdderNode.KernelPorts.Input, i);
                    set.Update();
                    Assert.AreEqual(i + 1, set.GetValueBlocking(node1GV));
                    Assert.AreEqual(i + 1, set.GetValueBlocking(node2GV));
                }

                set.ReleaseGraphValue(node1GV);
                set.ReleaseGraphValue(node2GV);
                set.Destroy(node1, node2);
            }
        }
        public void GraphAccumulatesData_OverLongChains(
            [Values(2, 10, 30)] int nodeChainLength,
            [Values(NodeSet.RenderExecutionModel.Synchronous, NodeSet.RenderExecutionModel.MaximallyParallel)] NodeSet.RenderExecutionModel meansOfComputation)
        {
            using (var set = new PotentiallyJobifiedNodeSet(meansOfComputation))
            {
                var nodes       = new List <NodeHandle <KernelAdderNode> >(nodeChainLength);
                var graphValues = new List <GraphValue <int> >(nodeChainLength);

                for (int i = 0; i < nodeChainLength; ++i)
                {
                    var node = set.Create <KernelAdderNode>();
                    nodes.Add(node);
                    graphValues.Add(set.CreateGraphValue(node, KernelAdderNode.KernelPorts.Output));
                }

                for (int i = 0; i < nodeChainLength - 1; ++i)
                {
                    set.Connect(nodes[i], KernelAdderNode.KernelPorts.Output, nodes[i + 1], KernelAdderNode.KernelPorts.Input);
                }

                set.Update();

                for (int i = 0; i < nodeChainLength; ++i)
                {
                    Assert.AreEqual(i + 1, set.GetValueBlocking(graphValues[i]));
                }

                for (int i = 0; i < nodeChainLength; ++i)
                {
                    set.ReleaseGraphValue(graphValues[i]);
                    set.Destroy(nodes[i]);
                }
            }
        }
Beispiel #4
0
        public void TwoNodeFeedbackLoop_Works([Values] NodeSet.RenderExecutionModel model)
        {
            using (var set = new NodeSet())
            {
                set.RendererModel = model;

                var node1 = set.Create <KernelAdderNode>();
                var node2 = set.Create <KernelAdderNode>();
                GraphValue <int> node1GV = set.CreateGraphValue(node1, KernelAdderNode.KernelPorts.Output);
                GraphValue <int> node2GV = set.CreateGraphValue(node2, KernelAdderNode.KernelPorts.Output);

                set.Connect(node1, KernelAdderNode.KernelPorts.Output, node2, KernelAdderNode.KernelPorts.Input);
                set.Connect(node2, KernelAdderNode.KernelPorts.Output, node1, KernelAdderNode.KernelPorts.Input, NodeSet.ConnectionType.Feedback);

                // After the first update, we expect GVs 1,2. On the next update, the 2 should be fedback into node1, so we expect 3,4. Next, 5,6...
                for (int i = 0; i < 10; ++i)
                {
                    set.Update();
                    Assert.AreEqual(i * 2 + 1, set.GetValueBlocking(node1GV));
                    Assert.AreEqual(i * 2 + 2, set.GetValueBlocking(node2GV));
                }

                set.ReleaseGraphValue(node1GV);
                set.ReleaseGraphValue(node2GV);
                set.Destroy(node1, node2);
            }
        }
        public void TestUserNodes_DoRunInsideBurst(
            [Values] NodeSet.RenderExecutionModel model
            )
        {
            if (!BurstConfig.IsBurstEnabled)
            {
                Assert.Ignore("Burst is not enabled");
            }
#if UNITY_EDITOR
            if (!TestRunConfig.EnableBurstCompileSynchronously)
            {
                Assert.Ignore("Burst is not compiling synchronously");
            }
#endif

            using (var set = new NodeSet())
            {
                set.RendererModel = model;
                var node = set.Create <BurstedNode>();
                var gv   = set.CreateGraphValue(node, BurstedNode.KernelPorts.Result);

                set.Update();

                Assert.IsTrue(set.GetValueBlocking(gv));

                set.Destroy(node);
                set.ReleaseGraphValue(gv);
            }
        }
        public void CanRead_ECSBuffer_InsideFromDFG(
            [Values] NodeSet.RenderExecutionModel model,
            [Values(1, 3, 13, 50)] int bufferSize)
        {
            const int k_Loops = 10;

            using (var f = new Fixture <UpdateSystem>())
            {
                f.Set.RendererModel = model;
                var entity     = f.EM.CreateEntity(typeof(SimpleBuffer));
                var entityNode = f.Set.CreateComponentNode(entity);
                var dfgNode    = f.Set.Create <BufferNode>();
                var gv         = f.Set.CreateGraphValue(dfgNode, BufferNode.KernelPorts.Output);

                f.Set.Connect(entityNode, ComponentNode.Output <SimpleBuffer>(), dfgNode, BufferNode.KernelPorts.Input);

                var rng = new Mathematics.Random(0x7f);

                f.Set.SetBufferSize(dfgNode, BufferNode.KernelPorts.Output, Buffer <SimpleBuffer> .SizeRequest(bufferSize));

                for (int i = 0; i < k_Loops; ++i)
                {
                    var ecsBuffer = f.EM.GetBuffer <SimpleBuffer>(entity);
                    ecsBuffer.ResizeUninitialized(bufferSize);

                    for (int n = 0; n < bufferSize; ++n)
                    {
                        ecsBuffer[n] = new SimpleBuffer {
                            Values = rng.NextFloat3()
                        };
                    }

                    f.System.Update();

                    var resolver = f.Set.GetGraphValueResolver(out var dependency);
                    dependency.Complete();

                    ecsBuffer = f.EM.GetBuffer <SimpleBuffer>(entity);

                    var dfgBuffer = resolver.Resolve(gv);

                    Assert.AreEqual(ecsBuffer.Length, dfgBuffer.Length);

                    // TODO: can compare alias here
                    for (int n = 0; n < bufferSize; ++n)
                    {
                        Assert.AreEqual(ecsBuffer[n], dfgBuffer[n]);
                    }
                }

                f.Set.ReleaseGraphValue(gv);
                f.Set.Destroy(entityNode, dfgNode);
            }
        }
        public void GraphCanUpdate_WithoutIssues([Values] NodeSet.RenderExecutionModel meansOfComputation)
        {
            using (var set = new PotentiallyJobifiedNodeSet(meansOfComputation))
            {
                NodeHandle <KernelNode>
                a = set.Create <KernelNode>(),
         b        = set.Create <KernelNode>();

                set.Connect(a, KernelNode.KernelPorts.Output, b, KernelNode.KernelPorts.Input);
                set.Update();
                set.DataGraph.SyncAnyRendering();

                set.Destroy(a, b);
            }
        }
Beispiel #8
0
        public void NthOrderFeedbackSystem_Works([Values] NodeSet.RenderExecutionModel model, [Values(2, 5, 100)] int numNodes)
        {
            using (var set = new NodeSet())
            {
                set.RendererModel = model;

                var nodes    = new List <NodeHandle <KernelSumNode> >();
                var nodeGVs  = new List <GraphValue <ECSInt> >();
                var expected = new List <ECSInt>();

                nodes.Add(set.Create <KernelSumNode>());
                nodeGVs.Add(set.CreateGraphValue(nodes[0], KernelSumNode.KernelPorts.Output));
                expected.Add(1);
                for (int i = 1; i < numNodes; ++i)
                {
                    var node = set.Create <KernelSumNode>();
                    nodeGVs.Add(set.CreateGraphValue(node, KernelSumNode.KernelPorts.Output));
                    expected.Add(1);
                    nodes.Add(node);
                    set.SetPortArraySize(node, KernelSumNode.KernelPorts.Inputs, 1);
                    set.Connect(nodes[i - 1], KernelSumNode.KernelPorts.Output, node, KernelSumNode.KernelPorts.Inputs, 0);
                    set.SetPortArraySize(nodes[i - 1], KernelSumNode.KernelPorts.Inputs, 2);
                    set.Connect(node, KernelSumNode.KernelPorts.Output, nodes[i - 1], KernelSumNode.KernelPorts.Inputs, 1, NodeSet.ConnectionType.Feedback);
                }

                set.SetData(nodes[0], KernelSumNode.KernelPorts.Inputs, 0, 1);
                for (int i = 0; i < 10; ++i)
                {
                    set.Update();
                    for (int j = 0; j < numNodes; ++j)
                    {
                        Assert.AreEqual(expected[j], set.GetValueBlocking(nodeGVs[j]));
                    }

                    expected[0] = expected[1] + 1;
                    for (int j = 1; j < numNodes - 1; ++j)
                    {
                        expected[j] = expected[j - 1] + expected[j + 1];
                    }
                    expected[numNodes - 1] = expected[numNodes - 2];
                }

                nodeGVs.ForEach(n => set.ReleaseGraphValue(n));
                nodes.ForEach(n => set.Destroy(n));
            }
        }
        public void KernelNodeMemberMemory_IsPersistent_OverMultipleGraphEvaluations([Values] NodeSet.RenderExecutionModel meansOfComputation)
        {
            using (var set = new PotentiallyJobifiedNodeSet(meansOfComputation))
            {
                var node  = set.Create <PersistentKernelNode>();
                var value = set.CreateGraphValue(node, PersistentKernelNode.KernelPorts.Output);

                for (int i = 0; i < 100; ++i)
                {
                    set.Update();

                    Assert.AreEqual(i, set.GetValueBlocking(value));
                }

                set.Destroy(node);
                set.ReleaseGraphValue(value);
            }
        }
Beispiel #10
0
        [Test, Explicit] // Does not work due to issue #331. Do we even want it to work?
        public void SingleNodeFeedbackLoop_Works([Values] NodeSet.RenderExecutionModel model)
        {
            using (var set = new NodeSet())
            {
                set.RendererModel = model;

                var node = set.Create <KernelAdderNode>();
                GraphValue <int> nodeGV = set.CreateGraphValue(node, KernelAdderNode.KernelPorts.Output);

                set.Connect(node, KernelAdderNode.KernelPorts.Output, node, KernelAdderNode.KernelPorts.Input, NodeSet.ConnectionType.Feedback);

                for (int i = 0; i < 10; ++i)
                {
                    set.Update();
                    Assert.AreEqual(i + 1, set.GetValueBlocking(nodeGV));
                }

                set.ReleaseGraphValue(nodeGV);
                set.Destroy(node);
            }
        }
        public void ComplexDAG_ProducesExpectedResults_InAllExecutionModels([Values] NodeSet.RenderExecutionModel model)
        {
            const int k_NumGraphs = 10;

            for (int k = 0; k < 10; ++k)
            {
                using (var set = new NodeSet())
                {
                    set.RendererModel = model;

                    var tests = new List <DAGTest>(k_NumGraphs);

                    for (int i = 0; i < k_NumGraphs; ++i)
                    {
                        tests.Add(new DAGTest(set));
                    }

                    for (int i = 0; i < k_NumGraphs; ++i)
                    {
                        tests[i].SetLeafInputs(i);
                    }

                    set.Update();

                    /*  A ---------------- B (1)
                     *  A -------- C ----- B (2)
                     *           /   \
                     *  A - B - B      C = C (3)
                     *           \   /
                     *  A -------- C ----- B (4)
                     *  A                    (5)
                     *
                     *  A = in + 1
                     *  B = in * 3
                     *  C = in1 + in2
                     *
                     */

                    void CheckExpectedValueAtRoot(int expected, DAGTest graph, int root, int i)
                    {
                        var     output = set.GetValueBlocking(graph.RootGVs[root]);
                        ref var value  = ref set.GetOutputValues()[graph.RootGVs[root].Handle.Index];

                        Assert.IsTrue(value.IsLinkedToGraph, // This happens locally inside CopyWorlds.
                                      $"Race condition on Root[{root}] from render graph in graph iteration {i}"
                                      );

                        if (expected != output)
                        {
                            System.Threading.Thread.Sleep(1000);

                            var laterOutput = set.GetValueBlocking(graph.RootGVs[0]);

                            Assert.AreEqual(
                                output,
                                laterOutput,
                                $"Root[{root}] produced a race condition in graph iteration {i}"
                                );

                            Assert.AreEqual(
                                expected,
                                output,
                                $"Root[0] produced unexpected results in graph iteration {i}"
                                );
                        }
                    }

                    for (int i = 0; i < k_NumGraphs; ++i)
                    {
                        var       graph = tests[i];
                        const int b     = 3;
                        const int c     = 2;

                        var a   = (i + 1);
                        var abb = a * b * b;

                        CheckExpectedValueAtRoot(
                            a * b,
                            graph,
                            0,
                            i
                            );

                        CheckExpectedValueAtRoot(
                            (abb + a) * b,
                            graph,
                            1,
                            i
                            );

                        CheckExpectedValueAtRoot(
                            (abb + a) * c * c,
                            graph,
                            2,
                            i
                            );

                        CheckExpectedValueAtRoot(
                            (abb + a) * b,
                            graph,
                            3,
                            i
                            );

                        CheckExpectedValueAtRoot(
                            a,
                            graph,
                            4,
                            i
                            );
                    }

                    tests.ForEach(t => t.Dispose());
                }
            }
        public void CanReadAndWrite_ToSameECSBuffer_FromInsideDFG(
            [Values] NodeSet.RenderExecutionModel model,
            [Values(1, 3, 13, 50)] int bufferSize,
            [Values] bool feedbackAfterProcessing)
        {
            const int k_Loops  = 10;
            var       k_Offset = new float3(1.0f, 1.5f, 2.0f);

            using (var f = new Fixture <UpdateSystem>())
            {
                f.Set.RendererModel = model;
                var entity = f.EM.CreateEntity(typeof(SimpleBuffer), typeof(SimpleData));

                var entityNode = f.Set.CreateComponentNode(entity);

                var dfgNode = f.Set.Create <BufferNode>();
                f.Set.SetData(dfgNode, BufferNode.KernelPorts.Offset, k_Offset);

                f.Set.Connect(
                    entityNode,
                    ComponentNode.Output <SimpleBuffer>(),
                    dfgNode,
                    BufferNode.KernelPorts.Input,
                    !feedbackAfterProcessing ? NodeSet.ConnectionType.Feedback : NodeSet.ConnectionType.Normal
                    );

                f.Set.Connect(
                    dfgNode,
                    BufferNode.KernelPorts.Output,
                    entityNode,
                    ComponentNode.Input <SimpleBuffer>(),
                    feedbackAfterProcessing ? NodeSet.ConnectionType.Feedback : NodeSet.ConnectionType.Normal
                    );

                var ecsBuffer = f.EM.GetBuffer <SimpleBuffer>(entity);

                // match all buffer sizes
                ecsBuffer.ResizeUninitialized(bufferSize);
                f.Set.SetBufferSize(dfgNode, BufferNode.KernelPorts.Output, Buffer <SimpleBuffer> .SizeRequest(bufferSize));

                var expected = new List <SimpleBuffer>();

                var rng = new Mathematics.Random(0x8f);
                for (int n = 0; n < bufferSize; ++n)
                {
                    ecsBuffer[n] = new SimpleBuffer {
                        Values = feedbackAfterProcessing ? -k_Offset : rng.NextFloat3()
                    };
                    expected.Add(ecsBuffer[n]);
                }

                for (int i = 0; i < k_Loops; ++i)
                {
                    f.System.Update();

                    // This should fence on all dependencies
                    ecsBuffer = f.EM.GetBuffer <SimpleBuffer>(entity);

                    for (int n = 0; n < bufferSize; ++n)
                    {
                        expected[n] = new SimpleBuffer {
                            Values = expected[n].Values + k_Offset
                        }
                    }
                    ;

                    for (int n = 0; n < bufferSize; ++n)
                    {
                        Assert.AreEqual(expected[n], ecsBuffer[n]);
                    }
                }

                f.Set.Destroy(entityNode, dfgNode);
            }
        }
    }
        public void CanConnect_ECSBuffer_ToECSBuffer_UsingOnlyComponentNodes_AndTransferData(
            [Values] NodeSet.RenderExecutionModel model,
            [Values(1, 3, 13, 50)] int bufferSize,
            [Values] ConnectionMode strongNess)
        {
            const int k_Loops = 10;

            using (var f = new Fixture <UpdateSystem>())
            {
                f.Set.RendererModel = model;
                var entitySource      = f.EM.CreateEntity(typeof(SimpleBuffer));
                var entityDestination = f.EM.CreateEntity(typeof(SimpleBuffer));

                var entityNodeSource = f.Set.CreateComponentNode(entitySource);
                var entityNodeDest   = f.Set.CreateComponentNode(entityDestination);

                if (strongNess == ConnectionMode.Strong)
                {
                    f.Set.Connect(
                        entityNodeSource,
                        ComponentNode.Output <SimpleBuffer>(),
                        entityNodeDest,
                        ComponentNode.Input <SimpleBuffer>()
                        );
                }
                else
                {
                    f.Set.Connect(
                        entityNodeSource,
                        (OutputPortID)ComponentNode.Output <SimpleBuffer>(),
                        entityNodeDest,
                        (InputPortID)ComponentNode.Input <SimpleBuffer>()
                        );
                }

                var rng = new Mathematics.Random(0x8f);

                var ecsSourceBuffer = f.EM.GetBuffer <SimpleBuffer>(entitySource);
                var ecsDestBuffer   = f.EM.GetBuffer <SimpleBuffer>(entityDestination);

                // match all buffer sizes
                ecsSourceBuffer.ResizeUninitialized(bufferSize);
                ecsDestBuffer.ResizeUninitialized(bufferSize);

                for (int i = 0; i < k_Loops; ++i)
                {
                    ecsSourceBuffer = f.EM.GetBuffer <SimpleBuffer>(entitySource);

                    for (int n = 0; n < bufferSize; ++n)
                    {
                        ecsSourceBuffer[n] = new SimpleBuffer {
                            Values = rng.NextFloat3()
                        };
                    }

                    f.System.Update();

                    // This should fence on all dependencies
                    ecsDestBuffer = f.EM.GetBuffer <SimpleBuffer>(entityDestination);
                    //f.Set.DataGraph.SyncAnyRendering();
                    // TODO: can compare alias here
                    for (int n = 0; n < bufferSize; ++n)
                    {
                        Assert.AreEqual(ecsSourceBuffer[n], ecsDestBuffer[n]);
                    }
                }

                f.Set.Destroy(entityNodeSource, entityNodeDest);
            }
        }
        public void CanWrite_ToECSBuffer_InsideFromDFG_FromOriginalECS_Source(
            [Values] NodeSet.RenderExecutionModel model,
            [Values(1, 3, 13, 50)] int bufferSize,
            [Values] ConnectionMode strongNess)
        {
            const int k_Loops = 10;

            using (var f = new Fixture <UpdateSystem>())
            {
                f.Set.RendererModel = model;
                var entitySource      = f.EM.CreateEntity(typeof(SimpleBuffer));
                var entityDestination = f.EM.CreateEntity(typeof(SimpleBuffer));

                var entityNodeSource = f.Set.CreateComponentNode(entitySource);
                var entityNodeDest   = f.Set.CreateComponentNode(entityDestination);

                var dfgNode = f.Set.Create <BufferNode>();
                var gv      = f.Set.CreateGraphValue(dfgNode, BufferNode.KernelPorts.Output);

                if (strongNess == ConnectionMode.Strong)
                {
                    f.Set.Connect(entityNodeSource, ComponentNode.Output <SimpleBuffer>(), dfgNode, BufferNode.KernelPorts.Input);
                    f.Set.Connect(dfgNode, BufferNode.KernelPorts.Output, entityNodeDest, ComponentNode.Input <SimpleBuffer>());
                }
                else
                {
                    f.Set.Connect(
                        entityNodeSource,
                        (OutputPortID)ComponentNode.Output <SimpleBuffer>(),
                        dfgNode,
                        (InputPortID)BufferNode.KernelPorts.Input
                        );

                    f.Set.Connect(
                        dfgNode,
                        (OutputPortID)BufferNode.KernelPorts.Output,
                        entityNodeDest,
                        (InputPortID)ComponentNode.Input <SimpleBuffer>()
                        );
                }

                var rng = new Mathematics.Random(0x8f);

                var ecsSourceBuffer = f.EM.GetBuffer <SimpleBuffer>(entitySource);
                var ecsDestBuffer   = f.EM.GetBuffer <SimpleBuffer>(entityDestination);

                // match all buffer sizes
                ecsSourceBuffer.ResizeUninitialized(bufferSize);
                ecsDestBuffer.ResizeUninitialized(bufferSize);
                f.Set.SetBufferSize(dfgNode, BufferNode.KernelPorts.Output, Buffer <SimpleBuffer> .SizeRequest(bufferSize));

                for (int i = 0; i < k_Loops; ++i)
                {
                    ecsSourceBuffer = f.EM.GetBuffer <SimpleBuffer>(entitySource);

                    for (int n = 0; n < bufferSize; ++n)
                    {
                        ecsSourceBuffer[n] = new SimpleBuffer {
                            Values = rng.NextFloat3()
                        };
                    }

                    f.System.Update();

                    // This should fence on all dependencies
                    ecsDestBuffer = f.EM.GetBuffer <SimpleBuffer>(entityDestination);

                    // TODO: can compare alias here
                    for (int n = 0; n < bufferSize; ++n)
                    {
                        Assert.AreEqual(ecsSourceBuffer[n], ecsDestBuffer[n]);
                    }
                }

                f.Set.ReleaseGraphValue(gv);
                f.Set.Destroy(entityNodeSource, entityNodeDest, dfgNode);
            }
        }