May 21, 2012

COM Smart Pointer in DX9/11 Renderer?

Main Article
Recently I've been developing a real-time application outside the gaming industry, and I happened to implement a very thin, stateless DX9 renderer, and then ported it to DX11. This piece of software runs on Windows PC, so it was kind of nice to deal with more powerful hardware than current-gen consoles, which I've been married to for the last 6+ years.

In the gaming industry, I don't think I saw anyone using COM smart pointers in a rendering engine while Direct3D is built on COM. Probably it's because of performance concerns.  But I'm not sure if it is still a valid concern. For the last few years, I saw more non-rendering game codes using smart pointers extensively, and most of the time the performance was fine. So I'm thinking now that it might be okay to use COM smart pointers for D3D objects.  Does anyone have any experience with this on a commercial game? If so, how did it behave?

Maybe I Should Add Something Useful Here
I feel guilty to finish this post without giving out any useful info. So let me just say how to use COM smart pointers for DX9 and 11.

For DX9:
To define smart pointers in DX9, just include comdef.h before including d3d9.h.

#incldue <comdef.h> 
#include <d3d9.h>

Then you will get a smart pointer for every single D3D type with ~Ptr prefix.  With this, your D3D device's smart pointer will be declared like this:

IDirect3DDevice9Ptr mDevice;

And using it is very straight-forward.  There's really no gotchas using this pointer.. (unlike dx11's)

For DX11:
d3d11.h doesn't contain any special preprocessor macros that automatically generate COM smart pointer types for D3D interfaces. So what I had to do was using atlbase's COM smart pointer.

First, include atlbase.h

#include <atlbase.h>

Now you can manually make smart pointers for any D3D declaration like this:

CComPtr<ID3D11Device> mDevice;

It works mostly same as DX9's COM smart pointer except one gotcha.  If you try to pass in the address of an atlbase COM smart pointer, while it's not empty, it'll assert on you.  And you know how often you have to pass in type** to a D3D calls. (e.g, to create a render target texture)  So if you do this, you should clear the smart pointer before you use & operator. This should be done by assigning nullptr to the smart pointer like this:

mRenderTarget = nullptr;

One gotcha here, I once assumed CComPtr's detach() function does the same thing as assigning nullptr, which was not true. gaaaahhh!! So don't do this, if you do that you will have unreleased resources hanging around.

K, I'm not feeling guilty anymore.. so ciao :)

No comments:

Post a Comment