PDA

View Full Version : Display mode changes at runtime (D3D7)


PeterM
07-28-2005, 10:10 AM
Hello,

I'm trying to write a rendering system using Direct3D 7. I'd prefer not to switch to another version, since I see D3D7 as the sweet spot for casual games under Windows.

Part of my difficulty is caused by the fact that I can't install the debug runtime for DX7, since I'm running an XP machine and it comes with DX 8.1. As you probably know, you can't downgrade DirectX to a previous version.

Anyway, I'm trying to switch between display modes at runtime, and between fullscreen and windowed mode. I'm being plagued by troubles related to lost surfaces, Begin/EndScene and the likes, so I'm surely doing something fundamentally wrong.

When switching from windowed to fullscreen I get the situation where BeginScene succeeds, EndScene reports lost surfaces, I restore them, then when trying EndScene again, it reports D3DERR_SCENE_NOT_IN_SCENE, which is strange considering BeginScene succeeded.

I'm wondering what exactly are the steps involved when switching display modes at runtime. Can anybody please tell me which objects are invalidated by DirectDraw and D3D?

Thanks for your help,

Pete

Nikster
07-28-2005, 10:14 AM
Surely if you lose the surface and reaquire you would have to basically go through the whole render process again, as if you lose the surface you basically lose everything you have rendered. I though that was how it worked.. more than likely wrong as always. :)

digriz
07-28-2005, 11:15 AM
From the DX7 SDK help files.
-------------------------------------------------------------------------
Beginning and Ending a Scene

Applications written in C++ notify Direct3D that scene rendering is about to begin by calling the IDirect3DDevice7::BeginScene method. BeginScene causes the system to check its internal data structures, the availability and validity of rendering surfaces, and sets an internal flag to signal that a scene is in progress. After you begin a scene, you can call the various rendering methods to render the primitives or individual vertices that make up the objects in the scene. Attempts to call rendering methods when a scene is not in progress fail, returning D3DERR_SCENE_NOT_IN_SCENE. For more information, see Rendering Primitives.

After you complete the scene, call the IDirect3DDevice7::EndScene method. The EndScene method clears an internal flag that signals when a scene is in progress, flushes cached data, and verifies the integrity of the rendering surfaces.

All rendering methods must be bracketed by calls to the BeginScene and EndScene methods. If surfaces are lost or internal errors occur, the scene methods return error values. If BeginScene fails, the scene does not begin, and subsequent calls to EndScene will fail. When surfaces are lost during rendering, EndScene will return DDERR_SURFACELOST. If surfaces were not successfully restored before calling BeginScene, then BeginScene will also return DDERR_SURFACELOST.

To summarize these cases:

If BeginScene returns any error, you must not call EndScene because the scene has not successfully begun.
If BeginScene succeeds, but you get an error while rendering of the scene, you must call EndScene.
If EndScene fails, for any reason, you need not call it again.
For example, some simple scene code might look like this:

HRESULT hr;

if(SUCCEEDED(lpDevice->BeginScene()))
{
// Render primitives only if the scene
// starts successfully.

// Close the scene.
hr = lpDevice->EndScene();
if(FAILED(hr))
return hr;
}
You cannot embed scenes; that is, you must complete rendering a scene before you can begin another one. Calling IDirect3DDevice7::EndScene when IDirect3DDevice7::BeginScene has not been called returns the D3DERR_SCENE_NOT_IN_SCENE error value. Likewise, calling BeginScene when a previous scene has not been completed (with the EndScene method) results in the D3DERR_SCENE_IN_SCENE error.

Do not attempt to call GDI functions on DirectDraw surfaces, such as the render target or textures, while a scene is being rendered (between BeginScene and EndScene calls). Attempts to do so can prevent the results of the GDI operations from being visible. If your application uses GDI functions, be sure that all GDI calls are made outside the scene functions.
[Visual Basic]
Visual Basic applications notify Direct3D that scene rendering is about to begin by calling the Direct3DDevice7.BeginScene method. BeginScene causes the system to check its internal data structures, the availability and validity of rendering surfaces, and sets an internal flag to signal that a scene is in progress. After you begin a scene, you can call the various rendering methods to render the primitives or individual vertices that make up the objects in the scene. Attempts to call rendering methods when a scene is not in progress fail, returning the D3DERR_SCENE_NOT_IN_SCENE error. For more information, see Rendering Primitives.

After you complete the scene, call the Direct3DDevice7.EndScene method. The EndScene method clears an internal flag that signals when a scene is in progress, flushes cached data, and verifies the integrity of the rendering surfaces.

All rendering methods must be bracketed by calls to the BeginScene and EndScene methods. If surfaces are lost or internal errors occur, the scene methods fail and Err.Number will be set to an error code. If BeginScene fails, the scene does not begin, and subsequent calls to EndScene will fail. When surfaces are lost during rendering, EndScene will fail, raising the DDERR_SURFACELOST error. If surfaces were not successfully restored before calling BeginScene, then BeginScene will also return DDERR_SURFACELOST.

To summarize these cases:

If BeginScene returns any error, you must not call EndScene because the scene has not successfully begun.
If BeginScene succeeds, but you get an error while rendering of the scene, you must call EndScene.
If EndScene fails, for any reason, you need not call it again.
For example, some simple scene code might look like this:

On Local Error Resume Next

Call d3dDev.BeginScene
If Err.Number = DD_OK Then
' Render primitives only if the scene
' starts successfully.

' Close the scene.
Call d3dDev.EndScene
If Err.Number <> DD_OK Then
' Code to handle error goes here.
End If
End If
You cannot embed scenes; that is, you must complete rendering a scene before you can begin another one. Calling Direct3DDevice7.EndScene when Direct3DDevice7.BeginScene has not been called causes a D3DERR_SCENE_NOT_IN_SCENE error. Likewise, calling BeginScene when a previous scene has not been completed (with the EndScene method) results in the D3DERR_SCENE_IN_SCENE error.

Do not attempt to call GDI functions on DirectDraw surfaces, such as the render target or textures, while a scene is being rendered (between BeginScene and EndScene calls). Attempts to do so can prevent the results of the GDI operations from being visible. If your application uses GDI functions, make sure that all GDI calls are made outside the scene functions.

PeterM
07-28-2005, 11:35 AM
You're both right, thanks for the info. I gotta RTFM more carefully! EndScene was failing, and I was calling it again.

Now that I can switch between fullscreen and windowed I'll look into recreating my texture surfaces properly.

Thanks again.

Pete

vjvj
07-28-2005, 01:20 PM
Keep in mind it's not just textures that need to be recreated, pretty much everything in D3DPOOL_DEFAULT needs to be rebuilt. This includes surfaces, vertex buffers, etc...

PeterM
07-28-2005, 04:13 PM
As far as I know D3DPOOL_* was introduced in version 8, but I indeed found that pretty much everything needs to be destroyed and recreated, or backed up in a software buffer for restoration when needed.

So that's what I do. Textures are backed up in software on creation for restoration later, and vertex buffers are backed up just before being destroyed, and restored from the backup when recreated.

Unfortunately this means I can't create them with the write only flag. But I can lock them with this flag.

I think I've pretty much got it sorted now, on with The Master Plan!

Thanks again guys.