Jump to content
  • Advertisement
Sign in to follow this  
schupf

Device Lost: Destroy AND fill?

This topic is 2692 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

Hello,

if you lose a D3D9 device you have to destroy all resources in default pool.
1. Are there other resources than VB, IB and textures I have to care about? The backbuffer is also a resource but I guess I don't have to destroy it?

2. The normal procedure when working with resources is like this:
createResource(..., &res);
res->lock()
// fill
res->unlock();
All documents about lost devices I have read so far tell me I have to destroy the resource on lost device. But when I destroy the resource all data that was INSIDE the resource
is lost too. So is it true that the flow on lost device should be more like this:
destroy res;
Then later if device is again available
res->lock()
// fill
res->unlock()
Is this correct?
I have some trouble finding a good solution for this "refilling after device reset" problem. I mean an entity can modify a resource very often (a dynamic VB for example) and when a deviceLost occurs
I somehow have to save the current values inside the resource, don't I? How do engines solve this problem?

Share this post


Link to post
Share on other sites
Advertisement
It's easiest if the entity can completely recalculate the data (for example a dynamic vertex buffer for particles) on demand. Then you'd just set a flag telling it to refresh everything, without actually needing to save the data.

Share this post


Link to post
Share on other sites

I mean an entity can modify a resource very often (a dynamic VB for example) and when a deviceLost occurs
I somehow have to save the current values inside the resource, don't I? How do engines solve this problem?
In that case, either have the entity able to recreate the buffer from scratch (keep the communication flow one-way, only ever write into your locked buffers, never read from them), OR if you have to be able to read from the buffers / can't re-create them from scratch, then whenever you lock/update a buffer, also update a copy of that data in main memory (e.g. use a vector<char> to hold your copy), then if the GPU loses it's copy, you can restore it from your own copy.

Share this post


Link to post
Share on other sites

[quote name='schupf' timestamp='1305102905' post='4809319']
I mean an entity can modify a resource very often (a dynamic VB for example) and when a deviceLost occurs
I somehow have to save the current values inside the resource, don't I? How do engines solve this problem?
In that case, either have the entity able to recreate the buffer from scratch (keep the communication flow one-way, only ever write into your locked buffers, never read from them), OR if you have to be able to read from the buffers / can't re-create them from scratch, then whenever you lock/update a buffer, also update a copy of that data in main memory (e.g. use a vector<char> to hold your copy), then if the GPU loses it's copy, you can restore it from your own copy.
[/quote]

But doesn't that mean I almost always have to cache the content of the resource in local RAM?
For example assume I have a very simple Box class that represents a static box. Normally I would just put the static content once in the VB:

Box::Box() {
Vertex v[8]
device->createVB(..., &mVB);
mVB->Lock();
// copy array v into VB
mVB->unlock();
}

Now all vertices are only in the VB (no second copy in RAM). If I understood you corretly you proposed that Box gets a fill method like Box::fill() that puts the vertices in the VB. When the device is lost
I call box->onDeviceLost() which destroys the VB and when the device is ready I call box->reset() which creates and fills the VB. But this means box has to store a local copy of the vertices as class
member (member v in the ctor code). Am I am right?

Share this post


Link to post
Share on other sites

Now all vertices are only in the VB (no second copy in RAM). If I understood you corretly you proposed that Box gets a fill method like Box::fill() that puts the vertices in the VB. When the device is lost
I call box->onDeviceLost() which destroys the VB and when the device is ready I call box->reset() which creates and fills the VB. But this means box has to store a local copy of the vertices as class
member (member v in the ctor code). Am I am right?
Yes - but in the simple case of a box there's no need to store a backup in RAM, because you can re-create it from the original parameters (e.g. the width/height/depth of the box)...

If instead of a box you've got a static mesh loaded from a file, you could choose to either store a backup in RAM, or instead you could re-load the file from disk (if you wanted to save a bit of memory, but increase the time it takes to recover from a lost device).

N.B. This "RAM backup" is exactly what D3DPOOL_MANAGED does for you automatically --- if you allocate a buffer in the managed pool, D3D will store a copy in both main RAM and on the GPU. You don't have to do anything when a device is lost for managed buffers - D3D does the 'backup restore' for you.

For most of your static meshes, the easiest option is simply to just use the managed pool.
The only things you can't put in the managed pool are dynamic vertex buffers -- and if you're using dynamic vertex buffers, that means you're overwriting them all the time with newly generated data from main RAM anyway, so it doesn't really matter if their data is lost (just overwrite it again as you always do).

In short:
Static vertex buffers (most of your models) == D3DPOOL_MANAGED
Static vertex buffers where you want to handle device-lost logic by yourself = D3DPOOL_DEFAULT + D3DUSAGE_WRITEONLY
Dynamically modified buffers (very rare you need these) == D3DPOOL_DEFAULT + D3DUSAGE_WRITEONLY + D3DUSAGE_DYNAMIC

Similarly for textures:
Static textures (most of your textures) == D3DPOOL_MANAGED
Textures that are drawn to by the CPU (e.g. for a video player, again, very rare) = D3DPOOL_DEFAULT + D3DUSAGE_DYNAMIC
Textures that are drawn to by the GPU (render-targets) == D3DPOOL_DEFAULT + D3DUSAGE_RENDERTARGET

Share this post


Link to post
Share on other sites
Wow, that was very helpful! Thanks Hodgman!

Two more little questions:
1. I wanted to make this design: I have an abstract base class D3DResource and for every D3D resource a sub class, for example: D3DVertexBuffer : public D3DResource. class D3DResource
has methods like onDeviceLost() and onDeviceReset(). The subclasses are just wrapper about the true resource, for example D3DVertexBuffer has a pointer to the real IDirect3DVertexBuffer*
All resources are created by a manager and this manager calls onDeviceLost() for all DEFAULT resources on a device lost.
The Problem: Now I have classes that use these resources, for example my Mesh class HAS a pointer to a D3DVertexBuffer. Now if the device is lost I wonder how I can notify the Mesh that it has to refill the D3DVertexBuffer. I could add a valid flag to the resources but then every user (like Mesh) had to check this flag every frame. Any ideas how I could solve this notification of resource users?

2. I have a vertexbuffer that gets updates SOMETIMES. For example 2 minutes no updates at all and then for some frames every frame 1 update. What would be the best type for such a VB?
I guess Dynamic + DEFAULT is kinda overkill. Would a MANAGED VB better? Or should I make a static DEFAULT VB and a SYSMEM VB and just update the SYSMEM VB and then copy into the DEFAULT VB?

Share this post


Link to post
Share on other sites
1.) You could make your mesh a D3DResource too, but you could also make the buffer recreate itself. Another way would be using function pointers to tell your resource manager which functions to call on lost and reset device instead of inheritance. I'm using a similar design as yours and once it's up and running, it works pretty good. Not sure if it's an optimal solution though.

2.) In this case a managed vb should suffice. I think it internally its quite the same as a sysmem + default vb.

Share this post


Link to post
Share on other sites

1.) You could make your mesh a D3DResource too, but you could also make the buffer recreate itself. Another way would be using function pointers to tell your resource manager which functions to call on lost and reset device instead of inheritance. I'm using a similar design as yours and once it's up and running, it works pretty good. Not sure if it's an optimal solution though.


Hm, I still have no good idea how to solve the refilling problem. Assume I have a class that uses some D3DResources (that may get lost):



class Mesh {

D3DVertexBuffer* vb;

D3DTexture* tex;

D3DTexture* tex2Managed;

}




Mesh::vb, Mesh::tex and Mesh::tex2Managed are created by a ResourceManager. When the device is lost the manager destroys all resources. But when the device is reset I somehow have to inform all users of the resources that they have to refill their recreated resources. In this example ResourceManager has to inform the Mesh object "hey, refill your vb and tex member" (tex2Managed is a MANAGED resource, so the manager should not order Mesh to refill this resource).

So a simple deviceReset() is not enough, because I need to tell Mesh exactly WHAT to refill. Anyone has an idea how I could solve this?

Share this post


Link to post
Share on other sites
Going back to your original question, any D3DX objects that have OnLostDevice/OnResetDevice methods also need to have these called.

MS recommend that your resource recreation code be the same as your initial resource creation code, and they generally tend to follow this in all of their examples.

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.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!