• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Keine Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Main repository of MikuMikuStudio


Commit MetaInfo

Revisionb698ece235f9dfec82d7a82383259eacb8d1007a (tree)
Zeit2013-05-16 09:53:58
AutorshadowisLORD <shadowisLORD@75d0...>
CommitershadowisLORD

Log Message

  • Add NativeObject.dispose() which deletes the object from GL driver, and if UNSAFE=true, also native buffers.
  • Rename NativeObjectManager.registerForCleanup() -> registerObject() so that its not confused with enqueueUnusedObject()

git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@10618 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

Ändern Zusammenfassung

Diff

--- a/engine/src/android/com/jme3/audio/android/AndroidOpenALSoftAudioRenderer.java
+++ b/engine/src/android/com/jme3/audio/android/AndroidOpenALSoftAudioRenderer.java
@@ -296,7 +296,7 @@ public class AndroidOpenALSoftAudioRenderer implements AndroidAudioRenderer, Run
296296 id = ib.get(0);
297297 f.setId(id);
298298
299- objManager.registerForCleanup(f);
299+ objManager.registerObject(f);
300300 }
301301
302302 if (f instanceof LowPassFilter) {
@@ -1212,7 +1212,7 @@ public class AndroidOpenALSoftAudioRenderer implements AndroidAudioRenderer, Run
12121212 id = ib.get(0);
12131213 ab.setId(id);
12141214
1215- objManager.registerForCleanup(ab);
1215+ objManager.registerObject(ab);
12161216 }
12171217
12181218 ab.getData().clear();
--- a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
+++ b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
@@ -942,7 +942,7 @@ public class OGLESShaderRenderer implements Renderer {
942942 shader.clearUpdateNeeded();
943943 if (needRegister) {
944944 // Register shader for clean up if it was created in this method.
945- objManager.registerForCleanup(shader);
945+ objManager.registerObject(shader);
946946 statistics.onNewShader();
947947 } else {
948948 // OpenGL spec: uniform locations may change after re-link
@@ -1318,7 +1318,7 @@ public class OGLESShaderRenderer implements Renderer {
13181318
13191319 id = intBuf1.get(0);
13201320 fb.setId(id);
1321- objManager.registerForCleanup(fb);
1321+ objManager.registerObject(fb);
13221322
13231323 statistics.onNewFrameBuffer();
13241324 }
@@ -1673,7 +1673,7 @@ public class OGLESShaderRenderer implements Renderer {
16731673
16741674 texId = intBuf1.get(0);
16751675 img.setId(texId);
1676- objManager.registerForCleanup(img);
1676+ objManager.registerObject(img);
16771677
16781678 statistics.onNewTexture();
16791679 }
@@ -1880,7 +1880,7 @@ public class OGLESShaderRenderer implements Renderer {
18801880
18811881 bufId = intBuf1.get(0);
18821882 vb.setId(bufId);
1883- objManager.registerForCleanup(vb);
1883+ objManager.registerObject(vb);
18841884
18851885 created = true;
18861886 }
@@ -2252,14 +2252,9 @@ public class OGLESShaderRenderer implements Renderer {
22522252
22532253 /**
22542254 * renderMeshVertexArray renders a mesh using vertex arrays
2255- * @param mesh
2256- * @param lod
2257- * @param count
22582255 */
22592256 private void renderMeshVertexArray(Mesh mesh, int lod, int count) {
2260- // IntMap<VertexBuffer> buffers = mesh.getBuffers();
2261- for (VertexBuffer vb : mesh.getBufferList().getArray()){
2262-
2257+ for (VertexBuffer vb : mesh.getBufferList().getArray()) {
22632258 if (vb.getBufferType() == Type.InterleavedData
22642259 || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
22652260 || vb.getBufferType() == Type.Index) {
@@ -2306,7 +2301,6 @@ public class OGLESShaderRenderer implements Renderer {
23062301 indices = mesh.getBuffer(Type.Index);// buffers.get(Type.Index.ordinal());
23072302 }
23082303 for (VertexBuffer vb : mesh.getBufferList().getArray()){
2309-
23102304 if (vb.getBufferType() == Type.InterleavedData
23112305 || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
23122306 || vb.getBufferType() == Type.Index) {
--- a/engine/src/core/com/jme3/util/NativeObject.java
+++ b/engine/src/core/com/jme3/util/NativeObject.java
@@ -46,6 +46,11 @@ public abstract class NativeObject implements Cloneable {
4646 public static final int INVALID_ID = -1;
4747
4848 /**
49+ * The object manager to which this NativeObject is registered to.
50+ */
51+ protected NativeObjectManager objectManager = null;
52+
53+ /**
4954 * The ID of the object, usually depends on its type.
5055 * Typically returned from calls like glGenTextures, glGenBuffers, etc.
5156 */
@@ -82,9 +87,14 @@ public abstract class NativeObject implements Cloneable {
8287 this.id = id;
8388 }
8489
90+ void setNativeObjectManager(NativeObjectManager objectManager) {
91+ this.objectManager = objectManager;
92+ }
93+
8594 /**
86- * Sets the ID of the GLObject. This method is used in Renderer and must
95+ * Sets the ID of the NativeObject. This method is used in Renderer and must
8796 * not be called by the user.
97+ *
8898 * @param id The ID to set
8999 */
90100 public void setId(int id){
@@ -138,6 +148,7 @@ public abstract class NativeObject implements Cloneable {
138148 try {
139149 NativeObject obj = (NativeObject) super.clone();
140150 obj.handleRef = new Object();
151+ obj.objectManager = null;
141152 obj.id = INVALID_ID;
142153 obj.updateNeeded = true;
143154 return obj;
@@ -187,4 +198,17 @@ public abstract class NativeObject implements Cloneable {
187198 * should be functional for this object.
188199 */
189200 public abstract NativeObject createDestructableClone();
201+
202+ /**
203+ * Reclaims native resources used by this NativeObject.
204+ * It should be safe to call this method or even use the object
205+ * after it has been reclaimed, unless {@link NativeObjectManager#UNSAFE} is
206+ * set to true, in that case native buffers are also reclaimed which may
207+ * introduce instability.
208+ */
209+ public void dispose() {
210+ if (objectManager != null) {
211+ objectManager.markUnusedObject(this);
212+ }
213+ }
190214 }
--- a/engine/src/core/com/jme3/util/NativeObjectManager.java
+++ b/engine/src/core/com/jme3/util/NativeObjectManager.java
@@ -31,11 +31,13 @@
3131 */
3232 package com.jme3.util;
3333
34-import com.jme3.scene.VertexBuffer;
34+import com.jme3.renderer.Renderer;
3535 import java.lang.ref.PhantomReference;
3636 import java.lang.ref.ReferenceQueue;
3737 import java.lang.ref.WeakReference;
38-import java.util.HashSet;
38+import java.util.ArrayDeque;
39+import java.util.ArrayList;
40+import java.util.Queue;
3941 import java.util.logging.Level;
4042 import java.util.logging.Logger;
4143
@@ -50,7 +52,14 @@ import java.util.logging.Logger;
5052 public class NativeObjectManager {
5153
5254 private static final Logger logger = Logger.getLogger(NativeObjectManager.class.getName());
53-
55+
56+ /**
57+ * Set to <code>true</code> to enable deletion of native buffers together with GL objects
58+ * when requested. Note that usage of object after deletion could cause undefined results
59+ * or native crashes, therefore by default this is set to <code>false</code>.
60+ */
61+ public static boolean UNSAFE = false;
62+
5463 /**
5564 * The maximum number of objects that should be removed per frame.
5665 * If the limit is reached, no more objects will be removed for that frame.
@@ -58,23 +67,26 @@ public class NativeObjectManager {
5867 private static final int MAX_REMOVES_PER_FRAME = 100;
5968
6069 /**
61- * The queue will receive notifications of {@link NativeObject}s which
62- * are no longer referenced.
70+ * Reference queue for {@link NativeObjectRef native object references}.
6371 */
6472 private ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
6573
6674 /**
6775 * List of currently active GLObjects.
6876 */
69- private HashSet<NativeObjectRef> refList
70- = new HashSet<NativeObjectRef>();
77+ private IntMap<NativeObjectRef> refMap = new IntMap<NativeObjectRef>();
78+
79+ /**
80+ * List of real objects requested by user for deletion.
81+ */
82+ private ArrayDeque<NativeObject> userDeletionQueue = new ArrayDeque<NativeObject>();
7183
72- private class NativeObjectRef extends PhantomReference<Object>{
84+ private static class NativeObjectRef extends PhantomReference<Object> {
7385
7486 private NativeObject objClone;
7587 private WeakReference<NativeObject> realObj;
7688
77- public NativeObjectRef(NativeObject obj){
89+ public NativeObjectRef(ReferenceQueue<Object> refQueue, NativeObject obj){
7890 super(obj.handleRef, refQueue);
7991 assert obj.handleRef != null;
8092
@@ -84,18 +96,68 @@ public class NativeObjectManager {
8496 }
8597
8698 /**
87- * Register a GLObject with the manager.
99+ * (Internal use only) Register a <code>NativeObject</code> with the manager.
88100 */
89- public void registerForCleanup(NativeObject obj){
90- NativeObjectRef ref = new NativeObjectRef(obj);
91- refList.add(ref);
101+ public void registerObject(NativeObject obj) {
102+ if (obj.getId() <= 0) {
103+ throw new IllegalArgumentException("object id must be greater than zero");
104+ }
105+
106+ NativeObjectRef ref = new NativeObjectRef(refQueue, obj);
107+ refMap.put(obj.getId(), ref);
108+
109+ obj.setNativeObjectManager(this);
110+
92111 if (logger.isLoggable(Level.FINEST)) {
93112 logger.log(Level.FINEST, "Registered: {0}", new String[]{obj.toString()});
94113 }
95114 }
115+
116+ private void deleteNativeObject(Object rendererObject, NativeObject obj, NativeObjectRef ref,
117+ boolean deleteGL, boolean deleteBufs) {
118+ assert rendererObject != null;
119+
120+ // "obj" is considered the real object (with buffers and everything else)
121+ // if "ref" is null.
122+ NativeObject realObj = ref != null ?
123+ ref.realObj.get() :
124+ obj;
125+
126+ assert realObj == null || obj.getId() == realObj.getId();
127+
128+ if (deleteGL && obj.getId() > 0) {
129+ // Unregister it from cleanup list.
130+ NativeObjectRef ref2 = refMap.remove(obj.getId());
131+ if (ref2 == null) {
132+ throw new IllegalArgumentException("This NativeObject is not " +
133+ "registered in this NativeObjectManager");
134+ }
96135
136+ assert ref == null || ref == ref2;
137+
138+ // Delete object from the GL driver
139+ obj.deleteObject(rendererObject);
140+ assert obj.getId() == NativeObject.INVALID_ID;
141+
142+ if (logger.isLoggable(Level.FINEST)) {
143+ logger.log(Level.FINEST, "Deleted: {0}", obj);
144+ }
145+
146+ if (realObj != null){
147+ // Note: make sure to reset them as well
148+ // They may get used in a new renderer in the future
149+ realObj.resetObject();
150+ }
151+ }
152+ if (deleteBufs && UNSAFE && realObj != null) {
153+ // Only the real object has native buffers.
154+ // The destructable clone has nothing and cannot be used in this case.
155+ realObj.deleteNativeBuffersInternal();
156+ }
157+ }
158+
97159 /**
98- * Deletes unused NativeObjects.
160+ * (Internal use only) Deletes unused NativeObjects.
99161 * Will delete at most {@link #MAX_REMOVES_PER_FRAME} objects.
100162 *
101163 * @param rendererObject The renderer object.
@@ -103,14 +165,20 @@ public class NativeObjectManager {
103165 */
104166 public void deleteUnused(Object rendererObject){
105167 int removed = 0;
168+ while (removed < MAX_REMOVES_PER_FRAME && !userDeletionQueue.isEmpty()) {
169+ // Remove user requested objects.
170+ NativeObject obj = userDeletionQueue.pop();
171+ deleteNativeObject(rendererObject, obj, null, true, true);
172+ removed++;
173+ }
106174 while (removed < MAX_REMOVES_PER_FRAME) {
175+ // Remove objects reclaimed by GC.
107176 NativeObjectRef ref = (NativeObjectRef) refQueue.poll();
108177 if (ref == null) {
109178 break;
110179 }
111180
112- refList.remove(ref);
113- ref.objClone.deleteObject(rendererObject);
181+ deleteNativeObject(rendererObject, ref.objClone, ref, true, false);
114182 removed++;
115183 }
116184 if (removed >= 1) {
@@ -119,38 +187,49 @@ public class NativeObjectManager {
119187 }
120188
121189 /**
122- * Deletes all objects. Must only be called when display is destroyed.
190+ * (Internal use only) Deletes all objects.
191+ * Must only be called when display is destroyed.
123192 */
124193 public void deleteAllObjects(Object rendererObject){
125194 deleteUnused(rendererObject);
126- for (NativeObjectRef ref : refList){
127- ref.objClone.deleteObject(rendererObject);
128- NativeObject realObj = ref.realObj.get();
129- if (realObj != null){
130- // Note: make sure to reset them as well
131- // They may get used in a new renderer in the future
132- realObj.resetObject();
133- }
195+ for (IntMap.Entry<NativeObjectRef> entry : refMap) {
196+ NativeObjectRef ref = entry.getValue();
197+ deleteNativeObject(rendererObject, ref.objClone, ref, true, false);
134198 }
135- refList.clear();
199+ assert refMap.size() == 0;
136200 }
137201
138202 /**
139- * Resets all {@link NativeObject}s.
203+ * Marks the given <code>NativeObject</code> as unused,
204+ * to be deleted on the next frame.
205+ * Usage of this object after deletion will cause an exception.
206+ * Note that native buffers are only reclaimed if
207+ * {@link #UNSAFE} is set to <code>true</code>.
208+ *
209+ * @param obj The object to mark as unused.
210+ */
211+ void enqueueUnusedObject(NativeObject obj) {
212+ userDeletionQueue.push(obj);
213+ }
214+
215+ /**
216+ * (Internal use only) Resets all {@link NativeObject}s.
217+ * This is typically called when the context is restarted.
140218 */
141219 public void resetObjects(){
142- for (NativeObjectRef ref : refList){
143- // here we use the actual obj not the clone,
144- // otherwise its useless
145- NativeObject realObj = ref.realObj.get();
146- if (realObj == null)
220+ for (IntMap.Entry<NativeObjectRef> entry : refMap) {
221+ // Must use the real object here, for this to be effective.
222+ NativeObject realObj = entry.getValue().realObj.get();
223+ if (realObj == null) {
147224 continue;
225+ }
148226
149227 realObj.resetObject();
150- if (logger.isLoggable(Level.FINEST))
228+ if (logger.isLoggable(Level.FINEST)) {
151229 logger.log(Level.FINEST, "Reset: {0}", realObj);
230+ }
152231 }
153- refList.clear();
232+ refMap.clear();
154233 }
155234
156235 // public void printObjects(){
--- a/engine/src/jogl/com/jme3/audio/joal/JoalAudioRenderer.java
+++ b/engine/src/jogl/com/jme3/audio/joal/JoalAudioRenderer.java
@@ -294,7 +294,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
294294 id = ib.get(0);
295295 f.setId(id);
296296
297- objManager.registerForCleanup(f);
297+ objManager.registerObject(f);
298298 }
299299
300300 if (f instanceof LowPassFilter) {
@@ -1033,7 +1033,7 @@ public class JoalAudioRenderer implements AudioRenderer, Runnable {
10331033 id = ib.get(0);
10341034 ab.setId(id);
10351035
1036- objManager.registerForCleanup(ab);
1036+ objManager.registerObject(ab);
10371037 }
10381038
10391039 ab.getData().clear();
--- a/engine/src/jogl/com/jme3/renderer/jogl/JoglGL1Renderer.java
+++ b/engine/src/jogl/com/jme3/renderer/jogl/JoglGL1Renderer.java
@@ -782,7 +782,7 @@ public class JoglGL1Renderer implements GL1Renderer {
782782 gl.glGenTextures(1, ib1);
783783 texId = ib1.get(0);
784784 img.setId(texId);
785- objManager.registerForCleanup(img);
785+ objManager.registerObject(img);
786786
787787 statistics.onNewTexture();
788788 }
--- a/engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java
+++ b/engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java
@@ -1143,7 +1143,7 @@ public class JoglRenderer implements Renderer {
11431143 shader.clearUpdateNeeded();
11441144 if (needRegister) {
11451145 // Register shader for clean up if it was created in this method.
1146- objManager.registerForCleanup(shader);
1146+ objManager.registerObject(shader);
11471147 statistics.onNewShader();
11481148 } else {
11491149 // OpenGL spec: uniform locations may change after re-link
@@ -1506,7 +1506,7 @@ public class JoglRenderer implements Renderer {
15061506 gl.glGenFramebuffers(1, intBuf1);
15071507 id = intBuf1.get(0);
15081508 fb.setId(id);
1509- objManager.registerForCleanup(fb);
1509+ objManager.registerObject(fb);
15101510
15111511 statistics.onNewFrameBuffer();
15121512 }
@@ -1899,7 +1899,7 @@ public class JoglRenderer implements Renderer {
18991899 gl.glGenTextures(1, intBuf1);
19001900 texId = intBuf1.get(0);
19011901 img.setId(texId);
1902- objManager.registerForCleanup(img);
1902+ objManager.registerObject(img);
19031903
19041904 statistics.onNewTexture();
19051905 }
@@ -2141,7 +2141,7 @@ public class JoglRenderer implements Renderer {
21412141 gl.glGenBuffers(1, intBuf1);
21422142 bufId = intBuf1.get(0);
21432143 vb.setId(bufId);
2144- objManager.registerForCleanup(vb);
2144+ objManager.registerObject(vb);
21452145
21462146 //statistics.onNewVertexBuffer();
21472147
--- a/engine/src/lwjgl/com/jme3/audio/lwjgl/LwjglAudioRenderer.java
+++ b/engine/src/lwjgl/com/jme3/audio/lwjgl/LwjglAudioRenderer.java
@@ -266,7 +266,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
266266 id = ib.get(0);
267267 f.setId(id);
268268
269- objManager.registerForCleanup(f);
269+ objManager.registerObject(f);
270270 }
271271
272272 if (f instanceof LowPassFilter) {
@@ -1002,7 +1002,7 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
10021002 id = ib.get(0);
10031003 ab.setId(id);
10041004
1005- objManager.registerForCleanup(ab);
1005+ objManager.registerObject(ab);
10061006 }
10071007
10081008 ab.getData().clear();
--- a/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java
+++ b/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglGL1Renderer.java
@@ -729,7 +729,7 @@ public class LwjglGL1Renderer implements GL1Renderer {
729729 glGenTextures(ib1);
730730 texId = ib1.get(0);
731731 img.setId(texId);
732- objManager.registerForCleanup(img);
732+ objManager.registerObject(img);
733733
734734 statistics.onNewTexture();
735735 }
--- a/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java
+++ b/engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java
@@ -55,6 +55,7 @@ import com.jme3.texture.Texture;
5555 import com.jme3.texture.Texture.WrapAxis;
5656 import com.jme3.util.BufferUtils;
5757 import com.jme3.util.ListMap;
58+import com.jme3.util.NativeObject;
5859 import com.jme3.util.NativeObjectManager;
5960 import com.jme3.util.SafeArrayList;
6061 import java.nio.*;
@@ -129,10 +130,12 @@ public class LwjglRenderer implements Renderer {
129130 nameBuf.rewind();
130131 }
131132
133+ @Override
132134 public Statistics getStatistics() {
133135 return statistics;
134136 }
135137
138+ @Override
136139 public EnumSet<Caps> getCaps() {
137140 return caps;
138141 }
@@ -1081,7 +1084,7 @@ public class LwjglRenderer implements Renderer {
10811084 shader.clearUpdateNeeded();
10821085 if (needRegister) {
10831086 // Register shader for clean up if it was created in this method.
1084- objManager.registerForCleanup(shader);
1087+ objManager.registerObject(shader);
10851088 statistics.onNewShader();
10861089 } else {
10871090 // OpenGL spec: uniform locations may change after re-link
@@ -1431,7 +1434,7 @@ public class LwjglRenderer implements Renderer {
14311434 glGenFramebuffersEXT(intBuf1);
14321435 id = intBuf1.get(0);
14331436 fb.setId(id);
1434- objManager.registerForCleanup(fb);
1437+ objManager.registerObject(fb);
14351438
14361439 statistics.onNewFrameBuffer();
14371440 }
@@ -1802,7 +1805,7 @@ public class LwjglRenderer implements Renderer {
18021805 glGenTextures(intBuf1);
18031806 texId = intBuf1.get(0);
18041807 img.setId(texId);
1805- objManager.registerForCleanup(img);
1808+ objManager.registerObject(img);
18061809
18071810 statistics.onNewTexture();
18081811 }
@@ -2041,7 +2044,7 @@ public class LwjglRenderer implements Renderer {
20412044 glGenBuffers(intBuf1);
20422045 bufId = intBuf1.get(0);
20432046 vb.setId(bufId);
2044- objManager.registerForCleanup(vb);
2047+ objManager.registerObject(vb);
20452048
20462049 //statistics.onNewVertexBuffer();
20472050