SafeDelete() and datablock deletion
by Michael Cordner · in Torque Game Builder · 07/20/2005 (3:25 am) · 7 replies
I'm trying to organise my efforts to date into some sort of coherent structure, whereby I can switch rooms when the character gets to the edge of the screen. I'm currently using an onWorldLimit() callback to detect when the current screen should unload and the new screen should load. The load and unload functionlity for a screen is encapsulated in a 'class' (or at least, as close as torquescript gets you to a class)
When actually trying to implement the deletion of the room, I came across some funnies with using safeDelete(). I think it's down to my lack of understand as to how it works, but I haven't really been able to find much info on it.
When I delete a room object, I call a Room::destroy() function that calls safedelete on all of the elements in the room (and delete() on the ScriptObjects that encapsulate some of them). Then the game controller loads the next room, which seems to appear without any issue. However, some of the onscreen elements from the previous scene still appear. It would appear that they aren't getting removed from the scenegraph, though the handles to them appear to be invalid (for instance, they won't cause collision events, even though they appear on screen).
Again, it's probably down to understanding. Does anyone have the time to explain when and how it's appropriate to use safedelete, and what kinds of issues might cause the behaviour I'm seeing? For instance, I've seen indications that calling safedelete within a callback might result in problems, though I'm not sure exactly what they might be.
A silly question on a related issue, if I have a datablock loaded, and no object actually referencing it, does it hang about in memory? Or is there some logic that only loads the data if and when an object is referencing it? If I'm changing 'rooms' like I'm describing, is it necessary to delete the room specific datablocks as I change?
When actually trying to implement the deletion of the room, I came across some funnies with using safeDelete(). I think it's down to my lack of understand as to how it works, but I haven't really been able to find much info on it.
When I delete a room object, I call a Room::destroy() function that calls safedelete on all of the elements in the room (and delete() on the ScriptObjects that encapsulate some of them). Then the game controller loads the next room, which seems to appear without any issue. However, some of the onscreen elements from the previous scene still appear. It would appear that they aren't getting removed from the scenegraph, though the handles to them appear to be invalid (for instance, they won't cause collision events, even though they appear on screen).
Again, it's probably down to understanding. Does anyone have the time to explain when and how it's appropriate to use safedelete, and what kinds of issues might cause the behaviour I'm seeing? For instance, I've seen indications that calling safedelete within a callback might result in problems, though I'm not sure exactly what they might be.
A silly question on a related issue, if I have a datablock loaded, and no object actually referencing it, does it hang about in memory? Or is there some logic that only loads the data if and when an object is referencing it? If I'm changing 'rooms' like I'm describing, is it necessary to delete the room specific datablocks as I change?
#2
Thanks for that. I had considered setting a flag to mark objects for deletion, and actually performing the deletion within an onSceneUpdate() callback. Obviously unnecessary for t2d objects, but it seems like it might still be needed to delete the non T2D ScriptObjects.
One further clarification on datablocks, now that I think I understand what you mean. If they are blocks of constants, then the actual loading of textures for usually occurs on object creation, not datablock creation?
Actually, I'm a bit confused now, as I'd assumed that the point of having an image texture referenced in a datablock was so that two seperate objects could reference the same version of the texture, and the texture gets rendered twice from one runtime instance, rather than from two seperately loaded instances at twice the memory overhead.
Or are you saying that T2D datablocks do load textures on datablock creation, but typically (as in TGE) they don't? If this is the case, than in my scenario, say I have 20 megs worth of data specific to a room and I want to unload it when I move to the next room and load the next room in, I want to delete the datablock as well as the objects?
-Mike
07/20/2005 (4:23 am)
Melv,Thanks for that. I had considered setting a flag to mark objects for deletion, and actually performing the deletion within an onSceneUpdate() callback. Obviously unnecessary for t2d objects, but it seems like it might still be needed to delete the non T2D ScriptObjects.
One further clarification on datablocks, now that I think I understand what you mean. If they are blocks of constants, then the actual loading of textures for usually occurs on object creation, not datablock creation?
Actually, I'm a bit confused now, as I'd assumed that the point of having an image texture referenced in a datablock was so that two seperate objects could reference the same version of the texture, and the texture gets rendered twice from one runtime instance, rather than from two seperately loaded instances at twice the memory overhead.
Or are you saying that T2D datablocks do load textures on datablock creation, but typically (as in TGE) they don't? If this is the case, than in my scenario, say I have 20 megs worth of data specific to a room and I want to unload it when I move to the next room and load the next room in, I want to delete the datablock as well as the objects?
-Mike
#3
When you define (execute) a T2D imagemap, it asks the internal texture-manager to give it the selected texture. If this hasn't been loaded, it will then load. If subsequent imagemap datablocks (or any other engine-objects) refer to the same texture then the texture-manager will not load the texture again but it will in-fact point to the same reused texture. You don't get duplicate (therefore wasted memory) as it's the same underlying texture.
Internally, the system creates another texture-handle that references the underlying texture so there's minimal overhead. When all references to this texture are removed, the texture is unloaded but all this is handled much lower at the texture-manager end of things.
T2Ds datablocks are all passive with the exception of the imageMap/Animation datablocks which seek/calculate external data (textures) immediately. Datablocks which configure T2D object class such as the fxStaticSpriteDatablock2D just contain values and are passive and are only referenced when a static-sprite is created and the datablock is specified for it.
This is why you *must* have the Canvas created before you define any imageMap datablocks because creating the Canvas initialises the underlying graphics-subsystem and imageMaps immediately access the specified texture.
To summarise; if you create 100 imageMap datablocks that reference a single texture, the texture will only be loaded once and all imageMaps will in-fact point to the same texture but this does allow you to specify different regions (frames) from a single texture.
Be aware that datablocks are not objects that are designed to be destroyed. Typically, they are loaded for the lifetime of your application but nothing is stopping you from destroying them so it is really up to you.
Good Luck,
- Melv.
07/20/2005 (7:30 am)
Michael,When you define (execute) a T2D imagemap, it asks the internal texture-manager to give it the selected texture. If this hasn't been loaded, it will then load. If subsequent imagemap datablocks (or any other engine-objects) refer to the same texture then the texture-manager will not load the texture again but it will in-fact point to the same reused texture. You don't get duplicate (therefore wasted memory) as it's the same underlying texture.
Internally, the system creates another texture-handle that references the underlying texture so there's minimal overhead. When all references to this texture are removed, the texture is unloaded but all this is handled much lower at the texture-manager end of things.
T2Ds datablocks are all passive with the exception of the imageMap/Animation datablocks which seek/calculate external data (textures) immediately. Datablocks which configure T2D object class such as the fxStaticSpriteDatablock2D just contain values and are passive and are only referenced when a static-sprite is created and the datablock is specified for it.
This is why you *must* have the Canvas created before you define any imageMap datablocks because creating the Canvas initialises the underlying graphics-subsystem and imageMaps immediately access the specified texture.
To summarise; if you create 100 imageMap datablocks that reference a single texture, the texture will only be loaded once and all imageMaps will in-fact point to the same texture but this does allow you to specify different regions (frames) from a single texture.
Be aware that datablocks are not objects that are designed to be destroyed. Typically, they are loaded for the lifetime of your application but nothing is stopping you from destroying them so it is really up to you.
Good Luck,
- Melv.
#4
Thanks again, that's invaluable information to have.
-Mike
07/20/2005 (7:54 am)
The reason I'm interested in loading/unloading of texture data is that our game calls for a series of unique rooms, each with its own unique background (at a maximum size of 3072x768,) with a few layers of parallax scrolling, as well as player sprite information, background animations etc etc... it's a lot of data to keep in memory at once, and I'm trying to be mindful of giving it a chance of running on less than bleeding edge machines. :)Thanks again, that's invaluable information to have.
-Mike
#5
Since T2D imagemaps load textures upon datablock definition, and datablocks are, as you say, not designed to be destroyed, is it the intent that games written in T2D should not have the ability to explicitly manage the loading and unloading of their texture data?
Again, I may have missed something, but it seems a restriction like this would automatically rule out T2D as a potential engine for non twitch/action games such as adventure games, edutainment titles, and graphical productivity applications. I can see many, many uses for T2D in these areas. But, as in my screen example above, the needs of this style of game tend towards being able to display many unique art resources on screen at once rather than taking everything from a master tile/sprite set.
If T2D is only intended to serve the needs of small physics based action games then that's fine, but not having a system for explicitly managing the loading and unloading of resource data really shuts T2D off from a huge wealth of potential uses.
07/21/2005 (3:47 am)
Quote:
Be aware that datablocks are not objects that are designed to be destroyed. Typically, they are loaded for the lifetime of your application but nothing is stopping you from destroying them so it is really up to you.
Since T2D imagemaps load textures upon datablock definition, and datablocks are, as you say, not designed to be destroyed, is it the intent that games written in T2D should not have the ability to explicitly manage the loading and unloading of their texture data?
Again, I may have missed something, but it seems a restriction like this would automatically rule out T2D as a potential engine for non twitch/action games such as adventure games, edutainment titles, and graphical productivity applications. I can see many, many uses for T2D in these areas. But, as in my screen example above, the needs of this style of game tend towards being able to display many unique art resources on screen at once rather than taking everything from a master tile/sprite set.
If T2D is only intended to serve the needs of small physics based action games then that's fine, but not having a system for explicitly managing the loading and unloading of resource data really shuts T2D off from a huge wealth of potential uses.
#6
We intend to provide much more control over the handling of texture resources and work is already progressing on that. Please don't misunderstand me as I'm describing what you've currently got, not what the final product will be. If I start describing what will be and not what is, then the inevitable question will be when; something that I can't give an answer to at the moment.
With that said, there are to be many changes to be made to the way that T2D handles textures, not least is the ability to automatically deal with textures, especially texture sizes and POT issues, appropriate to the underlying hardware as well as providing an interface for finer, more advanced control. The handling of textures is an extremely high priority.
- Melv.
07/21/2005 (7:03 am)
Michael,We intend to provide much more control over the handling of texture resources and work is already progressing on that. Please don't misunderstand me as I'm describing what you've currently got, not what the final product will be. If I start describing what will be and not what is, then the inevitable question will be when; something that I can't give an answer to at the moment.
With that said, there are to be many changes to be made to the way that T2D handles textures, not least is the ability to automatically deal with textures, especially texture sizes and POT issues, appropriate to the underlying hardware as well as providing an interface for finer, more advanced control. The handling of textures is an extremely high priority.
- Melv.
#7
07/21/2005 (8:59 am)
Thanks, Melv for taking the time to respond in depth to everything and for the information. That's very encouraging news
Associate Melv May
You mention that calling "safeDelete()" from within a callback causes problem but in-fact, "safeDelete()" is there for that very purpose. "SafeDelete" doesn't delete the object until prior to processing the next frame which is what makes it "safe". In other words, the deletion doesn't happen instantly. All it actually calls is the standard "delete" but it does so at a later time, that's all.
T2D objects can take control of this mechanism (in C++). All safe-deletes happen prior to the next frame starting but some objects such as the particle-effects can be configured to wait until a later time, particle-emitters can be configured to wait until all particles have been emitted for instance.
The trouble is that "safeDelete()" is only available for T2D objects. You can quite happily use the standard deletion mechanism but just be very careful doing so from callbacks that may rely on the object still being around when the callback finishes. This is why using "safeDelete()" is preferable all the time and not just from callbacks. Unfortunately, this isn't available yet for other objects from the underlying engine.
If you want all objects removed from the scene you can clear the scene but also get it to remove the objects as well.
Datablocks are created when you execute them in script. As to what they "load"; typically datablocks don't "load" anything but are just blocks of constant values that can be used for a common purpose. T2D datablocks like extend this idea by actually loading textures etc. Datablocks are always there and don't go in/out of scope or have reference-counting. The system typically relies on datablocks being always on but by system I'm obviously talking about objects that use datablocks.
Hope this helps,
- Melv.