Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

Direct3D 9 Optimization Problem

Started by kartracer12 Jun 21, 2010 at 8:23 PM 17 replies 4.8k views
Original Post
kartracer12
kartracer12
In short, i have this model i created, and when i draw it to the screen, my FPS goes to about 28-32, but when i load the model in the DirectX viewer, it can draw it at 58-60 FPS. Also, toymaker.info's bounding box collision demo can load it and run it at 60 FPS as well. My loop that i'm calculating the FPS of looks kinda like this:

d3ddevice->Clear(0, NULL,  D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);d3ddevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);d3ddevice->BeginScene();//Render Modeld3ddevice->EndScene();d3ddevice->Present(NULL, NULL, NULL, NULL);


The rendering of the model is a class function that looks like this:

void Model::draw(){        //View        D3DXMATRIX matView;	D3DXMatrixIdentity(&matView);	D3DXMatrixLookAtLH(&matView, &D3DXVECTOR3(0,2,-10),                                     &D3DXVECTOR3(0,0,0),                                     &D3DXVECTOR3(0,1,0));	m_app->m_d3ddev->SetTransform(D3DTS_VIEW, &matView);        //Transform	D3DXMATRIX matScale, matRotate, matTranslate, matWorld;	D3DXMatrixIdentity(&matScale);	D3DXMatrixIdentity(&matRotate);	D3DXMatrixIdentity(&matTranslate);	D3DXMatrixIdentity(&matWorld);	D3DXMatrixScaling(&matScale, 1, 1, 1);	D3DXMatrixRotationYawPitchRoll(&matRotate, 0, 0, 0));	D3DXMatrixTranslation(&matTranslate, 0, 0, 0);	matWorld = matScale*matRotate*matTranslate;	this->m_app->m_d3ddev->SetTransform(D3DTS_WORLD, &matWorld);        //Draw	for(DWORD i = 0; i < this->m_numMaterials; i++){		this->m_app->m_d3ddev->SetMaterial(&this->m_material);		if(this->m_texture != NULL){		     this->m_app->m_d3ddev->SetTexture(0, this->m_texture);		}		this->m_mesh->DrawSubset(i);	}}


I'm using Microsoft's visual c++ 2010 compiler with the June 2010 DirectX SDK. I hope i have provided enough code. I'm 99% sure it is somewhere in this. If you need more of the code i would be glad to provide it. This code is widely influenced by the directxtutorial.com guys, so if it looks familiar, thats why. Any help would be much appreciated.
MJP
MJP
How are you measuring your fps?
kartracer12
kartracer12
For the FPS, i have a function to initialize the FPS, a function to return the time, a function to reset the time, and a Function to print the FPS. They look like this:

//Global Variablesunsigned __int64 g_currentTick;unsigned __int64 g_ticksPerSecond;double g_startTime;int g_frames;double g_fps;//Initializevoid initFPS(){	QueryPerformanceFrequency((LARGE_INTEGER *)&g_ticksPerSecond);	QueryPerformanceCounter((LARGE_INTEGER*)&g_currentTick);	g_startTime = (double)(g_currentTick/g_ticksPerSecond);	g_frames = 0;	g_fps = -1;}//Get timedouble currentTime(){	QueryPerformanceCounter((LARGE_INTEGER*)&g_currentTick);	return ((double)g_currentTick/(double)g_ticksPerSecond) - g_startTime;}//Reset Timevoid resetTime(){	g_startTime = (double)g_currentTick/(double)g_ticksPerSecond;}//Printdouble printFPS(){	g_frames++;	if(currentTime() > .5){		g_fps = g_frames / currentTime();		resetTime();		g_frames = 0;	}	return g_fps;}


the initFPS() needs to be called once at the beginning of the program, and the printFPS() needs to be called once every time the loop cycles through.
TomKQT
TomKQT
Do you use the "release" compile option in VS? Do you use the retail version of DX runtimes?

If both "yes", could we see your main application loop?
kartracer12
kartracer12
Sorry for the ignorance, but i'm not quite sure what you mean:

1.) If the release option is the solution configuration (ie. debug or release) then the answer is the same results. Both have slow fps.

2.) I have no idea what the retail version of DX runtimes is. I got my directx sdk from the MSDN website and it is the June2010 version. I don't know if that answers it, but hopefully it does.
Noxis
Noxis
I dont think this is due to the way you measure your FPS !

The DirectX SDK offers several methods to optimize your mesh. This can seriously improve your mesh rendering performances.

Check ID3DXMesh::OptimizeInplace or ID3DXMesh::Optimize and let us know !


Noxis -
Evil Steve
Evil Steve
Quote:
Original post by kartracer12
2.) I have no idea what the retail version of DX runtimes is. I got my directx sdk from the MSDN website and it is the June2010 version. I don't know if that answers it, but hopefully it does.
Debug Runtimes. You want to select "Use Retail Version of Direct3D 9" though.

1. I'd measure both applications performance using FRAPS - that'll tell you if it's a problem with your FPS calculation (Or if the other app is wrong / lying [smile]).

2. You shouldn't be clearing twice, use one Clear() call, with what you want to clear OR'd together:
d3ddevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);

3. Are you rendering windowed or fullscreen? If windowed, are you calling AdjustWindowRect() to make sure your window is the correct size? If not, D3D will be having to stretch / shrink the backbuffer to fit the window, which could reduce performance.

4. Are you rendering with V-sync enabled or disabled (What's your D3DPRESENT_PARAMETERS.PresentationInterval set to)?
kartracer12
kartracer12
@Evil Steve:
First, i checked and i was using retail

1.)I got the same FPS with FRAPS, both on mine and the other applications so no one is lying.

2.)I changed it but there was no change in the FPS, but thank you for the tip.

3.)I was rendering windowed and was NOT calling AdjustWindowRect(), but i got slow FPS in full screen. I'll look into this function more and test it out but i don't think it alone is the trouble.

4.)My D3DPRESENT_PARAMETERS.PresentationInterval was not set therefore being defaulted to 0, which i believe is not v_sync. When i changed it to 1, the FPS were the same, which seems correct because i believe the v_sync would cap the FPS to 60 or so, but i can't get there.

@Noxis:
I will definitely be looking into that. I see there is a direct3d sample on that too. My only concern is the samples use DXUT and i have never used them so it might take me a while as i will have to jump between files to try and understand what is really going on.
Noxis
Noxis
That's a good idea to use fraps in order to check your framerate.

Do you experience the same issue with other models (like those from the DirectX SDK) ?

Noxis -
kartracer12
kartracer12
So i just loaded tiny.x from the DirectX tutorials and it prints at 60 FPS. But that doesn't say much. Other programs are able to print my model at 60fps or more, but i can only get 30fps or so. Also, something interesting i found is that the directx samples are sometimes showing more then 300 fps when my loop with no drawing is getting about 60fps. So that indicates that the drawing might not be the only thing holding the program back.

The test with tiny only suggests that i have low frame rate issues with higher quality models, which is fine but how can other programs be running it so fast. When i loaded my model in the optimizing mesh sample that came with directx, it was able to print it at over 250fps. There is clearly some discontinuity somewhere.

***As a side note, these are static meshes, not animated meshes. I don't know if that makes a difference, i just realized i hadn't stated that before.
TomKQT
TomKQT
Quote:
Original post by kartracer12
4.)My D3DPRESENT_PARAMETERS.PresentationInterval was not set therefore being defaulted to 0, which i believe is not v_sync. When i changed it to 1, the FPS were the same, which seems correct because i believe the v_sync would cap the FPS to 60 or so, but i can't get there.


This seems to be the problem ;)

0 is D3DPRESENT_INTERVAL_DEFAULT, which by the documentation is, quoting:
This is nearly equivalent to D3DPRESENT_INTERVAL_ONE.

1 is D3DPRESENT_INTERVAL_ONE.
Which means vsync ON.

You must set D3DPRESENT_INTERVAL_IMMEDIATE, don't leave it to 0 and don't set 1 (use the makro D3DPRESENT_INTERVAL_IMMEDIATE).

Quote:
Original post by kartracer12
So i just loaded tiny.x from the DirectX tutorials and it prints at 60 FPS. But that doesn't say much. Other programs are able to print my model at 60fps or more, but i can only get 30fps or so. Also, something interesting i found is that the directx samples are sometimes showing more then 300 fps when my loop with no drawing is getting about 60fps. So that indicates that the drawing might not be the only thing holding the program back.


This clearly points to vSync on, because you are capped at 60 FPS and when you add something complicated to render, your FPS drops to a half (30). When vsync is on and the system is not able to maintain the sync framerate, it drops to a half.
So you can have 60 or 30 or 15 etc.
Adam_42
Adam_42
Some more things to check:

- Are you using hardware vertex processing (D3DCREATE_HARDWARE_VERTEXPROCESSING)?

- What size, format and MSAA are the back buffer and z-buffer set to?

- Do you render anything other than that model?
kartracer12
kartracer12
And the winner is......@Adam_42. I hard software vertex processing. I changed it to hardware and got up to 150 fps and then to mixed and got 300. Just to tie up loose ends:

@Adam_42
1.) was using software, i have the best results with mixed.
2.) i think by format you mean the AutoDepthStencilFormat which is set to D3DFMT_D16, and i'm afraid i don't know what MSAA is.
3.) ...Nope

@Tom KQT: 100% correct. Now that i have fixed this issue i can see that if i leave it blank, set it to zero, or set it to one, it gets caped at 60, but if i set it to D3DPRESENT_INTERVAL_IMMEDIATE it goes to 300 or more, so thank you because that could have also caused alarm later.

Just a few last question on the stuff that i now realize i know very little about.
1.) Should i use hardware or mixed vertex processing. Clearly mixed gets me a much better performance, but is there a hidden downside that i don't know about?
2.) Is it better to v_sync or not. Likewise, i get a much better performance out of setting the PresentationInterval to D3DPRESENT_INTERVAL_IMMEDIATE but is there a reason to v_sync that i do not know about.

Thank you so much to everyone who helped. I can't express through text how much i appreciate how fast you all were and i'm really thankful to all of your input.
TomKQT
TomKQT
About VSync: http://en.wikipedia.org/wiki/Vsync

In short, with VSync off you can see "tearing", especially when something in the scene is moving fast. Reason is that you send new frames to the monitor faster than the monitor is displaying them and this may end in top half of the screen containing one frame and the bottom half the next frame - and when their content differs significantly (because of the fast movement), it may be visible (this is the tearing). In fact it may be even more extreme, if your framerate is much bigger than the vsync frequency, you can have pieces of multiple frames on one screen.

VSync on on the other side can bring problems if the system is not fast enough to render those 60 FPS. If your hardware is good enough only for 55 FPS, with VSync off you will see 55 FPS but with VSync on you will see 30 FPS (half of 60).

Whenever there is a VSync related discussion on some gaming forum, it's quite heated with no clear winner :) I personaly don't mind tearing so I'm turning VSync on in any game.

For you application, you may decide yourself. I would suggest either making it OFF or letting the user decide.
kartracer12
kartracer12
Is there anyway for me to disable vsync if the fps is too close to 60. something like if fps > 75 then enable vsync. Because it seems vsync doesn't do any negative effects until it gets close to 60.
21st Century Moose
21st Century Moose
A vsync change requires a present parameters change, which means a device reset; not something you want to be doing regularly at runtime!

Another possible approach would be to run with vsync off but artifically cap your performance at 60 FPS (or whatever the monitor's refresh rate is) by checking time passed each frame and if it's not more than 1/60 (or 1/72, or whatever) just skip rendering the frame.

End users might not be so happy if you did this however; I've found in the past that if someone has bought a very expensive 3D card and they only get 60 FPS (as opposed to 17,000,000,000) they will be unhappy with you. Can't win!
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
TomKQT
TomKQT
Valve games (Source engine - HL2, TF2 etc.) allows the player to enable/disable VSync and also to set FPS limit to any value. This way everybody is happy :D
kartracer12
kartracer12
Alright, that seems to makes sense. Thank you very much for the information.
TomKQT
TomKQT
You don't have to go the most complex way. IMHO giving the ability to choose between vsync on and off is absolutely enough. After all, many big commercial games don't have even this choice!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.