1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.jme3.util;
34 
35 import java.lang.ref.PhantomReference;
36 import java.lang.ref.ReferenceQueue;
37 import java.lang.ref.WeakReference;
38 import java.util.ArrayList;
39 import java.util.logging.Level;
40 import java.util.logging.Logger;
41 
42 /**
43  * GLObjectManager tracks all GLObjects used by the Renderer. Using a
44  * <code>ReferenceQueue</code> the <code>GLObjectManager</code> can delete
45  * unused objects from GPU when their counterparts on the CPU are no longer used.
46  *
47  * On restart, the renderer may request the objects to be reset, thus allowing
48  * the GLObjects to re-initialize with the new display context.
49  */
50 public class NativeObjectManager {
51 
52     private static final Logger logger = Logger.getLogger(NativeObjectManager.class.getName());
53 
54     /**
55      * The queue will receive notifications of {@link NativeObject}s which are no longer
56      * referenced.
57      */
58     private ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
59 
60     /**
61      * List of currently active GLObjects.
62      */
63     private ArrayList<NativeObjectRef> refList
64             = new ArrayList<NativeObjectRef>();
65 
66     private class NativeObjectRef extends PhantomReference<Object>{
67 
68         private NativeObject objClone;
69         private WeakReference<NativeObject> realObj;
70 
NativeObjectRef(NativeObject obj)71         public NativeObjectRef(NativeObject obj){
72             super(obj.handleRef, refQueue);
73             assert obj.handleRef != null;
74 
75             this.realObj = new WeakReference<NativeObject>(obj);
76             this.objClone = obj.createDestructableClone();
77         }
78     }
79 
80     /**
81      * Register a GLObject with the manager.
82      */
registerForCleanup(NativeObject obj)83     public void registerForCleanup(NativeObject obj){
84         NativeObjectRef ref = new NativeObjectRef(obj);
85         refList.add(ref);
86         if (logger.isLoggable(Level.FINEST))
87             logger.log(Level.FINEST, "Registered: {0}", new String[]{obj.toString()});
88     }
89 
90     /**
91      * Deletes unused GLObjects
92      */
deleteUnused(Object rendererObject)93     public void deleteUnused(Object rendererObject){
94         while (true){
95             NativeObjectRef ref = (NativeObjectRef) refQueue.poll();
96             if (ref == null)
97                 return;
98 
99             refList.remove(ref);
100             ref.objClone.deleteObject(rendererObject);
101             if (logger.isLoggable(Level.FINEST))
102                 logger.log(Level.FINEST, "Deleted: {0}", ref.objClone);
103         }
104     }
105 
106     /**
107      * Deletes all objects. Must only be called when display is destroyed.
108      */
deleteAllObjects(Object rendererObject)109     public void deleteAllObjects(Object rendererObject){
110         deleteUnused(rendererObject);
111         for (NativeObjectRef ref : refList){
112             ref.objClone.deleteObject(rendererObject);
113             NativeObject realObj = ref.realObj.get();
114             if (realObj != null){
115                 // Note: make sure to reset them as well
116                 // They may get used in a new renderer in the future
117                 realObj.resetObject();
118             }
119         }
120         refList.clear();
121     }
122 
123     /**
124      * Resets all {@link NativeObject}s.
125      */
resetObjects()126     public void resetObjects(){
127         for (NativeObjectRef ref : refList){
128             // here we use the actual obj not the clone,
129             // otherwise its useless
130             NativeObject realObj = ref.realObj.get();
131             if (realObj == null)
132                 continue;
133 
134             realObj.resetObject();
135             if (logger.isLoggable(Level.FINEST))
136                 logger.log(Level.FINEST, "Reset: {0}", realObj);
137         }
138         refList.clear();
139     }
140 
141 //    public void printObjects(){
142 //        System.out.println(" ------------------- ");
143 //        System.out.println(" GL Object count: "+ objectList.size());
144 //        for (GLObject obj : objectList){
145 //            System.out.println(obj);
146 //        }
147 //    }
148 }
149