[Dx9 API] Problem with Memory Leak Loading Textures

Started by
3 comments, last by yewbie 12 years, 9 months ago
I have been wracking my brain over this issue for the last 1 1/2 days, I have searched far and wide and I can't really find any good information on how to proceed.. So here is my problem.

I have a class I have written to load a image "sprite sheet" parse it out and dump it into many textures I can use inside of my game, this works great!
But when resources are lost via a control-alt-delete, etc. I ->Release() all of my textures, and everything even down to my d3d interface and recreate everything, well I am getting a huge memory leak everytime I do this, but I thought releasing everything would free up the memory? it doesn't seem to.

Everytime CreateDevice is called (even after a safe release) It still adds 3+ megs to my games memory used.

On top of just that, my texture loading class doesn't seem to be freeing memory either.

It doesn't seem like release is really doing anything?


Here is my code im using to load my textures into a vector
my vector is delcared like so
vector <LPDIRECT3DTEXTURE9> TextureList;

Any help would be GREATLY appreciated.


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TEXTUREMANAGER::LoadTextureSheet(string FileName, IDirect3DDevice9* D3d, int TileWidth, int TileHeight)
{
LPDIRECT3DSURFACE9 TempSurface; //this is our scratch surface when we are loading a textureset
LPDIRECT3DSURFACE9 TexSurface; //this is our scratch surface for our texture

Filename = FileName;
NumberOfTextures = 0;
D3DCOLOR colorkey = 0xFFFF00FF;
colorkey = D3DCOLOR_XRGB(0,0,0);

D3DXIMAGE_INFO info;
HRESULT result = D3DXGetImageInfoFromFile(FileName.c_str(), &info);

if(result != D3D_OK)
{
MessageBox(NULL, "Failed D3DXGetImageInfoFromFile", "error!" , MB_OK);
return;
}


//Create TextureSheet surface
result = D3d->CreateOffscreenPlainSurface(
info.Width, //Width of the surface
info.Height, //height of the surface
D3DFMT_A8R8G8B8, //Surface format
D3DPOOL_SYSTEMMEM, //Memory pool to use
&TempSurface, //Pointer to the surface
NULL); //Reserved (always NULL)
if(result != D3D_OK)
{
MessageBox(NULL, "Failed CreateOffscreenPlainSurface for TempSurface", "error!" , MB_OK);
return;
}


result = D3d->CreateOffscreenPlainSurface(info.Width, info.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &TexSurface, NULL);
if(result != D3D_OK)
{
MessageBox(NULL, "Failed CreateOffscreenPlainSurface for TexSurface", "error!" , MB_OK);
return;
}


//Load surface from file into newly created surface
result = D3DXLoadSurfaceFromFile(
TempSurface, //Destination surface
NULL, //Destination palette
NULL, //Destination rectangle
FileName.c_str(), //Source filename
NULL, //Source rectangle
D3DX_DEFAULT, //Controls how image is filtered
colorkey, //For transparency (0 for none)
NULL); //Source image info (usually NULL)
if(result != D3D_OK)
{
MessageBox(NULL, "Failed D3DXLoadSurfaceFromFile TempSurface", "error!" , MB_OK);
return;
}


int TilesWide = info.Width / TileWidth;
int TilesHigh = info.Height / TileHeight;

for(int b=0;b<TilesHigh;b++)
{
for(int a=0;a<TilesWide;a++)
{

LPDIRECT3DTEXTURE9 NewTexture = NULL;

result = D3DXCreateTexture(D3d,TileWidth,TileHeight,1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT, &NewTexture);

if(result != D3D_OK)
{
MessageBox(NULL, "Failed D3DXCreateTexture TempSurface", "error!" , MB_OK);
return;
}


result = NewTexture->GetSurfaceLevel(0, &TexSurface); //get surface of texture

if(result != D3D_OK)
{
MessageBox(NULL, "Failed GetSurfaceLevel TempSurface", "error!" , MB_OK);
return;
}

RECT Source;
SetRect(&Source, a*TileWidth,b*TileHeight, (a*TileWidth)+TileWidth,(b*TileHeight)+TileHeight);
RECT Dest;
SetRect(&Dest, 0,0,TileWidth,TileHeight);
result = D3d->UpdateSurface(TempSurface, &Source, TexSurface, NULL);

NumberOfTextures++;
TextureList.push_back(NewTexture);

if(TexSurface != NULL)
{
TexSurface->Release();
TexSurface = NULL;
}

}
}

cout << "Loaded: " << NumberOfTextures << " Textures" << endl;
Height = TileHeight;
Width = TileWidth;

if(TexSurface != NULL)
{
TexSurface->Release();
TexSurface = NULL;
}
if (TempSurface != NULL)
{
TempSurface->Release();
TempSurface = NULL;
}
}


This is my code im using to iterate through the vector and release all of them and then clear it

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TEXTUREMANAGER::ReleaseTextures() //Releases our surfaces
{
for(int i=0;i<NumberOfTextures;i++)
{

if(TextureList.at(i) != NULL)
{

TextureList.at(i)->Release();
TextureList.at(i)=NULL;
}
else
{
cout << "Could not release texture: " << i << endl;
}
}
NumberOfTextures = 0;
TextureList.clear();
cout << "Released Textures" << endl;
}
Advertisement
try this out and save some trouble

HRESULT D3DXCreateTextureFromFile( __in LPDIRECT3DDEVICE9 pDevice, __in LPCTSTR pSrcFile, __out LPDIRECT3DTEXTURE9 *ppTexture );
Wisdom is knowing when to shut up, so try it.
--Game Development http://nolimitsdesigns.com: Reliable UDP library, Threading library, Math Library, UI Library. Take a look, its all free.

try this out and save some trouble

HRESULT D3DXCreateTextureFromFile( __in LPDIRECT3DDEVICE9 pDevice, __in LPCTSTR pSrcFile, __out LPDIRECT3DTEXTURE9 *ppTexture );


I was doing that loading hundreds of individual images and it got really annoying to keep track of, so I made this solution to load a single image to load hundreds of textures at a single time.
And it works great, the only problem is with restoring my devices and some memory leak.

It really appears to me that Release() is not freeing the memory at all.

And loading a image as a surface makes it easier to manipulate than a texture.
A little update here, I ran a test app that (outside of a lost or reset device) just unloads ands reloads my sprite sheet over and over with this code and there is no memory leak.

So that leads me to believe that my re-creation of my D3D interface when its lost is causing all of this.

Hrmm something to do with my extra surfaces being released and reset failing, I am still working on this but thanks to anyone that has read this.
Well I figured it out.

Firstly I needed to get the pointer and release the pointer to my backbuffer every frame.
Then I needed to release and recreate my RenderTarget(s) as well as my other frame buffers.

and in my reinit I was failing to redo the following:
CreateVertexBuffer
SetStreamSource
SetRenderState
SetTextureStageState

Here is a screenshot for good measure:

This topic is closed to new replies.

Advertisement