The Singleton Pattern

June 11th, 2010 by

I have seen many implementations of the singleton pattern all with their advantages and disadvantages. In this post I will describe how we implemented the singleton pattern in C++ for FireFly engine 1.0 and 2.0. The example code present in this post does not compile out of the box and is only meant to illustrate ideas.

The singleton pattern is a design pattern that makes sure that there is only one instantiation of a given object. This is particularly useful if there is a single object that performs actions for the entire system.
I actually think that this pattern is bad code practice but we use it nonetheless. The reason why I think it is bad is because from a design point of view there is no easy way to find what code actually uses the singleton since the singleton is part of the global state. The object is exposed everywhere in the code so it could be used everywhere.
Even though the singleton pattern could be seen as an anti pattern it has it uses. If there were no singletons, developers would have to pass the object around which, for object that are used a lot, is a pain in the ass.

Ok so for implementation details. :)
The first and simplest way is using a static function that returns the address to a static local variable:

class A {
public:
    static A *GetInstance() {
        static A instance;
        return &instance;
    }
}

This is a simple and elegant method but it gives you absolutely no control over when and how the singleton instance is instantiated and destroyed. A more robust way is to instantiate the singleton once and delete it when we are done with it. One way to achieve this is like so:

class B {
private:
    static B *singleton;

public:
    B() {
        assert( singleton == 0 );
        singleton = this;
    }
    ~B() { singleton = 0; }

    static B *GetInstance() { return singleton; }
}

With this method we have to explicitly instantiate B and we have to delete the class when we are done with it. However it gives us much more control over the entire process. However using this method involves a lot of code duplication. The singleton setup code is the same for every singleton class. We tackled this by defining macros that take care of declaration, implementation, construction and destruction.

class C {
    __DeclareSingleton(C)

public:
    C() {
        __ConstructSingleton;
    }
    ~C() {
        __DestructSingleton;
    }
}

The code in the example above is a lot more flexible. The defines remove the code duplication of the second example almost completely but not entirely. Fortunately there is another method that is described in Game Programming Gems 1. It involves a template class that wraps the singleton stuff. To make a class a singleton all one would have to do is derive from this template class like so:

class D : Singleton<D> {
}

This approach requires no additional effort from the programmer, it removes code duplication and we can implement the singleton class anyway we want. Lets take a look at the implementation of this singleton class:

template<class T>
class Singleton {
private:
    static T *instance;

public:
    Singleton() {
        assert( instance == 0 );
        int offset = (intptr_t)(T*)1 - (intptr_t)(Singleton*)(T*)1;
        instance = (T*)((intptr_t)this+offset);
    }

    virtual ~Singleton() {
        instance = 0;
    }

    static T *GetInstance() {
        return instance;
    }
}

The constructor looks very scary but does in fact nothing more than retrieving a pointer to T from the this pointer. This is only possible under the assumption that T is a subclass of the Singleton<T> class. What happens is that it first figures out the relative address of the derived class T and then stores the result in the instance pointer. The derived class could be deriving from more than just our Singleton<T> class, in which case the this pointer from our derived class might be different from the Singleton’s this. The solution is to take a nonexistent object at address 0×1 in memory, cast it to both types, and see what the difference is. The difference is the offset from the Singleton<T> to the derived class T. I just love the things you can do in C++! :)
Of course you can implement more methods than just the GetInstance method like for instance a method that returns a reference to the singleton or a method that checks it the singleton has been instantiated. All of these methods are trivial to implement. And because it is a separate class you can implement anything you like without having to modify code anywhere else.

So to conclude, I am very happy about our implementation of the singleton (anti-)pattern. :)

Time for screenies

May 27th, 2010 by

I created some in-game screenshots of the engine me and my friend have been working on for the last few months. We wrote the engine to compare different lighting methods. We also wrote a paper about it which will be published here in a few weeks. In the mean time you can enjoy these screenshots which are all taken in-game at framerates around 300.

Fugly vs Nais

April 13th, 2010 by

Ran into this today :)

// FUGLY
statistics->SetVisibility(false);
debugMenu->SetVisibility(false);
bufferVisualiser->SetVisibility(false);
fpsCounter->SetVisibility(false);*/

// NAIS!
DebugHUD::OverlayItem *items[] = { statistics, debugMenu, bufferVisualiser, fpsCounter };

std::for_each(items,  // First item
	items + sizeof(items)/sizeof(items[0]), // Last item
	std::bind2nd( std::mem_fun(&DebugHUD::OverlayItem::SetVisibility), false) );	// Call the SetVisibility method on the object with true as parameter
Deferred rendering/shading

March 13th, 2010 by

We, which would be me and Marriez finally finished the deferred shading renderer this week.

Deferred shading is different from standard rendering in that it renders the lighting after all the geometry has been rendered. Standard, also called forward rendering requires a geometry pass for every light that influences the rendered geometry. Of course optimization can be made by not doing a pass for a single light but for multiple lights. For every pass however, all the geometry has to be processed, which takes time especially when the geometry is very complex. Forward rendering has a complexity of O(NL) where N is number of objects and L the number of lights.

Deferred shading does a single geometry pass. The geometry pass stores, per pixel, data required for lighting the scene in buffers. The buffers maintain normal, color, depth and material properties. These buffers are then used to perform the final lighting stage in which a pass for every light is done. Because all geometry is only rendered once deferred rendering has a complexity of O(N+L).

Unfortunately deferred shading has some caveat. The geometry buffers only holds data per pixel for a single depth. You cannot store multiple layers of depth which means you cannot do transparency. We solved this by using a forward pass to render the transparent geometry.

I will probably write a more detailed description of how our deferred renderer works in my next post. In the mean time you can enjoy these screenshots. :)

Order independent transparency

February 25th, 2010 by

Well we (Marriez & I) have been implementing lots of new stuff in our research project but there are two things that definitely stick out; the post processing framework and the order independent transparency.

The post processing framework allows very simple stacking of different effects like monochrome, sepia, underwater riple and also High Dynamic Range tonemapping and bloom. The framework automatically determines what rendertargets to use. It also automatically recycles the buffers, effectively creating a rendertarget pool. The framework follows the same approach described in this article but goes a step further. Using the post processing framework we also implemented High Dynamic Range Rendering as one of the post processing framework effects. The effect applies dynamic tone mapping and bloom to the scene.

We also implemented rendering of transparent objects. Transparent objects need to be sorted back to front to create a proper result. We looked at a lot of techniques that sort the renderable items but this requires a lot of processing on the CPU especially since we have a lot of transparent objects in our scene. It also fails if two transparent primitives cross each other because every sort result will produce a faulty image.

After realizing that sorting would not get us very far we looked at order independent transparency. The basic idea is that it does not matter in which order you render the transparent objects the result will always be correct. We first looked at depth peeling. With depth peeling the different layers of transparency that overlap are extracted from the image and rendered in the correct order which produces the final correct image. Testing showed that this technique was very inefficient the more layers that overlapped the more the framerate dropped. While researching a more efficient way to do depth peeling we stumbled upon another technique called weighted average transparency rendering. This technique is not linear in the number of overlapping primitives, requires less video memory (on average), is mostly GPU based and required very little effort to integrate into our existing rendering pipeline. The downside is that the technique does not produce a correct image but an approximation. The technique is described here under Single-pass Approximation  -> Weighted Average.

The technique used the observation that if all the colors for are given pixel are equal than the result is independent of the order in which the  fragments are blended. If the colors are not uniform than we simply replace the multiple colors by a uniform color namely the average of all the colors. When rendering the transparent objects they are additively rendered into an accumulation buffer. The result is an accumulated RGBA color  and the number of fragments per pixel. After this accumulation step the buffers are passed to a post processing step that performs the final calculation. In the original paper they also pass the framebuffer to the post processing step while we choose to use blending for this.