Rendering problem on new PC

Started by
4 comments, last by dracan 17 years, 5 months ago
Hi. I've recently got a new computer at work, and have pinched an NVidia 6600GT off a colleague who has just left the company. I'm finding that my DirectX geometry doesn't render if I create the device using hardware vertex processing. My testcase is just a basic app that renders a triangle onto the screen (using FFP, not shaders). I've got a 6600GT at home too, and it works fine there. I'm getting no DX debug output warnings. I've ran dxdiag.exe, and all the tests succeed. I've tried reinstalling the latest drivers. Nothing makes a difference. If I run it through pix, then it doesn't even seem to be trying to render the triangle. Any ideas what else I can try? (testcase download) Cheers, - Dan
Advertisement
A few thoughts/comments/suggestions:

1. I'd advise at least one call to UpdateWindow() and one to ShowWindow() after you've created and shown the window. [edit]missed the WS_VISIBLE, though I'd still put an UpdateWindow in to ensure you get that first paint message[/edit]

2. Consider what will happen if you get a WM_PAINT message before you've set up DirectX, your geometry, etc (different versions/service packs of Windows do subtly different things as part of their window creation - including which messages they do/don't send).

3. Consider what happens when you don't get any WM_PAINT messages or don't get them often (which will happen). If you want regular calls to Render, I'd put the call in the message pump loop instead.

4. Compare the desktop modes between the machine it works on and the one it doesn't. Try setting the one it doesn't work on to 16bit, if that works, compare the advanced D3D options in the display properties. It shouldn't be the case with the 6600, but older nVidia cards required the depth-stencil buffer to be the same bitdepth as the frame buffer [thus the existence of CheckDepthStencilMatch()] - their device drivers used to change the depths to match behind your back if your app requested differing formats - but only when the advanced option was enabled.

[Edited by - S1CA on October 21, 2006 8:57:22 AM]

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

I tried compiling your code with USE_REF_DEVICE #defined to FALSE on VC++ EE 2005 and got the following error message after trying to run the EXE:

Unhandled exception at 0x004010b3 in d3dtest.exe: 0xC0000005: Access violation reading location 0x00000000.

It did in fact run correctly with USE_REF_DEVICE set to TRUE. I'm not sure why. However, I can make the following suggestions:

- Stop using the C macros (IDirect3DDevice9_SetTransform(this, a, b). Use the -> operator instead. Using the macros is just awkward and clumsy, and switching between the two forms is even worse.

- If you're using D3DFVF_XYZRHW vertices, SetTransform and SetMaterial have no effect. Also most of those RenderStates you're setting have no effect under pre-transformed vertices.

- Don't render in WM_PAINT. Instead, use PeekMessage(0, &msg 0, 0, PM_REOMVE) in your message loop like this:

while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
Render();
}

- Your message loop should be part of WinMain so that you can return the wParam value as an exit code.

- Create your vertices in memory before you lock the vertex buffer. Once it is locked, use a memcpy() call to copy in all the vertices at once. You should always keep your buffers locked for as short a time as possible.

- Use CS_OWNDC instead of CS_CLASSDC in WNDCLASSEX.style. OWNDC gives each window its own DC, while CLASSDC requires that all the windows in the class share a DC. The only reason you might use CLASSDC is to save memory, but there's no reason to think about things like that nowadays.

- Like S1CA said, use ShowWindow and UpdateWindow after all your initialization. If you start the message loop too soon, you might get a WM_PAINT before DirectX is set up. Of course, you should also be using PeekMessage (as shown above) instead of GetMessage.

- Use angle brackets instead of quotes " " when #including the Direct3D headers. This tells C++ to search in the system include directories first instead of your own project include directories.

Of course, probably the best course of action is to just rewrite the whole project. That often helps catch errors that you otherwise miss completely.
Thanks for your replies guys. Please bear in mind that this testcase app was knocked up in about 5 minutes to test this problem in a basic program, instead of my engine project. I'm suspecting though that there's something wrong with the machine I'm using at work. My install of Windows has gone through a lot. Ie. upgrade from 2000 to XP (upgrade - not full reinstall), then a bit later followed by complete motherboard, cpu, and memory upgrade without reinstalling Windows. I think I might try a full reinstall of XP again. I've started noticing some things not rendering in other d3d apps too - although funnily enough - not all directx apps! :|

But to reply back about some of your comments ...

Quote:Original post by S1CA
1. I'd advise at least one call to UpdateWindow() and one to ShowWindow() after you've created and shown the window. [edit]missed the WS_VISIBLE, though I'd still put an UpdateWindow in to ensure you get that first paint message[/edit]

I didn't know that you could miss the first paint message like this. I'll start including UpdateWindow then. Does this apply to all Windows apps - or just D3D ones?

Quote:Original post by S1CA
2. Consider what will happen if you get a WM_PAINT message before you've set up DirectX, your geometry, etc (different versions/service packs of Windows do subtly different things as part of their window creation - including which messages they do/don't send).

But I set up directx and my geometry before I enter the messageloop. So surely the WM_PAINT message will be queued up until I call GetMessage? Or would it get discarded?

Quote:Original post by S1CA
3. Consider what happens when you don't get any WM_PAINT messages or don't get them often (which will happen). If you want regular calls to Render, I'd put the call in the message pump loop instead.

In my main engine, I've got my message loop, and render loop working in different threads. This testcase app was just quickly knocked together.

Quote:Original post by S1CA
4. Compare the desktop modes between the machine it works on and the one it doesn't. Try setting the one it doesn't work on to 16bit, if that works, compare the advanced D3D options in the display properties. It shouldn't be the case with the 6600, but older nVidia cards required the depth-stencil buffer to be the same bitdepth as the frame buffer [thus the existence of CheckDepthStencilMatch()] - their device drivers used to change the depths to match behind your back if your app requested differing formats - but only when the advanced option was enabled.

I'll give that a go tomorrow when I get to work :)

Quote:Original post by Anonymous Poster
I tried compiling your code with USE_REF_DEVICE #defined to FALSE on VC++ EE 2005 and got the following error message after trying to run the EXE:

Unhandled exception at 0x004010b3 in d3dtest.exe: 0xC0000005: Access violation reading location 0x00000000.

It did in fact run correctly with USE_REF_DEVICE set to TRUE. I'm not sure why.

That's interesting. I'm compiling using VC2003 here. Is there any chance you can run it in a debug build and let me know what the crash was?

Quote:Original post by Anonymous Poster
- Stop using the C macros (IDirect3DDevice9_SetTransform(this, a, b). Use the -> operator instead. Using the macros is just awkward and clumsy, and switching between the two forms is even worse.

I've recently converted my engine from C to Cpp. That's why there a mismatch of macro calls and -> calls. It's only a home R&D engine anyway - so it's not that important little things like that. I will go and have a "tidy up" session at some point though :)

Quote:Original post by Anonymous Poster
- If you're using D3DFVF_XYZRHW vertices, SetTransform and SetMaterial have no effect. Also most of those RenderStates you're setting have no effect under pre-transformed vertices.

As I said early, this testcase was knocked up very quickly. There may be a few states that didn't need to be set. However, this certainly shouldn't cause the problem I'm getting.

Quote:Original post by Anonymous Poster
- Create your vertices in memory before you lock the vertex buffer. Once it is locked, use a memcpy() call to copy in all the vertices at once. You should always keep your buffers locked for as short a time as possible.

As all my code is sequential in this testcase app, then it really shouldn't matter how long the buffer is locked for.

Quote:Original post by Anonymous Poster
- Use CS_OWNDC instead of CS_CLASSDC in WNDCLASSEX.style. OWNDC gives each window its own DC, while CLASSDC requires that all the windows in the class share a DC. The only reason you might use CLASSDC is to save memory, but there's no reason to think about things like that nowadays.

If I've only got one window - does it matter which one I choose?

Quote:Original post by Anonymous Poster
- Use angle brackets instead of quotes " " when #including the Direct3D headers. This tells C++ to search in the system include directories first instead of your own project include directories.

Noted. I'm from a C background, so it's always second nature to use quotes instead of angles brackets. I'll try and start getting into the habbit now.

Quote:Original post by Anonymous Poster
Of course, probably the best course of action is to just rewrite the whole project. That often helps catch errors that you otherwise miss completely.

That's what the testcase app was about! :) I certainly have no intention of rewriting my entire engine. I quickly knocked up this testcase to quickly try and narrow down what the problem was. I do think it's a problem with my machine though. Would be interesting to know what your crash was though.

Thanks again,
- Dan
Quote:Original post by dracan
I've started noticing some things not rendering in other d3d apps too - although funnily enough - not all directx apps! :|


Ah, so it could still be down to some hardware/driver/configuration thing - as well as graphics drivers, I'd check: motherboard & CPU drivers, AGP aperture size in the BIOS, and of course the various OS service packs.

Another thought - if the machine has multiple monitors, try forcing your window to open on the 'other' monitor rather than the default monitor. The part of the GPU driving each monitor shows up to Windows (and DirectX for pre-multihead drivers) as a separate device per monitor. Some [usually older budget] cards with two outputs really only have accelerated 3D on one output at a time.


Quote:
Quote:Original post by S1CA
1. I'd advise at least one call to UpdateWindow() and one to ShowWindow() after you've created and shown the window. [edit]missed the WS_VISIBLE, though I'd still put an UpdateWindow in to ensure you get that first paint message[/edit]

I didn't know that you could miss the first paint message like this. I'll start including UpdateWindow then. Does this apply to all Windows apps - or just D3D ones?


CreateWindow() with WS_VISIBLE is documented as "If the WS_VISIBLE style is specified, CreateWindow sends the window all the messages required to activate and show the window." AFAIK there's no guarantee of one of those messages being a WM_PAINT - I'll have to double check, but I've never seen it documented anywhere that you're guaranteed to get WM_PAINT.


Quote:
Quote:Original post by S1CA
2. Consider what will happen if you get a WM_PAINT message before you've set up DirectX, your geometry, etc (different versions/service packs of Windows do subtly different things as part of their window creation - including which messages they do/don't send).

But I set up directx and my geometry before I enter the messageloop. So surely the WM_PAINT message will be queued up until I call GetMessage? Or would it get discarded?


You get sent window messages before the message pump. Windows already has your window procedure callback address and does call it internally inside things like CreateWindow(). From a quick test using the Vertices tutorial just I got 20 different messages to the window procedure between entering CreateWindow() and the start of the message pump.


It might be worth completely obscuring then revealing the window with another to guarantee to WM_PAINTs (with some breakpointage too) which would let you at least rule out that code path.

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

I've just reinstalled Windows from scratch. That seems to have sorted it! God knows what was going on with it - but at least it's working now.

Thanks for your replies! :-)

- Dan

This topic is closed to new replies.

Advertisement