sprite render is very slow

Started by
18 comments, last by Brain 8 years, 6 months ago
I change the code according to Fix Your Timestep, but it doesn't work at all. render is ok, but codes inside while(accumulator >= 16) are somehow skipped when running(i add a messagebox method in it and imessagebox window won't pop when I run the program. Then I try to run step by step and it did pop! I wonder what happened..)
static LARGE_INTEGER frequency, time1, time2;
	static double accumulator = 0.f;
	QueryPerformanceFrequency(&frequency);
	QueryPerformanceCounter(&time1);

	while (message.message != WM_QUIT)
	{

		if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&message);
			DispatchMessage(&message);
		}
		QueryPerformanceCounter(&time2);
		accumulator += (  (time2.QuadPart - time1.QuadPart)/frequency.QuadPart  );
		time1.QuadPart = time2.QuadPart;
		while (accumulator >= 16)
		{
			UpdateDXGame();
			accumulator -= 16;
		}

		RenderDXGame();


	}
Advertisement

Thats because your time calculation is wrong. You do an integer division, then save the result in a double.

The easy fix is to cast frequency.QuadPart to double to get a floating point division.

The better fix would be to accumulate the integer ticks, then change the comparison such that it compares with frequency.QuadPart/60.

If it helps, here is my loop:

    FrameTimer timer;

    const float delta = 1.0f / 60.0f;
    float accumulator = delta;

    while(msg.message != WM_QUIT)
    {
        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        float t = timer.elapsed();

        accumulator += t;

        while(accumulator >= delta)
        {
            app.update(delta); // delta used to update physics etc
            accumulator -= delta;
        }

        app.render(accumulator / delta); // blend parameter used to interpolate between previous and current positions for render
    }
And here is implementation of FrameTimer (accuracy is fine for me using float here):

class FrameTimer
{
public:
    FrameTimer();

    float elapsed();

private:
    LARGE_INTEGER frequency;
    LARGE_INTEGER lastCount;
};

FrameTimer::FrameTimer()
{
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&lastCount);
}

float FrameTimer::elapsed()
{
    LARGE_INTEGER count;
    QueryPerformanceCounter(&count);

    float time = static_cast<float>(count.QuadPart - lastCount.QuadPart)/static_cast<float>(frequency.QuadPart);

    lastCount = count;

    return time > 0.25f ? 0.25f : time;
}
I've used this approach in a whole bunch of games now, but if there is something amiss with my implementation of FYT, I'd be happy to hear about it.
@Aardvajk I use almost the same code with yours and it can only move very slowly at 60fps. I have to raise fps to 500 to speed it up. for example, the velocity is 0.75f per second at 500fps, and it perform good. But when at 60fps, I have to increase the speed to 8.f or even more, which produce a very unsmooth movement(the object seems to be jumping on the screen). Can I find some way to fix that?(my English is not so good...so I may say something in a wrong way.. )
static LARGE_INTEGER frequency, time1, time2;
	static double accumulator = 0.002;//why?
	QueryPerformanceFrequency(&frequency);
	QueryPerformanceCounter(&time1);

	while (message.message != WM_QUIT)
	{

		if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&message);
			DispatchMessage(&message);
		}
		QueryPerformanceCounter(&time2);
		frametime = (((double)time2.QuadPart - (double)time1.QuadPart)
			/ (double)frequency.QuadPart);
		accumulator += frametime;
		time1.QuadPart = time2.QuadPart;
		while (accumulator >= 0.002)
		{
			UpdateDXGame();
			accumulator -= 0.002;
			getfps();
		}

		RenderDXGame();


	}
and I remembered converting longlong to double

@Aardvajk I use almost the same code with yours and it can only move very slowly at 60fps. I have to raise fps to 500 to speed it up. for example, the velocity is 0.75f per second at 500fps, and it perform good. But when at 60fps, I have to increase the speed to 8.f or even more, which produce a very unsmooth movement(the object seems to be jumping on the screen).


Setting aside that your code is not very much like Aardvajk's in important details (for example you process only a single message per frame, quite unlike the original), I strongly suspect your speeds are not 'per second' as you think but 'per frame'. It's rather telling you decrease your target frame rate by a factor of approximately 8 and then have to increase your speed by a factor of approximately 8 to get similar results.

Edit: some pseudo code:



int   updatesPerSecond     = 60; 
float secondsPerUpdateStep = 1.0f / static_cast<float>(updatesPerSecond);
float mySpeedPerSecond     = 10.0f;

// you appear to be doing this every update:
myPosition = myPosition + mySpeedPerSecond;

// you should be doing this:
myPosition = myPosition + secondsPerUpdateStep * mySpeedPerSecond;

Yeah, I don't think your loop is quite like mine.

0.002 is a strange delta. That is 1 / 500, which is a tiny amount. My delta is 1 60th of a second, i.e. my physics is running at 60 fps. Your is saying you want to simulate at 500 frames per second, which would make your update absolutely tiny.

But its hard to follow exactly. BitMaster seems to have done a better job than me of understanding your code.
Also, when dealing with problems like this it can be extremely helpful to add units to your values (at least in your head, although Boost has a framework to have the compiler do it), like you do in physics.

A speed has (for example) the unit pixel/second. A position has the unit pixel. The assignment
myPosition = myPosition + mySpeedPerSecond;
then should immediately give you pause because you try to add something with the unit pixel and pixel/second together. You cannot do that.

Let's check do a unit check for
myPosition = myPosition + secondsPerUpdateStep * mySpeedPerSecond;
though:
[pixel] = [pixel] + [seconds] * [pixel/seconds] = [pixel] + [seconds * pixel / seconds] = [pixel] + [pixel]
That checks out.

As BitMaster said, make the PeekMessage check a while. Process all messages from a queue or you have extremely delayed window behaviour (dragging your window should lag like hell). It's not solving the main problem, but could be the cause of a few others.

while ( PeekMessage( &message, NULL, 0, 0, PM_REMOVE ) ) 
{ 
  TranslateMessage( &message ); 
  DispatchMessage( &message ); 
}

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

thanks for your advice! I've really learned a lot. though, my problem has not been solved. I'll try to fix it.
why can't I mark this topic as solved?...

We don't mark topics as solved on this forum, as although it may have solved the problem for you, it might not be the solution for someone else :) besides this isn't stack exchange :)

This topic is closed to new replies.

Advertisement