views:

58

answers:

3

Hello!

Does someone know a fast way to invoke shader processing via DirectX?

Right now I'm setting shaders using D3DXCreateEffectFromFile calls, which create shaders in runtime (once per each shader) from *.fx files.

Rendering part for every object (every patch in my case - see further) then means something like:

// --------------------
// Preprocessing
effect->Begin();
effect->BeginPass(0);
effect->SetMatrix (or Vector or whatever - internal shader parameters) (...)
effect->CommitChanges();

// --------------------
// Geometry rendering

// Pass the geometry to render
// ...

// --------------------
// Postprocessing

// End 'effect' passes
effect->EndPass();
effect->End();

This is okay, but the profiler shows weird things - preprocessing (see code) takes about 60% of time (I'm rendering terrain object of 256 patches where every patch contains about 10k vertices).

Actual geometry rendering takes ~35% and postprocessing - 5% of total rendering time.

This seems pretty strange to me and I guess that D3DXEffect interface may not be the best solution for this sort of things.

I've got 2 questions:

1. Do I need to implement my own shader controller / wrapper (probably, low-level) and where should I start from?

2. Would compiling shaders help to somehow improve parameter setting performance?

Maybe somebody knows how to solve this kind of problem / some implemented shader interface or could give some advices about how is this kind of problem solved in modern game engines.

Thank you.

+2  A: 

Are you using a DirectX profiler or just timing your client code? Profiling DirectX API calls using timers in the client code is generally not that effective because it's not necessarily synchronously processing your state updates/draw calls as you make them. There's a lot of optimization that goes on behind the scenes. Here is an article about this for DX9 but I'm sure this hasn't changed for later versions:

http://msdn.microsoft.com/en-us/library/bb172234(VS.85).aspx

bshields
+2  A: 
  1. I've used effects before in DirectX and the system generally works fine. It provides some nice features that might be a pain to implement yourself at a lower-level, so I would stick with it for the moment.

    As bshields suggested, your timing information might be inaccurate. It sounds likely that the drawing actually is taking the most time, compared.

  2. The shader is compiled when it's loaded. Precompiling will save you a half-second of startup time, but so long as the shader doesn't change during runtime, you won't see any actual speed increase. Precompiling is also kind of a pain, if you're still testing a shader. You can do it with the final copy, but unless you have a lot of shaders, you won't get much benefit while loading them.

    If you're creating the shaders every frame or every time your geometry is rendered, that's probably the issue. Unless the shader itself (not parameters) changes every frame, you should create the effect once and reuse that.

    I don't remember where SetParameter calls go, but you may want to check the docs to make sure your SetMatrix is in the right spot. Setting parameters after the pass has started won't help anything, certainly not speed. Make sure that's set up correctly. Also, set parameters as rarely as possible, there is some slight overhead involved. Per-frame sets will give you a notable slow-down, if you have too many.

All in all, the effects system does work fine in most cases and you shouldn't be seeing what you are. Make sure your profiling is correct, your shader is valid and optimized, and your calls are in the right places.

peachykeen
+3  A: 

Actual geometry rendering takes ~35% and postprocessing - 5% of total rendering time

If you want to profile shader performance you need to use NVPerfHud or something similar. Using CPU profiler and measuring ticks is not going to help you - rendering is often asynchronous.

Do I need to implement my own shader controller / wrapper (probably, low-level)

Using your own shader wrapper isn't a bad idea - I never liked ID3DXEffect anyway. With your own wrapper you'll have a total control of resources and program behavior. Whether you need it or not is for you to decide. With ID3DXEffect you won't have a warranty that implementation is as fast as it could be - it could be wasting cpu cycles doing something you don't really need. D3DX library contains few classes that are useful, but aren't guaranteed to be efficient (ID3DXEffect, ID3DXMesh, All animation-related and skin-related functions, etc).

and where should I start from?

D3DXAssembleShader, IDirect3DDevice9::CreateVertexShader, IDirect3DDevice9::CreatePixelShader on DirectX 9, D3D10CompileShader on DirectX 10. Also download DirectX SDK and read shader documentation/tutorials.

Would compiling shaders help to somehow improve parameter setting performance?

Shaders are automatically compiled when you load them. You could compiling try with different optimization settings, but don't expect miracles.

SigTerm
+1 for NVPerfHud (or PIX). Standard CPU profilers are generally not useful in measuring rendering performance.
Alan