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)开发者_StackOverflow;
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!
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 :-)
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.
精彩评论