• 15
• 15
• 11
• 9
• 10

# Screenshot Problem (Missing HUD images)

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

## Recommended Posts

Hi Guys, Recently I incorporated a Screenshot function into my tech demo. The problem I am having is that when I take a screenshot everything is copied into the created .png image apart from any HUD images/textures I have set on the screen (these are also .png). It seems like it is only drawing the 3d scene into the screenshot and leaving out 2d stuff. I am taking a screenshot of the backbuffer, is this my problem? If so how can I solve it? Heres my code:
  // Save the screen shot
if(!screenShotSaved && KEY_DOWN(VK_SNAPSHOT))
{
D3DDISPLAYMODE display;
d3ddev->GetDisplayMode(0, &display);

// Create the off screen surface with the same info as the back buffer
d3ddev->CreateOffscreenPlainSurface(display.Width, display.Height, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT,
&ScreenShotSurface, NULL);

// Save the back buffer to the surface
d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &ScreenShotSurface);
sprintf_s(screenshotdir,"Screenshots/Screenshot%d.png",i);
D3DXSaveSurfaceToFile(screenshotdir, D3DXIFF_PNG, ScreenShotSurface, NULL, NULL);
// Increase i for next screenshot (Only allow up to 10 screenshots max for memory safety)
if(i>=10)
i = 1;
else
i++;

screenShotSaved = true;
}


thanks.

##### Share on other sites
First, that's a resource leak - GetBackBuffer() returns a pointer to a surface, so you newly created surface is lost. You're also not Release()ing the backbuffer pointer GetBackBuffer() gives you.

As for the actual problem, where are you calling that function? The correct place is after the last EndScene() call (and therefore after any ID3DXSprite::End() calls too), but before Present().

You should be using the Debug Runtimes, which will point out any obvious problems, and will show that memory leak I mentioned.

##### Share on other sites
Hi EvilSteve,

thanks for taking out the time to help me.

I forgot to mention I am releasing it in my CleanD3D() function:

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

and as for the screenshot function i am calling it:

AH DAMN!! THanks Steve, just realised when I was going to actually copy the code here that I am calling it before I draw the HUD in my render function.
I will change it to appear just before Present!

Another question I wanted to ask was about the FPS, I am calling my FPS function straight after:

d3ddev->Present(NULL, NULL, NULL, NULL);
// This will get the frames per second
GetFPS();

I will show my FPS function below, but what my problem is that I am getting around the region of 33 fps everytime? All I am doing in my program is calling a few .x meshes and rotating them. Is their a reason why my FPS is low?
Because I have seen similar tutorial demos, and in them I get FPS of about 220 or even one demo at 700fps.

I know this question is probably very awkward to answer as it depends on a lot of things but do you have any sujjesstions?

Here is my code:

// Gets and displays the Frames Per Secondvoid GetFPS(){   // Hold the number of frames per second in between seconds   static float FPS = 0.0f;   // Check if a second has passed   float nextSecond = 0.0f;   // Last second that occured   static float prevSecond = 0.0f;   // Add to the frames per second every time this function is called   FPS++;   // Get the second in millisecond then convert to seconds (by multiplying 0.001)   nextSecond = GetTickCount() * 0.001f;				   // If the time we have now substracted from the previous second is greater than   // or equal to 1 (i.e. if a second has passed) then we display the FPS number   if(nextSecond - prevSecond > 1.0f)      {         // Make the second we just got the previous second for next time the function is called	     prevSecond = nextSecond;		            // Display the FPS		 sprintf_s(frames,"FPS: %d",int(FPS));         // Reset the FPS counter         FPS = 0;      }}//End GetFPS

##### Share on other sites
Quote:
 Original post by NadsHi EvilSteve,thanks for taking out the time to help me.I forgot to mention I am releasing it in my CleanD3D() function:*** Source Snippet Removed ***

Why? Since you're not using it after you take the screenshot, you may as well release it as soon as you're done with it. This will also help prevent any mistakes; for example if you forget to call CleanD3D() every time you take a screenshot.

##### Share on other sites
GetTickCount() is extremely inaccurate, it's only got a granularity of about 25ms. So if a frame takes under 25ms, it'll report a time of 0ms.

You should use QueryPerformanceCounter instead, or timeGetTime (QPC has it's own issues).

Here's my timer class (Which may have bugs of its own [smile]):

//============================================================================// PTimer.h - Timer class//============================================================================#ifndef __PTIMER_H__#define __PTIMER_H__#include <windows.h>class PTimer{public:	PTimer();	~PTimer();	// Get the time taken for the last frame in ms	float GetFrameTime() const { return m_fFrameTime; }	//========================================================================	void BeginFrame();	void EndFrame();protected:	float m_fFrameTime;	DWORD m_dwStartTime;	size_t m_nIndex;	bool m_bFirstLoop;	LARGE_INTEGER m_liFreq;	LARGE_INTEGER m_liStart;	static const size_t ms_nFramesAverage = 16;	float m_fFrameTimes[ms_nFramesAverage];};#endif // __PTIMER_H__

Source code:
//============================================================================// PTimer.cpp - Timer class//============================================================================#include "PTimer.h"#include <mmsystem.h>#pragma comment(lib, "winmm.lib")// Max time one frame can take (Clamped to this max value)static const DWORD s_dwMaxFrameTime = 1000;// Frame time threshold (in ms) under which QPC result is usedstatic const DWORD s_dwQPCThreshold = 5;//============================================================================PTimer::PTimer() :	m_dwStartTime(0),	m_nIndex(0),	m_bFirstLoop(true){	timeBeginPeriod(1);	QueryPerformanceFrequency(&m_liFreq);	m_liStart.QuadPart = 0;	for(size_t i=0; i<ms_nFramesAverage; ++i)		m_fFrameTimes = 0.0f;}PTimer::~PTimer(){	timeEndPeriod(1);}//============================================================================void PTimer::BeginFrame(){	m_dwStartTime = timeGetTime();	QueryPerformanceCounter(&m_liStart);}void PTimer::EndFrame(){	// Get frame time (via QPC and timeGetTime())	LARGE_INTEGER liFrameTime;	QueryPerformanceCounter(&liFrameTime);	liFrameTime.QuadPart -= m_liStart.QuadPart;	DWORD dwFrameTime = timeGetTime() - m_dwStartTime;	bool bUseTimeGetTime;	float fTime = 0.0f;	// If this was a fast frame, use QPC, and check results with timeGetTime	if(dwFrameTime < s_dwQPCThreshold)	{		fTime = ((float)(liFrameTime.QuadPart*1000) / (float)m_liFreq.QuadPart);		// Validate nonsense answers		if(fTime > (float)s_dwQPCThreshold)			bUseTimeGetTime = true;		else			bUseTimeGetTime = false;	}	else		bUseTimeGetTime = true;	// This was a slow frame, don't care what QPC says, use timeGetTime	if(bUseTimeGetTime)	{		if(dwFrameTime > s_dwMaxFrameTime)			dwFrameTime = s_dwMaxFrameTime;		fTime = (float)dwFrameTime;	}	// Record frame	m_fFrameTimes[m_nIndex++] = fTime;	if(m_nIndex >= ms_nFramesAverage)	{		m_bFirstLoop = false;		m_nIndex = 0;	}	// Calculate total	float fTotal = m_fFrameTimes[0];	for(size_t i=1; i<ms_nFramesAverage; ++i)		fTotal += m_fFrameTimes;	// Average	if(m_bFirstLoop)		m_fFrameTime = fTotal / (float)m_nIndex;	else		m_fFrameTime = fTotal / (float)ms_nFramesAverage;}//============================================================================

It's a bit complicated, but it uses QPC for quick frames (Since it's more accurate), and timeGetTime for slower ones. If QPC returns rubbish (Which it can do on dual-core CPUs with no CPU driver, and laptops), it falls back to timeGetTime(). And it also averages the FPS over 16 frames to stop it jumping around wildly.

##### Share on other sites
Quote:
Original post by Sc4Freak
Quote:
 Original post by NadsHi EvilSteve,thanks for taking out the time to help me.I forgot to mention I am releasing it in my CleanD3D() function:*** Source Snippet Removed ***

Why? Since you're not using it after you take the screenshot, you may as well release it as soon as you're done with it. This will also help prevent any mistakes; for example if you forget to call CleanD3D() every time you take a screenshot.

thanks, I will change that.

##### Share on other sites
Quote:
 Original post by Evil SteveGetTickCount() is extremely inaccurate, it's only got a granularity of about 25ms. So if a frame takes under 25ms, it'll report a time of 0ms.You should use QueryPerformanceCounter instead, or timeGetTime (QPC has it's own issues).Here's my timer class (Which may have bugs of its own [smile]):Header:*** Source Snippet Removed ***Source code:*** Source Snippet Removed ***It's a bit complicated, but it uses QPC for quick frames (Since it's more accurate), and timeGetTime for slower ones. If QPC returns rubbish (Which it can do on dual-core CPUs with no CPU driver, and laptops), it falls back to timeGetTime(). And it also averages the FPS over 16 frames to stop it jumping around wildly.

Thanks Steve.

I did try using timeGetTime aswell last night, but it gave me the same result!

Your timer class looks highly complicated, but when I get home tonight (currently at work) I will try it out and see if I can understand and incorporate it into my demo.

Are you actually calling your begin and end functions in the render function, like how I called mine after ->Present()?

Do you use this timer class just for the FPS, or is it used for other things too?

PTimer();
~PTimer();

its probably a very beginner question but whats the ~ stand for?

Thanks.

##### Share on other sites
Quote:
 Original post by NadsThanks Steve.I did try using timeGetTime aswell last night, but it gave me the same result!
Did you call timeBeginPeriod(1); ? That increases the accuracy of timeGetTime() (Called from the constructor in my class).

Quote:
 Original post by NadsYour timer class looks highly complicated, but when I get home tonight (currently at work) I will try it out and see if I can understand and incorporate it into my demo.Are you actually calling your begin and end functions in the render function, like how I called mine after ->Present()?Do you use this timer class just for the FPS, or is it used for other things too?
Yeah, my main loop is:
void PApp::MainLoop(){	do	{		m_timer.BeginFrame();		Loop(true);		m_timer.EndFrame();	} while(!ShouldExit());}

Where Loop() does all the game logic and rendering. I only use the timer for keeping track of FPS currently, but there's no reason it couldn't be used for anything else - although you'd probably want to remove the frame time averaging code.

Quote:
 Original post by NadsAlso in your header file you have: PTimer();~PTimer();its probably a very beginner question but whats the ~ stand for?
The first function is the constructor, which is called when the object is created (And used to initialise any member variables and state). The second one (~PTimer) is the destructor, which is called when the object is destroyed (When it goes out of scope or it's deleted), and is used to clean up after the object.
For example, a rendering class might call IDirect3DDevice9::Release() from the destructor to make sure that the device was always cleaned up.

##### Share on other sites

Thanks again Steve.

Quote:
 Did you call timeBeginPeriod(1); ? That increases the accuracy of timeGetTime() (Called from the constructor in my class).

No I didnt try that but will do tonight. But even then how much can it increase it by?? As I mentioned earlier I was getting about 33FPS, where I am expecting atleast over 100FPS. To me it just feels like I was doing the function wrong although i did take tips from many tutorials. Hence I dont think timeBeginPeriod(1) could fix it by that much (although I could be wrong and therefore will try it!)

Thanks for explaining about the deconstructor, it isnt something I had come across before but will also read up on it now that i know what it is.