samedi 7 mars 2015

RAII for resources that can be invalidated


I'm a hobbyist C++ and DirectX programmer, so most of the knowledge I have is from old game development books in which the code designs are just to get something up and running as a demonstration, leaving me with a lot of design considerations for even the simplest of programs. During development of such a program, I recently learned of RAII, so I decided to give this design pattern a shot because from what I understood, an object should be usable and valid upon construction and this greatly simplifies the way objects can be used by the program. Previously, I had been using a create() & destroy() pattern in some of my objects which lead to a lot of validation checking in most member functions.


In the program's architecture, there are very few graphics objects that are constructed with DirectX resources, one of them being a Texture object. If I want to render tile map for example, I could have Tile objects that are constructed with pointers to AnimatedImage objects which are constructed with pointers to Texture objects.


The problem with using DirectX is that there are times in which the graphics device becomes lost, such as a driver update for the video card during program execution. When these events happen, the existing graphics resources must be released and reacquired to continue rendering normally, including the destruction and reconstruction of the Texture objects. This makes the use of an RAII design pattern seem like it may not be the best choice. I would need recreate the Texture objects, recreate the AnimatedImage objects, and then recreate the Tile objects. It seems like an extreme hassle because some objects that are recreated will contain more than just image data.


Is there some design concept I am missing here or is this one of those cases in which RAII works, but at a huge cost? Are there any known design patterns that are specifically suited for this scenario?


Here were some of the ways I have thought of approaching this:




  1. Equip the graphics objects with a recreate() method. The advantage is that any object that points to a Texture can retain that pointer without being destroyed. The disadvantage is that if the reacquisition fails, I would be left with a zombie object which is no better than the create() & destroy() pattern.




  2. Add a level of indirection using a registry of all graphics objects that will return an index to a Texture pointer or a pointer to a Texture pointer so that existing objects that rely on graphics don't need to be destroyed. Advantages and disadvantages are the same as above with the added disadvantage of additional overhead from the indirection.




  3. Store the current state of the program and unwind back until the graphics objects have been reacquired, then rebuild the program in the state it was in. No real advantage I can think of, but seems the most RAII appropriate. The disadvantage is the complexity in implementing this for a scenario that is not too common.




  4. Completely segregate all visual representations of objects from their physical representations. The advantage is that only the necessary objects to be recreated actually are, which can leave the rest of the program in a valid state. The disadvantage is that the physical and visual objects still need to know about each other in some way, which may lead to some bloated object management code.




  5. Abort program execution. The advantage is that this is as easy as it gets and very little work is spent for something that does not often happen. The disadvantage is that it would be frustrating to anyone using the program.






Aucun commentaire:

Enregistrer un commentaire