[DX9, C++] Lag issue when drawing models for the first frame

Started by
8 comments, last by ET3D 13 years, 8 months ago
Ok let me try to explain this odd problem as much and as simply as possible, because it does not seem to be a simple problem.

The project I am working on is a basic DX9 game for school. It's our Junior level applied development project. We are doing nothing insanely fancy or out of the ordinary so keep that in mind as I explain the issue.

The summary of the problem is that when I draw models for the first time during the run-time of the game.. there is a small lag issue. After a particular model has been drawn the first time, drawing it again there is 0 lag.

Let me explain the basic setup. I am not loading the .X files when I spawn them in the game. They are loaded at the beginning and stored in memory. Whenever I spawn an entity in the game, it's just accepting a pointer to already loaded model data and simply just draws what's in memory.

I made a basic profiler using the difference of the GetTickCount() method before and after certain areas to try and find the actual spike.

I found the spike directly around the calls:

gd3dDevice->EndScene();
gd3dDevice->Present(0, 0, 0, 0);

The spike does not come from anywhere that handles setting up drawing the objects to the back buffer.. it's only when I go to present that buffer that the issue pops up.

I am using D3DPOOL_MANAGED for my loading on the areas where that's set.

Also, this problem happens on multiple computers of all different types of video cards, processors, driver versions etc. It's not just my computer or my drivers or my gfx card.

This problem also just spawned recently. But I have 0 idea what might have been changed to cause this, I have gone back to older versions I have saved, and the problem doesn't exists, but where it counts that I can find, I don't see anything in the core drawing that would have caused it.

I will post any code that is requested. I have 0 idea where to even consider looking so I have no idea what I would need to post for you guys to look at.

I just know these key things.

The problem lies when presenting the back buffer
The problem does not happen when drawing to the shader
The problem only happens when a model is drawn for the first time during runtime
The problem is gone for that particular model once it has been drawn once

I have also tried to draw the mesh data's subset during the load time for each of those models that cause the issue to see if drawing it once would eliminate the issue like that, and it does not.

If you got any questions.. want to see any part of my code.. or have an idea you want me to try let me know!

Thanks,
GFT

*Update*
I went through using the DirectX Control panel to debug possible errors and warnings that were popping up. I had some issues that I cleared up with it, however when it comes to the lag spike issue itself, there are no warnings or errors that are popping up when it happens.

[Edited by - GhostfromTexas on August 16, 2010 11:51:30 PM]
Advertisement
*Update*
I went through using the DirectX Control panel to debug possible errors and warnings that were popping up. I had some issues that I cleared up with it, however when it comes to the lag spike issue itself, there are no warnings or errors that are popping up when it happens.
The bottleneck isn't really in EndScene/Present. It's just that that point is waiting for drawing to complete. The draw calls don't wait for drawing to be finished, which is why you don't see any problem there.

A better way to profile would be through PIX or a card specific profiler, such as NVIDIA's PerfHUD or AMD's GPU PerfStudio.

As for the problem, one of the possibilities is that you're using big textures, and they're being loaded into the graphics card when needed, which is managed by the Direct3D runtime (and because they're placed in the managed pool). You can try to call "PreLoad()" on the texture and see if that helps.
Thanks for your response. I have to admit when I first read your possibility for the solution I got kind of excited because that made 100% total sense for what I was doing... My models have around 1mb textures each for them and the models have quite the UV layout on them for these textures.

I did call PreLoad() on all the textures for the models after I loaded them, but alas the problem didn't correct itself.

best guess I've had so far.. so again thanks for the response. Got any other ideas?
Are you using Windows Vista or 7 (with a WDDM driver) and does this happen when you run it in the debugger?

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Quote:Original post by mhagain
Are you using Windows Vista or 7 (with a WDDM driver) and does this happen when you run it in the debugger?


This problem is happening across the board on several systems.. ranging from Windows XP 32bit to Windows 7 64bit.. and pretty much everything in between. So it's not just Windows Vista or Windows 7 Related


@ ET3D:

I decided to take what you said a step further, and I simply commented out the call where I set the texture to a my shader handle when I updated the models. Obviously now my models are black and not textured, but the problem is now gone when I do that. Is 1mb too large for a texture? Could it be something in my shader? Is there like an allocated amount of video memory that I might be filling up when I do this?
It's possible you're running out of video memory. Perfhud can tell you for sure.

As a simple test you could try using D3DXCreateTextureFromFileEx() to load your textures and pass D3DFMT_DXT5 as the format of your textures. That will cut their size in video ram down significantly at the cost of extra load time. Ideally you'd want to use D3DFMT_DXT1 for textures with no alpha channel, and also convert them offline with the texture tool that comes with the SDK into .dds files.

Even if you aren't running out of memory, the smaller textures will be quicker to upload to video ram which could help.
Quote:Original post by Adam_42
It's possible you're running out of video memory. Perfhud can tell you for sure.

As a simple test you could try using D3DXCreateTextureFromFileEx() to load your textures and pass D3DFMT_DXT5 as the format of your textures. That will cut their size in video ram down significantly at the cost of extra load time. Ideally you'd want to use D3DFMT_DXT1 for textures with no alpha channel, and also convert them offline with the texture tool that comes with the SDK into .dds files.

Even if you aren't running out of memory, the smaller textures will be quicker to upload to video ram which could help.


Ok i converted over to use this function and low and behold, the lag problem is gone! I do notice, however, it does take longer to load up initially (about an extra 5-6 seconds) but it's worth the improvement that I am seeing in game...

could you possibly explain to me exactly what the format does, and what are the other similar formats like D3DFMT_DXT3, D3DFMT_DXT4, etc?
You can get a detailed explanation at http://en.wikipedia.org/wiki/S3_Texture_Compression

Essentially DXT5 takes a 4x4 block of pixels and encodes them into 16 bytes which effectively gives you 1 byte per pixel. DXT1 takes a 4x4 block of pixels and encodes them into 8 bytes which effectively gives you 4 bits per pixel. However it doesn't encode the alpha channel.

To fix the load time issue, convert your textures to the appropriate texture format and save them as .dds files using the texture tool that comes with the DirectX SDK. They will then load quicker than the uncompressed textures because they are smaller files.
1MB is not too large for a texture. If you're too many such textures then you might saturate the card's memory, but cards these days have at least 512MB, so you can have a couple of hundred such textures and it'd still work.

Regarding the compressed textures, I can't say if they're actually solving the problem or just reducing the lag enough to be unnoticeable, because they're significantly smaller. Not that it's bad to use the compressed formats. If they provide enough quality then they're a good solution.

BTW, if it's just PreLoad not working that well, then the obvious solution would be to load all textures and immediately draw something with them (a single triangle). But that's a hack.

This topic is closed to new replies.

Advertisement