You likely have other surfaces alive in your executable somewhere. PIX will show you these objects in Direct3D 9.
Instead of trying to keep track of all the objects that need to be released manually (which will soon become impractical to manage and a major waste of time in trying to do so), wrap all the resource objects (textures, surfaces, index buffers, and vertex buffers) behind classes and use the constructor of the class to register that instance with some kind of “release manager” (and unregister in each object’s destructor).
When you want to release all the objects that need to be released just tell the release manager to send said notification to all objects it has and let them release anything they need to release. A similar notification is sent to have those objects recreate their resources when the device comes back.
It is really quite simple. Here is an example.
LSGDirectX9LosableResourceManager.h
class CDirectX9LosableResourceManager {
public :
// == Functions.
/**
* Destroy the losable resource manager. Should be called when shutting down.
*/
static LSVOID LSE_CALL Destroy();
/**
* Register a resource (also gives the resource a unique ID).
*
* \param _plrRes The resource to register. Losable resources call this on
* themselves directly, so this function should never be called by the user.
* \return Returns false if a memory error occurred. If false is returned, the
* engine must shut down.
*/
static LSBOOL LSE_CALL RegisterRes( CDirectX9LosableResource * _plrRes );
/**
* Remove a resource by its ID.
*
* \param _ui32Id Unique ID of the resource to remove from the list.
*/
static LSVOID LSE_CALL RemoveRes( LSUINT32 _ui32Id );
/**
* Notify all objects that the device has been lost.
*/
static LSVOID LSE_CALL OnLostDevice();
/**
* Notify all objects that the device has been reset.
*/
static LSVOID LSE_CALL OnResetDevice();
protected :
// == Members.
/** List of resources. */
static std::vector<CDirectX9LosableResource *> m_vResources;
/** Unique resource ID. */
static LSUINT32 m_ui32ResId;
/** Thread safety. */
static CCriticalSection m_csCrit;
};
LSGDirectX9LosableResource.h
class CDirectX9LosableResource {
friend class CDirectX9LosableResourceManager;
public :
// == Various constructors.
LSE_CALLCTOR CDirectX9LosableResource();
LSE_CALLCTOR ~CDirectX9LosableResource();
// == Functions.
/**
* Must perform some action when the device is lost.
*/
virtual LSVOID LSE_CALL OnDeviceLost() = 0;
/**
* Must renew resources when the device is reset.
*
* \return Return true if the renewal is successful, false otherwise.
*/
virtual LSBOOL LSE_CALL OnDeviceReset() = 0;
protected :
// == Members.
/** Do we need to reset the resource? */
LSBOOL m_bResourceCanBeLost;
private :
/** An ID that lets us remove ourselves from the global resource list. */
LSUINT32 m_ui32UniqueLosableResourceId;
};
LSGDirectX9LosableResource.cpp
LSE_CALLCTOR CDirectX9LosableResource::CDirectX9LosableResource() :
m_bResourceCanBeLost( false ) {
CDirectX9LosableResourceManager::RegisterRes( this );
}
LSE_CALLCTOR CDirectX9LosableResource::~CDirectX9LosableResource() {
CDirectX9LosableResourceManager::RemoveRes( m_ui32UniqueLosableResourceId );
}
LSGDirectX9IndexBuffer.h
class CDirectX9IndexBuffer : public CIndexBufferBase, public CDirectX9LosableResource
…
// == Functions.
/**
* Must perform some action when the device is lost.
*/
virtual LSVOID LSE_CALL OnDeviceLost();
/**
* Must renew resources when the device is reset.
*
* \return Return true if the renewal is successful, false otherwise.
*/
virtual LSBOOL LSE_CALL OnDeviceReset();
…
LSGDirectX9IndexBuffer.cpp
LSVOID LSE_CALL CDirectX9IndexBuffer::OnDeviceLost() {
if ( !m_bResourceCanBeLost || !m_pibIndexBuffer ) { return; }
// Release the existing index buffer.
CDirectX9::SafeRelease( m_pibIndexBuffer );
}
LSBOOL LSE_CALL CDirectX9IndexBuffer::OnDeviceReset() {
if ( !m_bResourceCanBeLost ) { return true; }
return CreateApiIndexBuffer();
}
CDirectX9LosableResource automatically registers itself with the CDirectX9LosableResourceManager and provides OnDeviceLost() and OnDeviceReset() as pure virtual methods.
CDirectX9IndexBuffer overrides them appropriately.
Because every object that inherits from CDirectX9LosableResource is autmatically registered as a system-wide losable resource, there are never any forgotten objects hanging around causing your device reset to fail.
L. Spiro