* Fixed assertion error bug in NativeObjectManager.deleteAllObjects()

* Fixed ID collision bug in NativeObjectManager by introducing NativeObject.getUniqueId()

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10637 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
sha..RD 12 years ago
parent 1ac240e971
commit dec182b13f
  1. 5
      engine/src/android/com/jme3/audio/android/AndroidAudioData.java
  2. 4
      engine/src/core/com/jme3/audio/AudioBuffer.java
  3. 5
      engine/src/core/com/jme3/audio/AudioStream.java
  4. 4
      engine/src/core/com/jme3/audio/LowPassFilter.java
  5. 5
      engine/src/core/com/jme3/scene/VertexBuffer.java
  6. 9
      engine/src/core/com/jme3/shader/Shader.java
  7. 5
      engine/src/core/com/jme3/texture/FrameBuffer.java
  8. 5
      engine/src/core/com/jme3/texture/Image.java
  9. 19
      engine/src/core/com/jme3/util/NativeObject.java
  10. 69
      engine/src/core/com/jme3/util/NativeObjectManager.java

@ -59,4 +59,9 @@ public class AndroidAudioData extends AudioData {
public NativeObject createDestructableClone() { public NativeObject createDestructableClone() {
return new AndroidAudioData(id); return new AndroidAudioData(id);
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_AUDIOBUFFER << 32) | ((long)id);
}
} }

@ -120,4 +120,8 @@ public class AudioBuffer extends AudioData {
return new AudioBuffer(id); return new AudioBuffer(id);
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_AUDIOBUFFER << 32) | ((long)id);
}
} }

@ -199,5 +199,8 @@ public class AudioStream extends AudioData implements Closeable{
} }
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_AUDIOSTREAM << 32) | ((long)ids[0]);
}
} }

@ -96,4 +96,8 @@ public class LowPassFilter extends Filter {
return new LowPassFilter(id); return new LowPassFilter(id);
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_FILTER << 32) | ((long)id);
}
} }

@ -1004,6 +1004,11 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
return new VertexBuffer(id); return new VertexBuffer(id);
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_VERTEXBUFFER << 32) | ((long)id);
}
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);
oc.write(components, "components", 0); oc.write(components, "components", 0);

@ -155,6 +155,11 @@ public final class Shader extends NativeObject {
return defines; return defines;
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_SHADERSOURCE << 32) | ((long)id);
}
@Override @Override
public String toString(){ public String toString(){
String nameTxt = ""; String nameTxt = "";
@ -322,4 +327,8 @@ public final class Shader extends NativeObject {
return new Shader(this); return new Shader(this);
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_SHADER << 32) | ((long)id);
}
} }

@ -501,4 +501,9 @@ public class FrameBuffer extends NativeObject {
public NativeObject createDestructableClone(){ public NativeObject createDestructableClone(){
return new FrameBuffer(this); return new FrameBuffer(this);
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_FRAMEBUFFER << 32) | ((long)id);
}
} }

@ -393,6 +393,11 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
return new Image(id); return new Image(id);
} }
@Override
public long getUniqueId() {
return ((long)OBJTYPE_TEXTURE << 32) | ((long)id);
}
/** /**
* @return A shallow clone of this image. The data is not cloned. * @return A shallow clone of this image. The data is not cloned.
*/ */

@ -45,6 +45,15 @@ public abstract class NativeObject implements Cloneable {
public static final int INVALID_ID = -1; public static final int INVALID_ID = -1;
protected static final int OBJTYPE_VERTEXBUFFER = 1,
OBJTYPE_TEXTURE = 2,
OBJTYPE_FRAMEBUFFER = 3,
OBJTYPE_SHADER = 4,
OBJTYPE_SHADERSOURCE = 5,
OBJTYPE_AUDIOBUFFER = 6,
OBJTYPE_AUDIOSTREAM = 7,
OBJTYPE_FILTER = 8;
/** /**
* The object manager to which this NativeObject is registered to. * The object manager to which this NativeObject is registered to.
*/ */
@ -111,7 +120,7 @@ public abstract class NativeObject implements Cloneable {
public int getId(){ public int getId(){
return id; return id;
} }
/** /**
* Internal use only. Indicates that the object has changed * Internal use only. Indicates that the object has changed
* and its state needs to be updated. * and its state needs to be updated.
@ -199,6 +208,14 @@ public abstract class NativeObject implements Cloneable {
*/ */
public abstract NativeObject createDestructableClone(); public abstract NativeObject createDestructableClone();
/**
* Returns a unique ID for this NativeObject. No other NativeObject shall
* have the same ID.
*
* @return unique ID for this NativeObject.
*/
public abstract long getUniqueId();
/** /**
* Reclaims native resources used by this NativeObject. * Reclaims native resources used by this NativeObject.
* It should be safe to call this method or even use the object * It should be safe to call this method or even use the object

@ -37,7 +37,7 @@ import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Queue; import java.util.HashMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -74,7 +74,7 @@ public class NativeObjectManager {
/** /**
* List of currently active GLObjects. * List of currently active GLObjects.
*/ */
private IntMap<NativeObjectRef> refMap = new IntMap<NativeObjectRef>(); private HashMap<Long, NativeObjectRef> refMap = new HashMap<Long, NativeObjectRef>();
/** /**
* List of real objects requested by user for deletion. * List of real objects requested by user for deletion.
@ -91,7 +91,8 @@ public class NativeObjectManager {
assert obj.handleRef != null; assert obj.handleRef != null;
this.realObj = new WeakReference<NativeObject>(obj); this.realObj = new WeakReference<NativeObject>(obj);
this.objClone = obj.createDestructableClone(); this.objClone = obj.createDestructableClone();
assert objClone.getId() == obj.getId();
} }
} }
@ -104,7 +105,7 @@ public class NativeObjectManager {
} }
NativeObjectRef ref = new NativeObjectRef(refQueue, obj); NativeObjectRef ref = new NativeObjectRef(refQueue, obj);
refMap.put(obj.getId(), ref); refMap.put(obj.getUniqueId(), ref);
obj.setNativeObjectManager(this); obj.setNativeObjectManager(this);
@ -125,30 +126,34 @@ public class NativeObjectManager {
assert realObj == null || obj.getId() == realObj.getId(); assert realObj == null || obj.getId() == realObj.getId();
if (deleteGL && obj.getId() > 0) { if (deleteGL) {
// Unregister it from cleanup list. if (obj.getId() <= 0) {
NativeObjectRef ref2 = refMap.remove(obj.getId()); logger.log(Level.WARNING, "Object already deleted: {0}", obj.getClass().getSimpleName() + "/" + obj.getId());
if (ref2 == null) { } else {
throw new IllegalArgumentException("This NativeObject is not " + // Unregister it from cleanup list.
"registered in this NativeObjectManager"); NativeObjectRef ref2 = refMap.remove(obj.getUniqueId());
} if (ref2 == null) {
throw new IllegalArgumentException("This NativeObject is not " +
assert ref == null || ref == ref2; "registered in this NativeObjectManager");
}
int id = obj.getId();
assert ref == null || ref == ref2;
// Delete object from the GL driver
obj.deleteObject(rendererObject); int id = obj.getId();
assert obj.getId() == NativeObject.INVALID_ID;
// Delete object from the GL driver
if (logger.isLoggable(Level.FINEST)) { obj.deleteObject(rendererObject);
logger.log(Level.FINEST, "Deleted: {0}", obj.getClass().getSimpleName() + "/" + id); assert obj.getId() == NativeObject.INVALID_ID;
}
if (logger.isLoggable(Level.FINEST)) {
if (realObj != null){ logger.log(Level.FINEST, "Deleted: {0}", obj.getClass().getSimpleName() + "/" + id);
// Note: make sure to reset them as well }
// They may get used in a new renderer in the future
realObj.resetObject(); if (realObj != null){
// Note: make sure to reset them as well
// They may get used in a new renderer in the future
realObj.resetObject();
}
} }
} }
if (deleteBufs && UNSAFE && realObj != null) { if (deleteBufs && UNSAFE && realObj != null) {
@ -194,8 +199,8 @@ public class NativeObjectManager {
*/ */
public void deleteAllObjects(Object rendererObject){ public void deleteAllObjects(Object rendererObject){
deleteUnused(rendererObject); deleteUnused(rendererObject);
for (IntMap.Entry<NativeObjectRef> entry : refMap) { ArrayList<NativeObjectRef> refMapCopy = new ArrayList<NativeObjectRef>(refMap.values());
NativeObjectRef ref = entry.getValue(); for (NativeObjectRef ref : refMapCopy) {
deleteNativeObject(rendererObject, ref.objClone, ref, true, false); deleteNativeObject(rendererObject, ref.objClone, ref, true, false);
} }
assert refMap.size() == 0; assert refMap.size() == 0;
@ -219,9 +224,9 @@ public class NativeObjectManager {
* This is typically called when the context is restarted. * This is typically called when the context is restarted.
*/ */
public void resetObjects(){ public void resetObjects(){
for (IntMap.Entry<NativeObjectRef> entry : refMap) { for (NativeObjectRef ref : refMap.values()) {
// Must use the real object here, for this to be effective. // Must use the real object here, for this to be effective.
NativeObject realObj = entry.getValue().realObj.get(); NativeObject realObj = ref.realObj.get();
if (realObj == null) { if (realObj == null) {
continue; continue;
} }

Loading…
Cancel
Save