Sign in to follow this  

[.net] How to make my material tree more efficient?

This topic is 4303 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey there everyone. I've just been working on state management in my team's game engine and we're using .NET 2.0 as our framework (obviously). The system uses an abstract class to represent a state change, and then these are linked together into a tree to create the scene representation. Everything seems to be working well at the moment - it's doing whats expected, but I'm sure it can do it (the traversal mainly) faster than it is at the moment. So I present to you, my material system code. The first snippet is my abstract state change class. This is most of the meat on the state changes themselves.
    abstract class StateChange
    {
        protected StateChange parent;
        protected List<StateChange> children = new List<StateChange>();
        protected List<SceneEntity> entities = new List<SceneEntity>();
        protected StateManager manager;

        public StateManager StateManager
        {
            get { return manager; }
            set { manager = value; }
        }
        internal List<StateChange> Children
        {
            get { return children; }
        }
        internal List<SceneEntity> Entities
        {
            get { return entities; }
        }
        public StateChange Parent
        {
            get { return parent; }
            set
            {
                value.AddChild(this);
            }
        }

        public void AddChild(StateChange child)
        {
            // First, check that the child did not previously have a parent, and if so - remove the child from the parent
            if (child.parent != null)
            {
                child.parent.RemoveChild(child);
            }

            // Now add the child, and set its parent.
            if (!children.Contains(child))
            {
                children.Add(child);
                child.parent = this;
            }
        }
        private void RemoveChild(StateChange child)
        {
            if (children.Contains(child))
            {
                children.Remove(child);
                child.parent = null;
            }
            else
                throw new NullReferenceException("Unable to remove a state change that is not a child of this parent");
        }

        public void AddEntity(SceneEntity entity)
        {
            if(!entities.Contains(entity))
                entities.Add(entity);
        }

        public abstract void Apply();
    }

An example implemtation of this is:
    class ShaderTexture : StateChange
    {
        private string parameter;
        private Microsoft.DirectX.Direct3D.Texture texture;

        public Microsoft.DirectX.Direct3D.Texture Texture
        {
            get { return texture; }
            set { texture = value; }
        }
        public string Parameter
        {
            get { return parameter; }
            set { parameter = value; }
        }

        public ShaderTexture(string parameter, Microsoft.DirectX.Direct3D.Texture texture)
        {
            this.parameter = parameter;
            this.texture = texture;
        }

        public override void Apply()
        {
            manager.ActiveShader.SetVariable(parameter, texture);
        }
    }
}

And here is how I'm traversing the scene:
    internal class StateTraverser
    {
        RenderVisitor renderVisitor = new RenderVisitor();
        Matrix view, projection;

        internal void Enter(StateChange change)
        {
            view = Engine.Active.SceneManager.ActiveCamera.View;
            projection = Engine.Active.SceneManager.ActiveCamera.Projection;

            VisitNode(change);
        }

        void VisitNode(StateChange change)
        {
            change.Apply();

            foreach (StateChange sc in change.Children)
                VisitNode(sc);

            foreach (SceneEntity e in change.Entities)
                if (e.IsVisible)
                {
                    Engine.Active.GraphicsDevice.States.ActiveShader.Update(e.WorldMatrix * Engine.Active.SceneManager.RootWorld, view, projection);
                    Engine.Active.GraphicsDevice.States.ActiveShader.Direct3DEffect.CommitChanges();
                    e.Accept(renderVisitor);
                }
        }
    }

Now my main concerns are with copying data and stuff. I think when I do "foreach SceneEntity e in change.Entities" there's some type of copy happening. Sure I read something like that somewhere. Anyway, any ideas are appreciated!

Share this post


Link to post
Share on other sites
As far as I can remember the foreach construct creates an instance of an enumerator, which contains an array of pointers to each of the items in the collection at the point the foreach block is commenced.

I suppose this construction of the enumerator could be said to be less efficient that using the indexers in a for(x) loop, but I would have thought the effect would be extremely marginal as it isn't copying the data, only references to the underlying data.

It could be worth just knocking up two different loops, one using foreach and one using indexers and see which is faster (or do they generate essentially identical IL ?).

Its the same approach I'd use, so it would be a thumbs-up from me, but I'm sure someone will now leap in and pour scorn over my mutterings 8-)

Phillip Hamlyn

Share this post


Link to post
Share on other sites
Are you going to handle sorting by state changes in your tree, or will that be handled elsewhere?

You should group bits of geometry that uses the same state together.

From cheapest to most expensive to change:
Material
Transform
Texture
Vertex/Pixel Shader

Share this post


Link to post
Share on other sites
There is no difference between using a foreach and for in C#. They both offer the same performance, as the compiler will optimize each statement appropriately. The only time when a for loop can offer better performance is when the number of elements is a fixed number, basically a hard coded conditional:

eg)

for (int index = 0; index < 15; index++)


~Graham

Share this post


Link to post
Share on other sites
Quote:
Original post by gwihlidal
There is no difference between using a foreach and for in C#. They both offer the same performance, as the compiler will optimize each statement appropriately.


No you're wrong that very much depends on the implementation on the IEnumerator returned by the IEnumerable class. Is posile to have very close perf for foreach and for constructs but it is also posilble to have a big diference

From the C# 'Language Specification 2.0.doc' :
"
In a foreach statement of the form
foreach (ElementType element in collection) statement
if the collection expression is a type that does not implement the collection pattern, but does implement the constructed interface System.Collections.Generic.IEnumerable<T> for exactly one type T, then the expansion of the foreach statement is:
IEnumerator<T> enumerator = ((IEnumerable<T>)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
enumerator.Dispose();
}
"

So you can see in this case we have a cast and a method call which might not be inlined if it's more 32 Bytes (in opcode size). So the oportunity for a perf degrade is definatly here.


Share this post


Link to post
Share on other sites
Quote:
Original post by gwihlidal
There is no difference between using a foreach and for in C#. They both offer the same performance, as the compiler will optimize each statement appropriately. The only time when a for loop can offer better performance is when the number of elements is a fixed number, basically a hard coded conditional:

eg)

for (int index = 0; index < 15; index++)


~Graham


Also, writing your for loops as:
for(int index = 0; index < array.Length; index++)

makes it easier for the compiler to hoist the bounds check out of the loop body.

Share this post


Link to post
Share on other sites

This topic is 4303 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this