Sign in to follow this  

sprite render is very slow

This topic is 809 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 use ID3DXSprite interface to make this game. At first I put all properties into one class which is not a good style. Then I try to use component - contain many pointers to different components in entity class. But problems come. The rendering becomes awful! when runing at 60 fps, you can see the jump between frames... I upload the code. if someone have spare time please give it a look. I've changed the code many times but this problem remains.

the code is not so complex. class scene create entities and update them. ticktimer is a timer class. gamestart, gamerun and gameend is called at proper place. that's all.

the file I upload is more smooth because I raise the framerate to 120fps. but when use 60fps, it will be horrible.. you can change it in main.cpp - it is in messageloop.

er..and any improve to this code is welcome..but be sure to send me a copysmile.png

Edited by sunsflower

Share this post


Link to post
Share on other sites

Without looking at the code i can give one piece of advice.

 

You should be thinking of migrating away from D3DX functions as they have been obsolete for many years.

 

If you are using anything newer than directx 9 (which most people are by now) there are many better replacements. In fact, on windows 10, D3DX won't work at all unless you install it as a seperate DLL/dependency with your game. Time is ticking and leaving you behind! :)

Share this post


Link to post
Share on other sites


..I raise the framerate to 120fps. but when use 60fps, it will be horrible..

 

If you're doing frame limiting could you post that section of code?

It can produce stuttering if you limit fps to 60 (in my engine it did), maybe using something like 62 fps will help?

Have you tried using vsync?

Share this post


Link to post
Share on other sites

I've looked at it.

It's not sprite rendering slow. It's your simulation not depending on actual time.

You're waiting when time for rendering will come, then perform one fixed size step.

But that won't work on low fps, because actual time step and your desired 4ms step will differ drastically.

Just compare 1sec/60frames ~=16ms. You're doing 4 times less steps than you expect. Sure it will move slower.

Instead you should check exact amount of ms passed, and perform simulation based on that info.

Edited by vstrakh

Share this post


Link to post
Share on other sites
@MarkS I'm sorry but I have no intention that someone else should fix the code for me. I just don't know which part is wrong, so I have to upload the whole project...I think I will choose some part for now. thanks for your advice;

@vstrakh thanks for your time! I've always had a question about the timer. and I have found an article discussing this topic. Maybe I am going to fix that!

as for using directx..,I have to say that I bought many books and they are all about dx9, so naturally I chose it

Share this post


Link to post
Share on other sites

If you have problems with your applications being slow, you should consider learning about/looking into profilers.

They can help show you which sections of your code is running slowly. Even if you don't know a solution to the slow part yourself, you can at least narrow it down and be able to post a lot more specific questions, which is likely to give you better replies and solutions.

Share this post


Link to post
Share on other sites
@vinterberg this is messageloop. tmr.tickprecise(4)will return true every 250ms(I've tested it in a separate project). but I only got 120fps.
	while (message.message != WM_QUIT)
	{
		if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&message);
			DispatchMessage(&message);
		}
		if (tmr.timeprecise(4))
		{
			UpdateDXGame();
		}
	}
and this is the entity class
class entity
{
public:
	entity();
	~entity();

	void make_transform(lpvector2 origin, float rotation);
	void make_movement(lpvector2 velocity, float angularvelocity);
	void make_graphics(lpvector2 topleft, RECT* SourceRect);
	void make_input(int iflag);
	void make_collision(vector2* vertice, int vercount);
	void make_fire();

	void messagepump(lptexture texture, entity** miss, int* iterator);

	transform* _transform;
	movement* _movement;
	graphics* _graphics;
	input* _input;
	collision* _collision;
	fire* _fire;
};

this is the funciton to be called every frame. implecolli calculate collisions and it works quite good.
void scene::update()
{
	for (int i = 0; i < _iterator; i++)
	{
		_entities[i]->messagepump(texture, &_missilemanage[_iteratormiss], &_iteratormiss);

		if (_entities[i]->_collision->detector == true)
		{
			for (int j = 0; j < _iterator; j++)
			{
				if (j == i)
					continue;
				vector2 mtd;
				if (impleColli(_entities[i]->_collision->_vertrans, _entities[i]->_collision->_iterator,
					&_entities[i]->_movement->_velc, &_entities[i]->_transform->_ori,
					_entities[j]->_collision->_vertrans, _entities[j]->_collision->_iterator,
					&_entities[j]->_movement->_velc, &_entities[j]->_transform->_ori,
					&mtd))
				{
					if(mtd != NULL)
						_entities[i]->_transform->_ori += mtd;
				}
			}
		}
	}
	ostringstream os; string s;
	os << _iteratormiss; s = os.str();
	SetWindowText(GetActiveWindow(), s.c_str());
	for (int i = 0; i < _iteratormiss; i++)
	{
		_missilemanage[i]->messagepump(texture, &_missilemanage[_iteratormiss], &_iteratormiss);
	}
}

here is messagepump. it handles the communication between components
void entity::messagepump(lptexture texture, entity** miss, int* iterator)
{
	//movement
	if (_transform != NULL && _movement != NULL)
	{
		_transform->_ori += _movement->_velc;
		_transform->_rot += _movement->_angvelc;
	}
	//input
	if (_input != NULL && _movement != NULL && _transform != NULL)
	{
		int imove, irotate, addi;
		_input->update(&imove, &irotate, &addi);
		float tx = 0;
		float ty = 0;
		float rotR = 0;
		vector2 Vtrans = D3DXVECTOR2(0, 0);
		rotR = 3.14159265 * 2 * _transform->_rot / 360;
		tx = _movement->max_vel * sin(rotR);
		ty = -_movement->max_vel * cos(rotR);
		Vtrans = vector2(tx, ty);
		switch (imove)
		{
		case 1:
			_movement->_velc = Vtrans;
			break;

		case 2:
			_movement->_velc = -Vtrans;
			break;

		case 3:
			_movement->_velc = vector2(0, 0);
			break;
		}
		switch(irotate)
		{
		case 2:
			_movement->_angvelc = _movement->max_angv;
			break;

		case 1:
			_movement->_angvelc = -_movement->max_angv;
			break;

		case 3:
			_movement->_angvelc = 0;
			break;
		}
		if (addi == 1)
		{
			_fire->makefire(miss, &_collision->springarm, _transform->_rot);
			*iterator += 1;
		}
	}
	//graphics
	if (_graphics != NULL)
	{
		float rotR = 3.14159265f * 2.f / 360.f * _transform->_rot;
		D3DXMATRIX mat;
		D3DXMatrixTransformation2D(&mat, NULL, 0, NULL, &(_graphics->_topleft*-1), rotR, &_transform->_ori);
		spriteobj1->SetTransform(&mat);
		spriteobj1->Draw(texture, &_graphics->_srcrect, NULL, NULL, D3DCOLOR_XRGB(255, 255, 255));
	}
	//collision
	if (_collision != NULL)
	{
		_collision->update(&_transform->_rot, &_transform->_ori);
	}
}

Share this post


Link to post
Share on other sites


tmr.tickprecise(4)

That line supposed to return true when 4 ms elapsed since previous update.

But your simulation updates is coupled with rendering. Means with VSync at 60fps you will get next check in 16ms.

After 16ms that check will again report true, since 16ms>=4ms, but only one fixed size step of simulation will be performed, while you need 4 steps to cover those 16ms.

Share this post


Link to post
Share on other sites
&nbsp;

tmr.tickprecise(4)

That line supposed to return true when 4 ms elapsed since previous update.
But your simulation updates is coupled with rendering. Means with VSync at 60fps you will get next check in 16ms.
After 16ms that check will again report true, since 16ms&gt;=4ms, but only one fixed size step of simulation will be performed, while you need 4 steps to cover those 16ms.
&nbsp;

I see...but, how can I fix it? is there any articles about it?

Share this post


Link to post
Share on other sites
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();


	}

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
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. Edited by Aardvajk

Share this post


Link to post
Share on other sites
@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

Share this post


Link to post
Share on other sites

@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;

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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. Edited by BitMaster

Share this post


Link to post
Share on other sites

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 ); 
}

Share this post


Link to post
Share on other sites

This topic is 809 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this