Proper way to dispose Stage3D context’s content when recreating View3D many times

Software: Away3D 4.x

Synsim, Newbie
Posted: 09 January 2012 06:18 PM   Total Posts: 4

To put the question shortly, how can I dispose current View3D instance and replace it with the new one, (arbitrary number of times) so that all old one’s Context3D and Scene3D content is disposed and new one’s is clear and free?

I tried and failed to find solution, and now I want to find out is this a bug or I misuse Away3D somehow.

Obviously there’s a limit on number of any kind of resource, that is created through Context3D methods. For instance, I need a lot of CubeMap textures in my 3D simulation, so I decided to determine the exact limit number, and the plan was to recreate View3D instance and add all existing objects as I reach limit. That is, you can create any number (well, at least, a lot) of Away3D CubeMap instances, and dispose them with CubeMap’s dispose method, but it is all right as long as you don’t render them. Once the cubemap gets rendered, it’s stuck somewhere inside Context3D, and dispose call doesn’t affect this. I made a test application which creates new cubemap (it’s bitmapDatas are cloned from embedded ones), makes skybox out of it, adds it to the view’s scene and renders view. Then, it disposes old skybox and creates new one with fresh cubemap. So I discovered the limits, and that they are resolution-dependent: for 512x512x6 cubemap the limit is 28, for 1024x1024x6 it is 7. After the limit is reached you get exception from Context3D.createCubeTexture method when Away3D tries to render new skybox :
Error: Error #3691: Resource limit for this resource type exceeded.

By the way, apart from disposable skybox my test scene contains 1 point light, 1 plane primitive and 1 cube primitive, no textures. I keep references to all objects within my application class’ variables, to be able to add them to freshly created view’s scene.

So far, so good, but when it came to exchanging views, things got really nasty. At first I tried straightforward approach, like:

protected function recreateView():void
{
 removeChild
(_view);
 
_view = new View3D();
 
addChildAt(_view0);
 
_view.stage.addEventListener(Event.RESIZEonStageResizefalse0true);
 
 
addObjects(); 

It seemed to work, but only 3 times, because Away’s Stage3DManager has it’s own limitation on total Stage3D instances (4), and as you try to add fifth view, its method ‘getFreeStage3DProxy()’ throws an Exception:  ‘Error: Too many Stage3D instances used!
Anyway, we are able to create and render 28 cubemaps instead of 7.

Well, after this failure, I figured that actual Stage3D instance is not disposed along with old View3D, so I have to delete it manually somehow. So I found Stage3DProxy’s method dispose(), and as view keeps reference to its Stage3D, I call it like that:

protected function recreateView():void
{
 removeChild
(_view);
 
 var 
oldView:View3D _view// remember old view
 
 
_view = new View3D();
 
addChildAt(_view0);
 
_view.stage.addEventListener(Event.RESIZEonStageResizefalse0true);
  
 
addObjects(); 
 
oldView.stage3DProxy.dispose(); // dispose old view's Stage3D

Well, I guess (hope), it helped in some way. But now it generates exception after 2nd view exchange (and 14 cubemaps rendered sucessfully), this time trying to draw triangles of the plane primitive:
Error: Error #3600: No valid program set.
And here I’m out of ideas, and have to beg of an advice from people who understand Broomstick and Molehill guts better than me. If anyone is interested, I can attach my test project (it is in FlashDevelop format).

   

Synsim, Newbie
Posted: 16 January 2012 02:03 PM   Total Posts: 4   [ # 1 ]

Well, since no one answered my question yet, I’ll have to be the one.
Here’s what I found after couple of hours of intensive debugging. When you dispose current Stage3D instance like:

view.stage3DProxy.dispose(); 

the Stage3D is actually disposed (and videoadapter resources like textures and programs are freed) allright. But, since I don’t delete my objects (for I intend to add them to freshly created scene) their materials get messed up, because the references to Program3D instances in their materials aren’t updated, and still point to disposed programs. The remedy I made up for this problem reminds quick hack, but it works. Before rendering newly created view, (well, actually, right after adding objects to new scene), I iterate through all materials in my scene and change some common property (I use material’s “smooth” property), to trigger Program3D update. But there’s one more catch with this method, if you set material’s property to its current value, it does nothing at all (optimization!). So I have to set property twice to leave it eventually unchanged, like this:

protected function invalidateObjects():void  
{
 
var isSmooth:Boolean;

 
isSmooth samplePlane.material.smooth;
 
samplePlane.material.smooth = !isSmooth;
 
samplePlane.material.smooth isSmooth;

 
isSmooth sampleCube.material.smooth;
 
sampleCube.material.smooth = !isSmooth;
 
sampleCube.material.smooth isSmooth;

After this, the scene renders just fine. And you can create and render as many cubemaps as you want, beyond 128 mb limit, provided you don’t use them all at once, and properly delete old ones. Still, I’m not sure is there any bug to report in this ‘not-so-intuitive’ behavior. I found couple of related bugs in github tracker:
#11
#13
But those were closed long ago.

By the way, observing Flash Player memory usage graphs in Windows, makes me suspect that deleted cubemaps aren’t really garbage collected after dispose call until Stage3D is disposed. But, that’s the subject for totally different post, I guess. I attach sources of my test project, in case someone other will invade the misty realm of Away3D’s view/scene recreation.

 

File Attachments
LimitsTest.zip  (File Size: 517KB - Downloads: 315)
   
   

X

Away3D Forum

Member Login

Username

Password

Remember_me



X