Performance problem with directX

E96bdd9352bdf5f0e17646cd08c83b0e
0
yakul 101 Feb 26, 2008 at 09:37

Hello, I have written a software which uses a projector as one of the output displays.
When I run the program on debug version it runs at about 220 FPS, when I run it on retail it runs between 30 and 60 FPS.
I suspect that for some kind of a reason the retail files are not up to date.
The date of d3d9d.dll is 7/2/2007, the date of d3d9.dll is 8/4/2004.
I have installed directx of november 2007 and the dates of the two mention dlls didn’t change at all.
What should be the dates of these dlls?
What seem to be the problem?
Thank you.

10 Replies

Please log in or register to post a reply.

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 Feb 26, 2008 at 10:01

If you turn up the debug level to maximum with the debug driver does it report any errors? Likelihood is you are doing something wrong and debug fails gracefully and doesn’t hurt ya but Retail is suffering issues as a result of its lack of error checking …

E96bdd9352bdf5f0e17646cd08c83b0e
0
yakul 101 Feb 26, 2008 at 14:46

It doesn’t report any error, it just says redundant setrenderstate.
The thing is the projcetor is displaying in another thread, I set the D3DCREATE_MULTITHREADED in the parameters.
If I leave the bare minimum to present the projector back buffer, then on retail the performance is 12FPS and on debug its 200 FPS.
As if the present takes a lot of cpu to retail but not too much for debug.
How can I make sure that I am actually using retail and not debug and vise versa?
Perhaps it is not that the projector thread eats a lot of cpu because even if I leave it with a blank while(1){}, the performance is barely affected when running on debug directX.
What am I doing wrong?
Edit: Maybe I am doing wrong something with the window message?
I have a window to display on the screen and another window for the projector.
Yet the PeekMessage loop is only at the main thread?
Some code:

void 
DXProjector::ProjectPattern (int i)
{
//  Error::Assert (i<this->Pattern.Size(), "Pattern index greater then stock");
/*  Error::CheckDirectX (this->Device->BeginScene ());
    Error::CheckDirectX(this->SpriteDraw->Begin (0));
    Error::CheckDirectX(this->SpriteDraw->Draw(this->Pattern[i].GetInterface(), NULL, NULL, NULL, 0xFFFFFFFF));
    Error::CheckDirectX(this->SpriteDraw->End ());
    Error::CheckDirectX (this->Device->EndScene ());*/
    Error::CheckDirectX(this->Device->Present(0, 0, 0, 0));
}

void 
DXProjector::ProjectLoop()
{
    int i=0;
    while (1){
        this->ProjectPattern (i);
        i++;
        i%=this->Pattern.Size();
    }
}

void 
D3DDevice::InitializeFullScreen (DXReference<IDirect3D9> A_Object, D3DDEVTYPE A_Type, DWORD A_Adapter, DWORD A_RequestedVP, DWORD A_Width, DWORD A_Height, HWND A_HWnd)
{
    // TODO: Spartan!
    this->bInitialize = true;

    this->D3DObject = A_Object;
    D3DDISPLAYMODE mode;
    this->D3DObject->GetAdapterDisplayMode(A_Adapter, &mode);
    Error::CheckDirectX(this->D3DObject->CheckDeviceType(A_Adapter, A_Type, mode.Format, mode.Format, false));
    Error::CheckDirectX(this->D3DObject->CheckDeviceType(A_Adapter, A_Type, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, false));

    D3DADAPTER_IDENTIFIER9 Identifier;
    Error::CheckDirectX(this->D3DObject->GetAdapterIdentifier (A_Adapter, 0, &Identifier));
    D3DCAPS9 caps;
    Error::CheckDirectX(this->D3DObject->GetDeviceCaps(A_Adapter, A_Type, &caps));

    DWORD devBehaviorFlags = 0;
    if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
        devBehaviorFlags |= A_RequestedVP;
    else
        devBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;

    if( caps.DevCaps & D3DDEVCAPS_PUREDEVICE &&
        devBehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)
            devBehaviorFlags |= D3DCREATE_PUREDEVICE;
    devBehaviorFlags |= D3DCREATE_MULTITHREADED; // Comment: Multi threading!
    
    Error::Assert(caps.VertexShaderVersion>=D3DVS_VERSION(3, 0), "Does not support vertex shader 3");
    Error::Assert(caps.PixelShaderVersion>=D3DPS_VERSION(3, 0), "Does not support pixel shader 3");

    this->d3dPParameters.BackBufferWidth            = A_Width; 
    this->d3dPParameters.BackBufferHeight           = A_Height;
    this->d3dPParameters.BackBufferFormat           = D3DFMT_X8R8G8B8;
    this->d3dPParameters.BackBufferCount            = 1;
    this->d3dPParameters.MultiSampleType            = D3DMULTISAMPLE_NONE;
    this->d3dPParameters.MultiSampleQuality         = 0;
    this->d3dPParameters.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
    this->d3dPParameters.hDeviceWindow              = A_HWnd;
    this->d3dPParameters.Windowed                   = false;
    this->d3dPParameters.EnableAutoDepthStencil     = false; 
    this->d3dPParameters.AutoDepthStencilFormat     = D3DFMT_D24S8;
    this->d3dPParameters.Flags                      = 0;
    this->d3dPParameters.FullScreen_RefreshRateInHz = 60;//TODO: Here D3DPRESENT_RATE_DEFAULT;
    this->d3dPParameters.PresentationInterval       = D3DPRESENT_INTERVAL_DEFAULT;

    HRESULT h = this->D3DObject->CreateDevice(
        A_Adapter, // primary adapter
        A_Type,           // device type
        A_HWnd,          // window associated with device
        devBehaviorFlags,   // vertex processing
        &this->d3dPParameters,            // present parameters
        &this->Device.GetWriteAddress());      // return created device
    if (h == D3D_OK)
        return;
    this->bInitialize = false;
    if (h == D3DERR_DEVICELOST)
        return;
    Error::CheckDirectX(h);
}
6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 Feb 26, 2008 at 19:55

Firstly … while( 1 ) {}; is a very intensive thing to do … it caches REALLY well and doesn’t waste many cycles … try while( 1 ) Sleep( 0 );

Btw, Have you tried setting your presentation interval to D3DPRESENT_INTERVAL_ONE or IMMEDIATE rather than DEFAULT? Have seen that give crap before …

46407cc1bdfbd2db4f6e8876d74f990a
0
Kenneth_Gorking 101 Feb 27, 2008 at 12:42

Using D3DCREATE_MULTITHREADED does not make it multithreaded, but multithread safe. This can degrade performance, because of the increased number of enforced locks the runtime makes to avoid deadlocks.

Is there any particular reason why the projector and the window message handler cannot run on the same thread? D3D might not even need the D3DCREATE_MULTITHREADED flag that you provide, so try and remove it and see what happens in the retail version. :)

E96bdd9352bdf5f0e17646cd08c83b0e
0
yakul 101 Feb 27, 2008 at 13:56

With Immediate mode there is no slowdown, but I cannot work with it because ti cause tearing in the projector images and this is unacceptable.
INTERVAL_ONE has the same problem like in INTERVAL_DEFAULT.
I have tried to do while(1){Sleep(0);} and there is no slow down.

Edit:
I have try to run the program on a different computer, and I got other results including some access violation.
First on the output on debug version I get:

Direct3D9: :DoneExclusiveMode
Direct3D9: :Unsubclassing window 001a0776
D3DX: Unrecognized shader version

Notice “Unrecognized shader version”. I get this when I use the following function:

    h = D3DXCreateEffectFromFile(A_Device.GetInterface(), s.c_str(), 
        0, 0, D3DXSHADER_OPTIMIZATION_LEVEL3, 0, &this->Effect.GetWriteAddress(), &errors);

h is Ok.

I don’t know what it means, I don’t get it on the other computer.
However, later on I also get:

“Assertion failure! (h:\gfx_sdk_dgt_sdk\windows\directx\dxg\active\compiler\mid\cbaseprogram.cpp 637): uRangeMin < m_uInsts && uRangeMax <= m_uInsts”

A few dozen times.
Then another: “D3DX: Unrecognized shader version”

Now, sometimes the program just runs without any exception.
Sometimes I get an error INVALIDCALL on this->Effect->BeginPass(n), where n is 0.

Now I noticed that the access violation is gone.
This might be due to the fact that I sorted a problem I had with the projector thread.
The projector thread would keep run, eventhough the class will already be destroyed.
I thought that it shouldn’t affect everything that happens before it, but apparently, not exiting the program properly, affects the next session of the program which suppose to be unrelated to the previous?
I tested the program like this on the other computer.
There is still a slow down on the other computer, but it might be less worse then it was before, I need to check this.

6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 Feb 27, 2008 at 14:06

Have you tried breaing the frame and seeing what the last 10 frame times are? It soudns like your framerate isn’t quite as good as the 200+fps tends to imply. Due to the way drivers work they often buffer several frames worth of data and render it in one go. This can mean that every few presents your frame rate suddenly drops massively.

If you are setting the present parameter to 1 then the frame rate will nto be able to go above the refresh rate (ie 60fps). If it takes longer than a 60th of a second (\~16ms) then it will present whenever it has the opportunity to do so. Which would explain your frame rates between 30fps and 60fps. Its the 200 odd in Debug that are anomalous. I reckon it would be 2 frames fo 200 and then 1 frame of 30 odd … Definitely worth checking.

E96bdd9352bdf5f0e17646cd08c83b0e
0
yakul 101 Feb 27, 2008 at 14:25

No, now that I have set all devices to INTERVAL_DEFAULT, then I get frame rate which is no higher then 60.
On debug the frame rate is about 60, on release its between 15 and 30, but I still need to check it.
Notice I edited my reply, perhaps you could help me with what I am getting there?

Edit:
I have done some research and I found the following:
If I present the projector in the main thread then there is no slow down, but this might cause a slow down of the projector and it is not wanted.
I have tried all sort of combination of creating one or two ID3DObject and ID3DDevice, in the main thread or the projector thread.
It seems like the problematic function is present, I figured that eventhough I have used D3DCREATE_MULTITHREADED, it is still not 100% thread safe.
So I decided to wrap the present of the devices with a mutex.
However, I have a different problem, for some kind of reason the mutex does not protect the critical code, and I end up having both threads enter Present. Because I get an error on present in debug mode in both threads simultanously.
Here is some code:

HANDLE gPresentMutex;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
                   PSTR cmdLine, int showCmd)
{
    gPresentMutex = CreateMutex (NULL, false, NULL);
.
.
.
}

// TODO: Temporary
extern HANDLE gPresentMutex;

void 
D3DDevice::ThreadPresent()
{
    WaitForSingleObject(gPresentMutex, INFINITE);
    Error::CheckDirectX(this->Device->Present(0, 0, 0, 0)); // <break point here
    ReleaseMutex(gPresentMutex);
}
6673a7d3bfd3d1db5e05c5676cc040b6
0
Goz 101 Feb 28, 2008 at 09:45

what EXACTLY are you trying to do? Callnig present from multiple threads is a nightmare waiting to happen (As it seems you have found out). Unless you have 2 seperate windows and 2 seperate D3DDevices …

It sounds to me like you have something SEVERELY architecturally wrong going on …

E96bdd9352bdf5f0e17646cd08c83b0e
0
yakul 101 Feb 29, 2008 at 12:06

I do have two different Devices.
I think the problem is with the full screen mode, I can instead have a window that covers the entire projector “screen” instead and it will work.

46407cc1bdfbd2db4f6e8876d74f990a
0
Kenneth_Gorking 101 Feb 29, 2008 at 18:51

I just stumbled upon an blog entry which might explain your frametime fluctations: Why is Present so slow?