• Advertisement
Sign in to follow this  

Video Memory Leak

This topic is 3763 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a bug. In my program, if the user changes the screen settings (resolution or whatever), the code essentially dumps everything D3D and rebuilds it. The problem I'm having is that if they do this more than a few times, the program crashes with an error. This is what I get in my log file [7.49324]Unable to Create Direct3D Device Direct3DClass::InitD3D(): Out of video memory - D3DERR_OUTOFVIDEOMEMORY The thing is, I can't figure out why it's running out of video memory. As far as I can tell, I release all the textures and vertex buffers. Is there some other thing I'm supposed to do when I reset the device? This is the function that gets called when the screen settings are changed.
void Direct3DClass::ChangeScreenSettings(int AdapterIndex, int DisplayModeIndex, int DeviceModeIndex, int ComboModeIndex)
    {
    //get rid of everything
    InterfaceManager.ReleaseCurrentScreen();
    TextureManager.ReleaseAllTextures();
    FontManager.ReleaseFonts();
    SAFE_RELEASE(TwoDVertexBuffer);
    SAFE_RELEASE(ThreeDVertexBuffer);
    SAFE_RELEASE(D3DDevice);
    SAFE_RELEASE(D3D);

    //set the current settings to the desired settings
    CurrentAdapter = AdapterIndex;
    CurrentDisplayMode = DisplayModeIndex;
    CurrentDevice = DeviceModeIndex;
    CurrentCombo = ComboModeIndex;

    //reset D3D and then the user screen
    InitD3D();
    FontManager.InitializeFonts();
    InterfaceManager.RebuildScreen();
    }



The error happens in the InitD3D function, which is pretty long and complicated, but the crash occurs right near the beginning at the CreateDevice() call, so I'll post it up to that point. But I don't think there's anything bad in here.
HRESULT Direct3DClass::InitD3D()
	{
	HRESULT r;
    ostringstream ss;
	static char FunctionString[] = "Direct3DClass::InitD3D()";

	D3D = Direct3DCreate9(D3D_SDK_VERSION);

	ZeroMemory(&PresentParams, sizeof(PresentParams));
	if (AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].Windowed == true)
		{
		PresentParams.BackBufferWidth = 0;
		PresentParams.BackBufferHeight = 0;
		PresentParams.BackBufferFormat = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].BackbufferFormat;
		PresentParams.BackBufferCount = 1;
		PresentParams.MultiSampleType = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].MultiSampleType;
		PresentParams.MultiSampleQuality = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].MultiSampleQuality;
		PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
		PresentParams.hDeviceWindow = ControlWindow.GetControlWindowHandle();
		PresentParams.Windowed = true;
		PresentParams.EnableAutoDepthStencil = true;
		PresentParams.AutoDepthStencilFormat =  AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].DepthStencilFormat;
		PresentParams.Flags = 0;
		PresentParams.FullScreen_RefreshRateInHz = 0;
		PresentParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
		}
	else
		{
		PresentParams.BackBufferWidth = AdapterInfo[CurrentAdapter].DisplayMode[CurrentDisplayMode].Width;
		PresentParams.BackBufferHeight = AdapterInfo[CurrentAdapter].DisplayMode[CurrentDisplayMode].Height;
		PresentParams.BackBufferFormat = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].BackbufferFormat;
        PresentParams.BackBufferCount = 1;
		PresentParams.MultiSampleType = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].MultiSampleType;
		PresentParams.MultiSampleQuality = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].MultiSampleQuality;
		PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
		PresentParams.hDeviceWindow = ControlWindow.GetControlWindowHandle();
		PresentParams.Windowed = false;
		PresentParams.EnableAutoDepthStencil = true;
		PresentParams.AutoDepthStencilFormat =  AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].DepthStencilFormat;
		PresentParams.Flags = 0;
		PresentParams.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
		PresentParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
		}

	r = D3D->CreateDevice(AdapterInfo[CurrentAdapter].AdapterIndex , AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].DevType, ControlWindow.GetControlWindowHandle(), AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].Behavior, &PresentParams, &D3DDevice);

    ....etc....



I appear to be leaking video memory somehow, but I don't see where. Anyone have any ideas?

Share this post


Link to post
Share on other sites
Advertisement
Quote:
the code essentially dumps everything D3D and rebuilds it.

Can I ask why you do not release volatile memory and just call reset with the new params?

Share this post


Link to post
Share on other sites
Because I had all the functions in place to do a complete reset, and it seemed like the easiest and safest way to do it.

But just in case I tried with a reset


void Direct3DClass::ChangeScreenSettings(int AdapterIndex, int DisplayModeIndex, int DeviceModeIndex, int ComboModeIndex)
{
HRESULT r;
ostringstream ss;
static char FunctionString[] = "Direct3DClass::ChangeScreenSettings()";

//get rid of everything
InterfaceManager.ReleaseCurrentScreen();
TextureManager.ReleaseAllTextures();
FontManager.ReleaseFonts();

//set the current settings to the desired settings
CurrentAdapter = AdapterIndex;
CurrentDisplayMode = DisplayModeIndex;
CurrentDevice = DeviceModeIndex;
CurrentCombo = ComboModeIndex;

ZeroMemory(&PresentParams, sizeof(PresentParams));
if (AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].Windowed == true)
{
PresentParams.BackBufferWidth = 0;
PresentParams.BackBufferHeight = 0;
PresentParams.BackBufferFormat = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].BackbufferFormat;
PresentParams.BackBufferCount = 1;
PresentParams.MultiSampleType = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].MultiSampleType;
PresentParams.MultiSampleQuality = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].MultiSampleQuality;
PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
PresentParams.hDeviceWindow = ControlWindow.GetControlWindowHandle();
PresentParams.Windowed = true;
PresentParams.EnableAutoDepthStencil = true;
PresentParams.AutoDepthStencilFormat = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].DepthStencilFormat;
PresentParams.Flags = 0;
PresentParams.FullScreen_RefreshRateInHz = 0;
PresentParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
}
else
{
PresentParams.BackBufferWidth = AdapterInfo[CurrentAdapter].DisplayMode[CurrentDisplayMode].Width;
PresentParams.BackBufferHeight = AdapterInfo[CurrentAdapter].DisplayMode[CurrentDisplayMode].Height;
PresentParams.BackBufferFormat = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].BackbufferFormat;
PresentParams.BackBufferCount = 1;
PresentParams.MultiSampleType = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].MultiSampleType;
PresentParams.MultiSampleQuality = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].MultiSampleQuality;
PresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
PresentParams.hDeviceWindow = ControlWindow.GetControlWindowHandle();
PresentParams.Windowed = false;
PresentParams.EnableAutoDepthStencil = true;
PresentParams.AutoDepthStencilFormat = AdapterInfo[CurrentAdapter].DeviceInfo[CurrentDevice].Combo[CurrentCombo].DepthStencilFormat;
PresentParams.Flags = 0;
PresentParams.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
PresentParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
}

D3DDevice->Reset(&PresentParams);
FontManager.InitializeFonts();
InterfaceManager.RebuildScreen();
}



This gives me a parameter error

{[5.99588]Unable to Reset Direct3D Device Direct3DClass::ChangeScreenSettings(): Invalid call - D3DERR_INVALIDCALL}

Not really sure why, I haven't spent a ton of time looking at it.

Share this post


Link to post
Share on other sites
Okay, I've looked at it, and I give up. I can find no reason why I should be getting an invalid call error. The present parameters are *exactly* the same as they were during initalization (which works, obviously). The only difference is that the reset is done after textures/etc. have been set up. I'm pretty sure I dumped all my D3DPOOL_DEFAULT stuff before calling the reset.

If I have D3DPOOL_DEFAULT resources still around when I call the reset, would it cause that error?

Share this post


Link to post
Share on other sites
Have you enabled DirectX debug from the control panel? Have you tried using pix?

Share this post


Link to post
Share on other sites
What is pix? I don't know that one.

When I enabled the debug libraries, I got a host of errors. I guess I should have done that earlier, heh. It's not even letting me to the main screen with them on anymore. I'm getting a host of errors from just being on the load screen in my Debug Output that say

D3D9: (ERROR) Clear Failed
D3D9: (ERROR) Multisample Type between depth stencil buffer and Render Target must match

That corresponds to entries in my log output which say

{[4.14412]Unable to Clear Scene InterfaceManagerClass::DisplayScreen: Invalid call - D3DERR_INVALIDCALL}

Which is from the clear call

r = Direct3D.GetD3DDevice()->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 0, 0, 0), 0, 0);

So I have to clean up that before I can even get back to where I was. I'll work on it, thanks for suggesting I run the debug libraries. (I already fixed one bug brought to light from the debug D3D that has made my intro movie run much cleaner, so it's already been a plus).

Share this post


Link to post
Share on other sites
Alright, I found the leak. For some of my text stuff I set a new render target, first saving the original.

r = Direct3D.GetD3DDevice()->GetRenderTarget(0, &OriginalTarget);

r = Direct3D.GetD3DDevice()->SetRenderTarget(0, TextRenderTarget->GetTextureSurface());

Then I drew the text and reset the render target

r = Direct3D.GetD3DDevice()->SetRenderTarget(0, OriginalTarget);

Well, once the rouitne was over, I was not releasing the original render target that I got from the GetRenderTarget call. Thus the video memory leak. I added the release call, and now I can either to a Reset call or just rebuild D3D altogether, and it works just fine.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement