7

Currently I want to optimize my 3d engine for consoles a bit. More precisely I want to be more cache friendly and align my structures more data oriented, but also want to keep my nice user interface.

For example:

bool Init()
{
  // Create a node
  ISceneNode* pNode = GetSystem()->GetSceneManager()->AddNode("viewerNode");

  // Create a transform component
  ITransform* pTrans = m_pNode->CreateTransform("trans");
  pTrans->SetTranslation(0,1.0f,-4.0f);
  pTrans->SetRotation(0,0,0);

  // Create a camera component
  ICamera* pCam = m_pNode->CreateCamera("cam", pTrans);
  pCam->LookAt(Math::Vec3d(0,0,0));

  // And so on...
}

So the user can work with interface pointers in his code.

BUT
In my engine I currently store pointers to scene nodes.

boost::ptr_vector<SceneNode> m_nodes

So in data oriented design it's good practice to have structs of arrays and not arrays of structs. So my node gets from...

class SceneNode
{
private:
  Math::Vec3d m_pos;
};

std::vector<SceneNode> m_nodes;

to this...

class SceneNodes
{
  std::vector<std::string> m_names;
  std::vector<Math::Vec3d> m_positions;
  // and so on...
};

So I see two problems here if I want to apply DOP. Firstly how could I keep my nice user interface without having the user to work with IDs, indexes and so on?

Secondly how do I handle relocations of properties when some vectors resize without letting users interface pointers point to nirvana?

Currently my idea is to implement a kind of handle_vector from which you get a handle for persistent "pointers":

typedef handle<ISceneNodeData> SceneNodeHandle;
SceneNodeHandle nodeHandle = nodeHandleVector.get_handle(idx);

So when the intern std::vector resizes, it updates its handles. A "handle" stores a pointer to the actual object and the "->" operator is overloaded to achive a nice wrapping. But this approach sounds a bis complicated to me?!

What do you think? How to keep a nice interface, but keep thinks contiguous in memory for better cache usage?

Thanks for any help!

VitaminCpp
  • 314
  • 1
  • 4
  • 11
  • Data-oriented-programming is in my example the conversion from arrays-of-structs to a struct-of-arrays. The virtual Update() methode gets pulled out of a SceneNode an is then a member of the SceneNodes structure. So I can step linear over my arrays in which I'm interested. – VitaminCpp Oct 06 '10 at 17:19

2 Answers2

5

You will need to use smarter handles than raw pointers. There is no way around it with DOP.

This means:

class SceneNode
{
public:
  std::string const& getName() const { mManager->getSceneName(mId); }
  void setName(std::string const& name) { mManager->setSceneName(mId, name); }

  // similar with other data
private:
  ISceneManager* mManager;
  size_t mId;
};

One very good point though: the user cannot accidently call delete on one of the pointer you returned now. That's why smart handles are always better.

On the other hand: how are you going to deal with the lifetime of the pointee of mManager is another issue :-)

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Yes I also thought in this direction, but it doesn't seem very elegant to me... But I think I will choose such a solution and hide the indexing from the user. In my design all "managers" are global. So a simple assert() in debug mode to ensure we have a valid manager is enought. This is a big drawback of DOP. Thank you! – VitaminCpp Oct 06 '10 at 14:12
  • @VitaminCpp: it's not really a drawback, as far as I am concerned, because I always use smart handles anyway when designing an interface. Much easier to evolve, may include reference counting transparently, protects the content and may provide binary compatibility much more easily. – Matthieu M. Oct 06 '10 at 14:34
  • Indeed this is a strong argument! Now the hard part is to remodel the scene node itself DOP... :( Thanks a lot! – VitaminCpp Oct 06 '10 at 14:46
1

For those interested in a practical example of DOP, have a look at this fantastic presentation from Niklas Frykholm => http://bitsquid.blogspot.com/2010/05/practical-examples-in-data-oriented.html

This helped me to implement my scene graph in a data oriented manner.

VitaminCpp
  • 314
  • 1
  • 4
  • 11