Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Given: Selfmade 3D engine based on DirectX9 written in C++

Task: While render loop runs load additional textures in a background thread

Current Implementation: - Create device with D3DCREATE_MULTITHREADED - Ensure that loaded content is used by render thread only after loading finished

Problem: Loading performance is very poor because DirectX calls block most of the time

More specific: Seems that all DirectX calls are blocked for the whole duration the "Present" call waits for the vsync. That is in my case 99% of the time -> Loading thread has very few opportunities to run its DirectX calls.

Absurd observation (on first sight): Loading performance gets much better when I deactivate vsync and the render tread runs full speed. That is because the relative portion of time the render thread is inside a DirectX function is lower.

Possible but problematic solution: Do not let "Present" wait for the vsync, instead do a "while" loop with a non waiting "Present" and as long as it returns "D3DERR_WASSTILLDRAWING" do a short "Sleep".

But I do not like that solution: First I am afraid it degrades maximum performance of the render loop as the resolution of "Sleep" time is limited. Second problem is that I am using multihead rendering with several monitors and I am afraid taking away full control about vsyncing from DirectX might introduce effects like tearing on some monitors or something like that.

First question: Why? I would bet my life that blocking whole DirectX while waiting for vsync is not neccessary especially while I am only using separated resources in the loading thread. But, well, it is like Microsoft implemented it and I am afraid I have to deal with it.

Second question: Better ideas, anyone? Does anybody have a better solution for this, or enough experience to tell me that my possible solution is not problematic at all or can think of a better way.

I know that Microsoft worked on these things with DirectX11 but porting the whole thing now is not an option, it would take too much time.

Thanks for your time, Ole

share|improve this question
    
On which thread are you creating the Textures? Which functions are blocking on the loader thread? What's the interval between present calls? –  SmoCoder Jun 24 '13 at 14:46
    
I am creating the textures with the loader thread, as that may take a substancial amount of time and I want to do it in background. The blocking functions are any direct3D call - thats the problem. Direct3D does not differenciate resources it simply blocks globally. The interval between present calls? Well either a vsync or immediate - depending if vsync is on or not. –  Ole Dittmann Jul 8 '13 at 11:41
    
Did you try running the ContentStreaming sample that comes with the DirectX SDK? Does it exhibit the same stalls? –  SmoCoder Jul 17 '13 at 11:06
add comment

3 Answers

Preventing present waiting for a vsync is basically all you can do if you want to do other things with that thread or D3D9 in general.

However what you could do is load your file from disk on another thread (or asynchronously with say overlapped IO) then create your texture from that on the main thread. If your using a compressed image format that will need to be decompressed (e.g. PNG) you could also do the decoding on another thread.

If your not letting D3D9 block and just doing D3D calls on the main thread I believe that is about as good as you can get. I have never found the CPU thread to be completely limiting at that point, but rather the GPU or data transfers cant keep up.

share|improve this answer
    
Yes, unfortunately that is is a solution which means a huge effort. First I cant use the integrated D3DX functions for texture loading any more and will have to reproduce all that loading and filtering functionality. Second I will have to split the whole loading procedure beetween multiple threads while taking care that the rendering thread only does as much as it can while keeping full fps. And yes youre right, its not the cpu time which is the limiting factor, but the GPU data transfers. But texture loading implies data transfer :-( –  Ole Dittmann Sep 30 '13 at 20:37
    
@OleDittmann: CPU to GPU data transfers are extremely fast. On modern GPUs, you can easily transfer data at more than 10GB/s. What usually makes loading times long is disk waiting. On HDDs, you very commonly get millisecond delays for non-sequential data. Will's recommendation is correct: file loading and decompression can be done asynchronously. Many async I/O libraries let you poll for completion, allowing you to keep your program single threaded (async is not the same as multi-threaded) –  Panda Pajama Oct 1 '13 at 5:44
add comment
up vote 0 down vote accepted

Came up with a solution on my own. Its not beautiful, but its simple and works.

Just do a "Sleep(8)" after each "Present" in the rendering thread.

Sounds weird at first sight and as far as 8 miliseconds is about half a frame you might think that I am limiting the maximum performance of my engine to 50%. But in fact only the GPU feeding rendering CPU thread sleeps, not the GPU itself. Testing shows no degradation in maximum performance, even If I set the maximimum buffered frames to only one to achieve better responsiveness to input in terms of delay. There is always at least one buffer left - the backbuffer.

Of course I have to outsource processor intensive calculations to other threads now because the rendering thread itself should not load the CPU, but that is good practice anyway and was already done.

But there is some uncertainty left:

  1. You depend on a buffering and asychronous execution model you do not really know anything about, and which may work completely different under other circumstances.
  2. The resolution of "Sleep" is somewhat undefined, so if you say 8 miliseconds you never know how long that "Sleep" will really be.

But both points haven proven to be negligible after extensive testing.

So as long as I do not port to a higher DirectX version I will go with that because:

  1. Its very simple - all my current code can stay as it is.
  2. I may use DirectX calls across my loading code now as I like. And the "Sleep" ensures they are not blocked for too long.
  3. It still uses a perfectly "normal" Present call so I do not have to be afraid of tearing effects or some other unwanted behaviour in cases of complicated monitor configurations.

Only thing I am not sure about: Place the "Sleep" before or after The "Present"? Or a totally different place? While testing I could not notice a difference.

share|improve this answer
add comment

Placing sleep after the Present call is usually the best solution, so you get least ammount of delay between all your D3D calls in the frame that you are about to present.

Sleep at start or end of the render thread. Doesnt matter where, for obvious reasons.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.