Project

General

Profile

« Previous | Next » 

Revision c204c69d

Added by Leszek Koltunski about 7 years ago

New, cleaner way to create/destroy DistortedSurfaces.

Serious regression in StarWars (crashes!). Looks like the Node's internal FBO is being deleted and not re-created in time.

View differences:

src/main/java/org/distorted/library/DistortedNode.java
27 27
///////////////////////////////////////////////////////////////////////////////////////////////////
28 28
/**
29 29
 * Class which represents a Node in a Tree of (InputSurface,Mesh,Effects) triplets.
30
 *  
30
 * <p>
31 31
 * Having organized such sets into a Tree, we can then render any Node to any OutputSurface.
32 32
 * That recursively renders the set held in the Node and all its children.
33
 * <p>
34
 * The class takes special care to only render identical sub-trees once. Each Node holds a reference
35
 * to sub-class 'NodeData'. Two identical sub-trees attached at different points of the main tree
36
 * will point to the same NodeData; only the first of this is rendered (when mData.numRendered==0).
33 37
 */
34
public class DistortedNode
38
public class DistortedNode implements DistortedAttacheable
35 39
  {
36 40
  private static HashMap<ArrayList<Long>,NodeData> mMapNodeID = new HashMap<>();
37 41
  private static long mNextNodeID =0;
......
41 45
  private DistortedInputSurface mSurface;
42 46
  private NodeData mData;
43 47

  
44
  private DistortedNode mParent;
45 48
  private ArrayList<DistortedNode> mChildren;
46 49
  private int[] mNumChildren;  // ==mChildren.length(), but we only create mChildren if the first one gets added
47 50

  
......
58 61
      numPointingNodes= 1;
59 62
      numRendered     = 0;
60 63
      mFBO            = null;
61

  
62
      android.util.Log.e("DistortedNode", "new NodeData");
63 64
      }
64 65
    }
65 66
 
......
71 72
    mMapNodeID.clear();
72 73
    }
73 74

  
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75
// tree isomorphism
76
  
77
  private void RecomputeNodeID(ArrayList<Long> prev)
78
    {
79
    ArrayList<Long> curr = generateIDList();
80
     
81
    if( mParent==null )
82
      {
83
      adjustNodeData(prev,curr);
84
      }
85
    else
86
      {
87
      ArrayList<Long> parentPrev = mParent.generateIDList();
88
      adjustNodeData(prev,curr);
89
      mParent.RecomputeNodeID(parentPrev);
90
      }
91
    }
92

  
93 75
///////////////////////////////////////////////////////////////////////////////////////////////////
94 76

  
95 77
  private ArrayList<Long> generateIDList()
......
108 90
    return ret;
109 91
    }
110 92

  
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112

  
113
  private void adjustNodeData(ArrayList<Long> oldList, ArrayList<Long> newList)
114
    {
115
    boolean otherNodesPoint = (mData.numPointingNodes>1);
116

  
117
    if( otherNodesPoint ) mData.numPointingNodes--;
118
    else                  mMapNodeID.remove(oldList);
119

  
120
    NodeData newData = mMapNodeID.get(newList);
121
    
122
    if( newData==null )
123
      {
124
      if( otherNodesPoint )  mData = new NodeData(++mNextNodeID);
125
      else                   mData.ID = ++mNextNodeID;  // numPointingNodes must be 1 already
126

  
127
      if( newList.size()>1 )
128
        {
129
        if( mData.mFBO ==null )
130
          {
131
          android.util.Log.e("DistortedNode", "creating a new FBO");
132

  
133
          mData.mFBO = new DistortedFramebuffer(mSurface.getWidth(), mSurface.getHeight());
134
          }
135
        }
136
      else
137
        {
138
        if( mData.mFBO !=null )
139
          {
140
          android.util.Log.e("DistortedNode", "marking FBO for deletion and setting it to NULL");
141

  
142
          mData.mFBO.markForDeletion();
143
          mData.mFBO = null;
144
          }
145
        else
146
          {
147
          android.util.Log.e("DistortedNode", "adjustNodeData: impossible situation??");
148
          }
149
        }
150

  
151
      mMapNodeID.put(newList, mData);
152
      }
153
    else
154
      {
155
      newData.numPointingNodes++;
156
      mData = newData;
157
      }
158
    }
159

  
160 93
///////////////////////////////////////////////////////////////////////////////////////////////////  
161 94
// this will be called on startup and every time OpenGL context has been lost
162 95

  
......
174 107

  
175 108
///////////////////////////////////////////////////////////////////////////////////////////////////
176 109
// Debug - print all the Node IDs
177
/*
110

  
178 111
  void debug(int depth)
179 112
    {
180 113
    String tmp="";
181 114
    int i;
182 115

  
183 116
    for(i=0; i<depth; i++) tmp +="   ";
184
    tmp += (mData.ID+" (nodes: "+mData.numPointingNodes+")");
117
    tmp += ("NodeID="+mData.ID+" (nodes pointing: "+mData.numPointingNodes+" surfaceID="+mSurface.getID()+")");
185 118

  
186 119
    android.util.Log.e("NODE", tmp);
187 120

  
......
199 132
    for(ArrayList<Long> key: mMapNodeID.keySet())
200 133
      {
201 134
      tmp = mMapNodeID.get(key);
135
      android.util.Log.e("NODE", "NodeID: "+tmp.ID+" <-- "+key);
136
      }
137
    }
138

  
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

  
141
  void treeIsomorphism()
142
    {
143
    android.util.Log.e("NODE", "begin treeIso for Node Surface ID="+mSurface.getID());
144
    debug(0);
145
    debugMap();
146
    android.util.Log.e("NODE", "begin treeIso for Node Surface ID="+mSurface.getID());
147

  
148
    ArrayList<Long> oldList = generateIDList();
149

  
150
    for(int i=0; i<mNumChildren[0]; i++)
151
      {
152
      mChildren.get(i).treeIsomorphism();
153
      }
154

  
155
    ArrayList<Long> newList = generateIDList();
156
    NodeData newData = mMapNodeID.get(newList);
157

  
158
    if( newData==null )
159
      {
160
      android.util.Log.d("NODE", "  inserted newData to map, newList="+newList);
161

  
162

  
163
      newData = new NodeData(++mNextNodeID);
164
      mMapNodeID.put(newList,newData);
165
      debugMap();
166
      }
167
    else if( newData.ID != mData.ID )
168
      {
169
      newData.numPointingNodes++;
170
      }
171

  
172
    if( newData.ID != mData.ID )
173
      {
174
      boolean fboUsed = false;
175

  
176
      if( mNumChildren[0]>0 && newData.mFBO==null )
177
        {
178
        if( mData.mFBO!=null )
179
          {
180
          newData.mFBO = mData.mFBO;
181
          fboUsed = true;
182
          }
183
        else
184
          {
185
          newData.mFBO = new DistortedFramebuffer(mSurface.getWidth(),mSurface.getHeight());
186
          }
187
        }
188
      if( mNumChildren[0]==0 && newData.mFBO!=null )
189
        {
190
        newData.mFBO.markForDeletion();
191
        newData.mFBO = null;
192
        }
193

  
194
      if( --mData.numPointingNodes==0 )
195
        {
196
        android.util.Log.d("NODE", "  removed oldData to map, oldList="+oldList);
197

  
202 198

  
203
      android.util.Log.e("NODE", "key="+key+" NodeID: "+tmp.ID);
199
        mMapNodeID.remove(oldList);
200
        debugMap();
201

  
202
        if( !fboUsed && mData.mFBO!=null )
203
          {
204
          mData.mFBO.markForDeletion();
205
          mData.mFBO = null;
206
          }
207
        }
208

  
209
      mData = newData;
204 210
      }
211

  
212
    android.util.Log.e("NODE", "end treeIso for Node SurfaceID="+mSurface.getID()+" newList="+newList);
213
    debug(0);
214
    debugMap();
215
    android.util.Log.e("NODE", "end treeIso for Node SurfaceID="+mSurface.getID()+" newList="+newList);
205 216
    }
206
*/
217

  
207 218
///////////////////////////////////////////////////////////////////////////////////////////////////
208 219

  
209 220
  void drawRecursive(long currTime, DistortedOutputSurface surface)
......
256 267
    mSurface       = surface;
257 268
    mEffects       = effects;
258 269
    mMesh          = mesh;
259
    mParent        = null;
260 270
    mChildren      = null;
261 271
    mNumChildren   = new int[1];
262 272
    mNumChildren[0]= 0;
......
289 299
 */
290 300
  public DistortedNode(DistortedNode node, int flags)
291 301
    {
292
    mParent = null;
293 302
    mEffects= new DistortedEffects(node.mEffects,flags);
294 303
    mMesh = node.mMesh;
295 304

  
......
314 323
      }
315 324
    if( (flags & Distorted.CLONE_CHILDREN) != 0 )
316 325
      {
326
      if( node.mChildren==null )     // do NOT copy over the NULL!
327
        {
328
        node.mChildren = new ArrayList<>(2);
329
        }
330

  
317 331
      mChildren = node.mChildren;
318 332
      mNumChildren = node.mNumChildren;
319 333
      }
......
338 352
      mMapNodeID.put(list, mData);
339 353
      }
340 354
    }
341
  
355

  
342 356
///////////////////////////////////////////////////////////////////////////////////////////////////
343 357
/**
344 358
 * Adds a new child to the last position in the list of our Node's children.
345
 * 
359
 * <p>
360
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
361
 * DistortedAttachDeamon (by calling attachNow())
362
 *
346 363
 * @param node The new Node to add.
347 364
 */
348
  public synchronized void attach(DistortedNode node)
365
  public void attach(DistortedNode node)
349 366
    {
350
    ArrayList<Long> prev = generateIDList(); 
351
   
352
    if( mChildren==null ) mChildren = new ArrayList<>(2);
353

  
354
    android.util.Log.e("DistortedNode", "ATTACH1");
355

  
356

  
357
    node.mParent = this;
358
    mChildren.add(node);
359
    mNumChildren[0]++;
360
     
361
    RecomputeNodeID(prev);
367
    DistortedAttachDaemon.attach(this,node);
362 368
    }
363
   
369

  
364 370
///////////////////////////////////////////////////////////////////////////////////////////////////
365 371
/**
366 372
 * Adds a new child to the last position in the list of our Node's children.
367
 * 
373
 * <p>
374
 * We cannot do this mid-render - actual attachment will be done just before the next render, by the
375
 * DistortedAttachDeamon (by calling attachNow())
376
 *
368 377
 * @param surface InputSurface to initialize our child Node with.
369 378
 * @param effects DistortedEffects to initialize our child Node with.
370 379
 * @param mesh MeshObject to initialize our child Node with.
371 380
 * @return the newly constructed child Node, or null if we couldn't allocate resources.
372 381
 */
373
  public synchronized DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
382
  public DistortedNode attach(DistortedInputSurface surface, DistortedEffects effects, MeshObject mesh)
374 383
    {
375
    ArrayList<Long> prev = generateIDList(); 
376

  
377
    android.util.Log.e("DistortedNode", "ATTACH2");
384
    DistortedNode node = new DistortedNode(surface,effects,mesh);
385
    DistortedAttachDaemon.attach(this,node);
386
    return node;
387
    }
378 388

  
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390
/**
391
 * This is not really part of the public API. Has to be public only because it is a part of the
392
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
393
 * Java has no multiple inheritance.
394
 *
395
 * @param node The new Node to add.
396
 */
397
  public void attachNow(DistortedNode node)
398
    {
379 399
    if( mChildren==null ) mChildren = new ArrayList<>(2);
380
    DistortedNode node = new DistortedNode(surface,effects,mesh);
381
    node.mParent = this;
400

  
382 401
    mChildren.add(node);
383 402
    mNumChildren[0]++;
384
   
385
    RecomputeNodeID(prev);
386

  
387
    return node;
388 403
    }
389
  
404

  
390 405
///////////////////////////////////////////////////////////////////////////////////////////////////
391 406
/**
392 407
 * Removes the first occurrence of a specified child from the list of children of our Node.
393
 * 
408
 * <p>
409
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
410
 * DistortedAttachDeamon (by calling detachNow())
411
 *
394 412
 * @param node The Node to remove.
395
 * @return <code>true</code> if the child was successfully removed.
396 413
 */
397
  public synchronized boolean detach(DistortedNode node)
414
  public void detach(DistortedNode node)
398 415
    {
399
    if( mNumChildren[0]>0 )
400
      {
401
      ArrayList<Long> prev = generateIDList();  
402
         
403
      if( mChildren.remove(node) )
404
        {
405
android.util.Log.e("DistortedNode", "DETACH1");
406

  
407
        node.mParent = null;
408
        mNumChildren[0]--;
409
     
410
        RecomputeNodeID(prev);
411
     
412
        return true;
413
        }
414
      }
415
   
416
    return false;
416
    DistortedAttachDaemon.detach(this,node);
417 417
    }
418 418

  
419 419
///////////////////////////////////////////////////////////////////////////////////////////////////
......
422 422
 * <p>
423 423
 * A bit questionable method as there can be many different Nodes attached as children, some
424 424
 * of them having the same Effects but - for instance - different Mesh. Use with care.
425
 * <p>
426
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
427
 * DistortedAttachDeamon (by calling detachNow())
425 428
 *
426 429
 * @param effects DistortedEffects to remove.
427
 * @return <code>true</code> if the child was successfully removed.
428 430
 */
429
  public synchronized boolean detach(DistortedEffects effects)
431
  public void detach(DistortedEffects effects)
430 432
    {
431 433
    long id = effects.getID();
432 434
    DistortedNode node;
......
437 439

  
438 440
      if( node.mEffects.getID()==id )
439 441
        {
440
android.util.Log.e("DistortedNode", "DETACH2");
441

  
442

  
443
        ArrayList<Long> prev = generateIDList();
444

  
445
        node.mParent = null;
446
        mChildren.remove(i);
447
        mNumChildren[0]--;
448

  
449
        RecomputeNodeID(prev);
450

  
451
        return true;
442
        DistortedAttachDaemon.detach(this,node);
443
        break;
452 444
        }
453 445
      }
454

  
455
    return false;
456 446
    }
457 447

  
458 448
///////////////////////////////////////////////////////////////////////////////////////////////////
459 449
/**
460
 * Removes all children Nodes.
450
 * This is not really part of the public API. Has to be public only because it is a part of the
451
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
452
 * Java has no multiple inheritance.
453
 *
454
 * @param node The Node to remove.
461 455
 */
462
  public synchronized void detachAll()
456
  public void detachNow(DistortedNode node)
463 457
    {
464
    for(int i=0; i<mNumChildren[0]; i++)
458
    if( mNumChildren[0]>0 && mChildren.remove(node) )
465 459
      {
466
      mChildren.get(i).mParent = null;
460
      mNumChildren[0]--;
467 461
      }
468
   
462
    }
463

  
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465
/**
466
 * Removes all children Nodes.
467
 * <p>
468
 * We cannot do this mid-render - actual detachment will be done just before the next render, by the
469
 * DistortedAttachDeamon (by calling detachAllNow())
470
 */
471
  public void detachAll()
472
    {
473
    DistortedAttachDaemon.detachAll(this);
474
    }
475

  
476
///////////////////////////////////////////////////////////////////////////////////////////////////
477
/**
478
 * This is not really part of the public API. Has to be public only because it is a part of the
479
 * DistortedAttacheable interface, which should really be a class that we extend here instead but
480
 * Java has no multiple inheritance.
481
 */
482
  public void detachAllNow()
483
    {
469 484
    if( mNumChildren[0]>0 )
470 485
      {
471
      ArrayList<Long> prev = generateIDList();  
472
      
473 486
      mNumChildren[0] = 0;
474 487
      mChildren.clear();
475
      RecomputeNodeID(prev);
476 488
      }
477 489
    }
478 490

  

Also available in: Unified diff