Jump to content
  • Advertisement
Sign in to follow this  
zyrolasting

Preserving data through device reset?

This topic is 3694 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

When I make any other window active then return to my game, it crashes. It seems that when my device resets, the data I need to redraw the screen was lost. I built a good sized namespace with several classes holding DirectX interfaces. After I define all my classes, I make a final class that holds instances of the previous classes to make an interface, which I access through all parts of my wrapper. All I want to do is know how to retain all the data of that one last class through a device reset, but I'm not sure how to do that. For reasons of keeping my posts short enough to read, I'm not pasting my code.

Share this post


Link to post
Share on other sites
Advertisement
All the Interfaces that are device-dependant and are not in the MANAGED pool need to be recreated when resetting the device.

The common way to do it is to create both LostDevice and ResetDevice events in your class, and call them when needed. The LostDevice event should clear all references to the device-dependant interfaces, and the ResetDevice should recreate them.

Generally, the most efficient of handling these situations is creating static objects like meshes or textures on the MANAGED pool (so they doesn't need to be recreated) and the dynamic objects on the DEFAULT pool (they will need to be handled by the LostDevice and ResetDevice events).

If you have a class that holds other classes, you may create the LostDevice and ResetDevice on the main class, and then let it call it's children classes when needed.

(Pascal)


type
TChildClass = TObject
private
D3DDefaultPoolObject: IDirect3DTexture9;
public
procedure LostDevice;
procedure ResetDevice;
end;

TChildClass.LostDevice;
begin
// Remove reference to the D3DPOOL_DEFAULT interfaces
SAFE_RELEASE(D3DDefaultPoolObject);
end;

TChildClass.ResetDevice;
begin
// Recreate the D3DPOOL_DEFAULT interfaces
D3DXCreateTexture(..., D3DDefaultPoolObject);
end;




TMainClass = TObject
public
procedure LostDevice;
procedure ResetDevice;
end;

TMainClass.LostDevice;
var I: Integer;
begin
// Remove reference to the D3DPOOL_DEFAULT interfaces
// on all childs
for I:= 0 to ChildCount-1 do
Childs.LostDevice;
end;

TMainClass.ResetDevice;
var I: Integer;
begin
// Recreate the D3DPOOL_DEFAULT interfaces
// on all childs
for I:= 0 to ChildCount-1 do
Childs.ResetDevice;
end;



I hope this helps. Regards,

Juan Pablo

Share this post


Link to post
Share on other sites
I noted you mentioning the class-based reset/create events, and I'll remember that. Thanks for the input!

EDIT: Alright, my issue seems a little weirder than expected.

I double checked, and all of my graphic resources are already in the managed pool. (To the extent I could manage)

Anyway, I figured my issue was resource related when I saw my game crashed with an unhandled exception error right as it was about to draw the sprites.
The line the debugger points me to is actually a call to SetRect, and I get this error.

Unhandled exception at 0x0058e132 in DirectX Practice.exe: 0xC0000005: Access violation writing location 0x7f807500.

The address 0xC0000005 was one I saw before, and it IS related to my textures from what I've seen in my previous issues, but from what I see, everything is on Managed.

I get this in a little more detail? Again, the debugger highlights a call to SetRect, when the window is made active again. This is right before drawing sprites.

[Edited by - zyrolasting on November 2, 2008 10:34:59 PM]

Share this post


Link to post
Share on other sites
You're welcome :)

You don't need to worry about resources created on the MANAGED pool. In most cases, meshes and textures are created on this pool. You need to take a look at your code to make sure of it. For example, if you're using D3DX,

HRESULT D3DXCreateMesh(
DWORD NumFaces,
DWORD NumVertices,
DWORD Options,
CONST LPD3DVERTEXELEMENT9 * pDeclaration,
LPDIRECT3DDEVICE9 pD3DDevice,
LPD3DXMESH * ppMesh
);

The Options parameters must include the D3DXMESH_MANAGED flag.

Dynamic objects like renderable textures or dynamic vertex buffers are usually created on the DEFAULT pool and need to be restored when the device is reset.

Good luck!

Share this post


Link to post
Share on other sites
Hm, interesting... can you post some of your code to see it with more details? At least the code related to the SetRect call you're referring. I hope I can help you :)

"For reasons of keeping my posts short enough to read, I'm not pasting my code." Remember to surround your code with the [ source ] and [ /source ] tags (without the spaces).

Regards,

Share this post


Link to post
Share on other sites
Quote:
"For reasons of keeping my posts short enough to read, I'm not pasting my code." Remember to surround your code with the [ source ] and [ /source ] tags (without the spaces).
I'm aware, just a lot of code.

I removed the calls to my sprites, and now the debugger mentions a call
to D3DXMatrixTranslation being faulty. It's still obscure, especially since my models were working when the sprite calls were there!. For the record, I set my Debug Output level to almost Max, (Both D3D and DI) and I don't see any error entries...

I have an idea. Rather than post all my code at once and become overwhelming, I'll start with my engine header. It's pretty generic. Tell me the areas you don't like the look of, and I'll reveal more related code.
Since I keep mentioning graphics, I also threw in my Sprite and Model classes.

For a little background, the engine interface class uses a constructor for a very basic struct... It holds window width, height, screen mode... Nothing worrisome or relevant.

Just let me know what you need to see... Sorry it can't be shorter, and thanks again.


/**************************/
//Model Class.
//Holds info for a mesh. Requires Direct3D headers.
/**************************/

class MODEL
{
public:
LPD3DXMESH Mesh;
D3DMATERIAL9* Material;
LPDIRECT3DTEXTURE9* Texture;
DWORD numMaterials;
GameObject* AssignedObject;


D3DXVECTOR3 minBounds, maxBounds, WorldBounds[8], ObjectBounds[8];
bool meshReady;
int mesh_Id;

~MODEL()
{
delete [] Material;
delete [] Texture;
}
bool SetModelBoundBox();
void AABBtoWorldArray(D3DXMATRIX *T);
void AABBfromOBB();
};

//Sprite Class holds info related to a sprite interface.
class SPRITE
{
public:
int rows, cols, width, height, id; // width and height are frame based.
LPDIRECT3DTEXTURE9 tex; // texture
~SPRITE()
{
if (spriteReady)
tex->Release();
}
void DrawSprite(RECT spriteArea, float x, float y);
private:
bool spriteReady;
};






#ifndef __QE__
#define __QE__

#define MAX_TEXTURES 100
#define MAX_MESHES 50
#define MAX_SPRITES 20
#define MAX_LIGHTS 20
#define MAX_LEVELS 5


namespace 3D_Engine
{
enum 3DE_Report
{
FINE,
LOADING_RESOURCES,
RESOURCE_LOADED,
TEXT_FILE_FAILED,
FILE_NOT_FOUND,
MODEL_FAILED,
SPRITE_FAILED,
LIMIT_REACHED,
};

/***********************//*
CLASS C_Resources
The main resource handler to the game. It will handle model/sprite usage,
as well as text files to manipulate values.
*/
/***********************/
class C_Resources
{
public:
LPDIRECT3DDEVICE9 dev;
MODEL objectModels[MAX_MESHES];
SPRITE gameSprites[MAX_SPRITES];

~C_Resources()
{
for (int i = 0; i < MAX_MESHES; i++)
{
if (objectModels.meshReady)
objectModels.Mesh->Release();
}
}
bool LoadModel(MODEL* mesh, LPCTSTR File);
bool AddModel(LPTSTR filename, int id);

bool LoadSprite(LPCTSTR File, int _id);
void setSpriteInterface(LPD3DXSPRITE _d3dspr) { d3dspr = _d3dspr; }
void DrawSprite(int index, int rx, int ry, int rX, int rY, float x, float y)
{
d3dspr->Begin(D3DXSPRITE_ALPHABLEND);
D3DXVECTOR3 position(x, y, 0.0f);

RECT spriteArea;
SetRect(&spriteArea, rx, ry, rX, rY);

d3dspr->Draw(gameSprites[index].tex, &spriteArea, NULL, &position, D3DCOLOR_XRGB(255, 255, 255));
d3dspr->End();
}
void AssignMeshtoObject(GameObject* gObj, int index) { objectModels[index].AssignedObject = gObj; }
LPD3DXSPRITE * GetSpriteInterface() { return &d3dspr; }
private:
int MeshesLoaded, SpritesLoaded;
LPD3DXSPRITE d3dspr;
};


/***********************//*
CLASS C_Manager
The primary tool for the Engine's error checking.
It is focused on more specific issues, and will be more useful for
mathematical validation and checking the integrity of my own data.
*/
/***********************/


class C_Manager
{
public:
C_Manager()
{
ObjectsInGame = ObjectsActive = NULL;
};
bool CheckEquality(float a, float b, bool HighPrecision);
int ObjectsInGame, ObjectsActive;
};

/***********************//*
CLASS C_RoomC
Short for Room Constructor.
This will act as a mapper and graphical debugger for levels, using simple concept functions
with potentially complex calculations in later versions.
It can be very useful for determining distance in game, or just moving crap around and seeing if
you like a certain place for it to be.

The class will also hold the paths to files necessary for levels as they load.
*/
/***********************/

class C_RoomC
{
public:
LPDIRECT3DDEVICE9 dev;
char* LevelPath[MAX_LEVELS];
int CurrentLevel;

C_RoomC()
{
CurrentLevel = active = 0;
};
C_RoomC(bool _active)
{
CurrentLevel = 0;
active = _active;
};
void setActive(bool _active) {active = _active;}
void CreateBasicLight(LIGHT* Light, D3DXVECTOR3 _Position, float range);
void CreateComplexLight(LIGHT* Light, D3DLIGHTTYPE type, float range, D3DXVECTOR3 _Position, D3DXVECTOR3 Attenuations, D3DXCOLOR color);
void TweakAmbientLight(int r, int g, int b) { dev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(r, g, b)); }

private:
bool active;
int lights_used;
LIGHT Lights[MAX_LIGHTS];
};
};

//Engine immediately available.
using namespace 3D_Engine;


/***********************//*
CLASS EngineInterface

Holds the above classes to make the entire engine accessible.
Intended to be used as an instance once Direct3D loads.
*/
/************************/
typedef class EngineInterface
{
public:
GAMEWINDOW* gw;

C_Resources Loader;
Manager Mng;
C_RoomC Room;

fstream 3DE_Log;

EngineInterface(GAMEWINDOW* _gw)
{
setGameLevelPaths();
gw = _gw;
3DE_Log.open("3DE_Log.txt", ios::app);
3DE_Log << "Initializing Engine" << endl << endl;
};

~EngineInterface() { if (3DE_Log.is_open()) 3DE_Log.close(); }

void setInterface(LPDIRECT3DDEVICE9 _dev) { dev = Room.dev = Meblod.dev = _dev; }
3DE_Report setGameLevelPaths();
3DE_Report LoadLevel();

private:
LPDIRECT3DDEVICE9 dev;
} ENGINE;
#endif



Share this post


Link to post
Share on other sites
D3DX interfaces, like sprites, have OnLostDevice and OnResetDevice functions that need to be called on device reset (the first before the reset and the second after it). I haven't read your code, but my guess is that's the problem.

Share this post


Link to post
Share on other sites
Whoa, noted. Thanks.

I'm considering a rebuild, make it less strewn out over my sources...

What's also weird is that my LoadModel and LoadSprite
functions are enclosed in FAILED() conditions that
are meant to terminate the game if true.

So... I should have everything loaded. Even so, again, I noticed the unhandled exception error had the same address as a previous issue I had, where my buffers in mesh loading were invalid.

TO make it even more annoying, the error look-up tool has no info
I can understand about the error address. (0xC0000005 or so)

Share this post


Link to post
Share on other sites
Quote:
Original post by zyrolasting
Whoa, noted. Thanks.

I'm considering a rebuild, make it less strewn out over my sources...

What's also weird is that my LoadModel and LoadSprite
functions are enclosed in FAILED() conditions that
are meant to terminate the game if true.

So... I should have everything loaded. Even so, again, I noticed the unhandled exception error had the same address as a previous issue I had, where my buffers in mesh loading were invalid.

TO make it even more annoying, the error look-up tool has no info
I can understand about the error address. (0xC0000005 or so)
That's not the memory address, that's the exception code - 0xC0000005 means "Access Violation". The memory address is 0x7f807500, which looks like it's in kernel32.dll or some other system DLL.
Look further down the call stack when the exception occurs, and find the line of your code that causes it. Once you've done that, you can be pretty sure that the pointer you dereferenced on that line is invalid (Not reset, etc).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!