• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

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

修訂69a5976b653746b019085207def7e4691aa9a717 (tree)
時間2013-07-07 03:56:44
作者kobayasi <kobayasi@pscn...>
Commiterkobayasi

Log Message

add asset cache

Change Summary

差異

--- a/engine/src/core/com/jme3/asset/AssetKey.java
+++ b/engine/src/core/com/jme3/asset/AssetKey.java
@@ -61,7 +61,16 @@ public class AssetKey<T> implements Savable {
6161 public AssetKey(){
6262 }
6363
64- protected static String getExtension(String name){
64+ @Override
65+ public AssetKey<T> clone() {
66+ try {
67+ return (AssetKey<T>) super.clone();
68+ } catch (CloneNotSupportedException ex) {
69+ throw new AssertionError();
70+ }
71+ }
72+
73+ protected static String getExtension(String name) {
6574 int idx = name.lastIndexOf('.');
6675 //workaround for filenames ending with xml and another dot ending before that (my.mesh.xml)
6776 if (name.toLowerCase().endsWith(".xml")) {
--- /dev/null
+++ b/engine/src/core/com/jme3/asset/AssetProcessor.java
@@ -0,0 +1,71 @@
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.asset;
33+
34+import com.jme3.material.Material;
35+import com.jme3.shader.Shader;
36+
37+/**
38+ * <code>AssetProcessor</code> is used to apply processing to assets
39+ * after they have been loaded. They are assigned to a particular
40+ * asset type (which is represented by a {@link Class} and any assets
41+ * loaded that are of that class will be processed by the assigned
42+ * processor.
43+ *
44+ * @author Kirill Vainer
45+ */
46+public interface AssetProcessor {
47+ /**
48+ * Applies post processing to an asset.
49+ * The method may return an object that is not the same
50+ * instance as the parameter object, and it could be from a different class.
51+ *
52+ * @param obj The asset that was loaded from an {@link AssetLoader}.
53+ * @return Either the same object with processing applied, or an instance
54+ * of a new object.
55+ */
56+ public Object postProcess(AssetKey key, Object obj);
57+
58+ /**
59+ * Creates a clone of the given asset.
60+ * If no clone is desired, then the same instance can be returned,
61+ * otherwise, a clone should be created.
62+ * For example, a clone of a {@link Material} should have its own set
63+ * of unique parameters that can be changed just for that instance,
64+ * but it may share certain other data if it sees fit (like the {@link Shader}).
65+ *
66+ * @param obj The asset to clone
67+ * @return The cloned asset, or the same as the given argument if no
68+ * clone is needed.
69+ */
70+ public Object createClone(Object obj);
71+}
--- /dev/null
+++ b/engine/src/core/com/jme3/asset/CloneableSmartAsset.java
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.asset;
33+
34+import com.jme3.asset.cache.WeakRefCloneAssetCache;
35+
36+/**
37+ * Implementing the <code>CloneableSmartAsset</code> interface allows use
38+ * of cloneable smart asset management.
39+ * <p>
40+ * Smart asset management requires cooperation from the {@link AssetKey}.
41+ * In particular, the AssetKey should return {@link WeakRefCloneAssetCache} in its
42+ * {@link AssetKey#getCacheType()} method. Also smart assets MUST
43+ * create a clone of the asset and cannot return the same reference,
44+ * e.g. {@link AssetProcessor#createClone(java.lang.Object) createClone(someAsset)} <code>!= someAsset</code>.
45+ * <p>
46+ * If the {@link AssetManager#loadAsset(com.jme3.asset.AssetKey) } method
47+ * is called twice with the same asset key (equals() wise, not necessarily reference wise)
48+ * then both assets will have the same asset key set (reference wise) via
49+ * {@link AssetKey#AssetKey() }, then this asset key
50+ * is used to track all instances of that asset. Once all clones of the asset
51+ * are garbage collected, the shared asset key becomes unreachable and at that
52+ * point it is removed from the smart asset cache.
53+ */
54+public interface CloneableSmartAsset extends Cloneable {
55+
56+ /**
57+ * Creates a clone of the asset.
58+ *
59+ * Please see {@link Object#clone() } for more info on how this method
60+ * should be implemented.
61+ *
62+ * @return A clone of this asset.
63+ * The cloned asset cannot reference equal this asset.
64+ */
65+ public Object clone();
66+
67+ /**
68+ * Set by the {@link AssetManager} to track this asset.
69+ *
70+ * Only clones of the asset has this set, the original copy that
71+ * was loaded has this key set to null so that only the clones are tracked
72+ * for garbage collection.
73+ *
74+ * @param key The AssetKey to set
75+ */
76+ public void setKey(AssetKey key);
77+
78+ /**
79+ * Returns the asset key that is used to track this asset for garbage
80+ * collection.
81+ *
82+ * @return the asset key that is used to track this asset for garbage
83+ * collection.
84+ */
85+ public AssetKey getKey();
86+}
--- /dev/null
+++ b/engine/src/core/com/jme3/asset/cache/AssetCache.java
@@ -0,0 +1,121 @@
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.asset.cache;
33+
34+import com.jme3.asset.AssetKey;
35+
36+/**
37+ * <code>AssetCache</code> is an interface for asset caches.
38+ * Allowing storage of loaded resources in order to improve their access time
39+ * if they are requested again in a short period of time.
40+ * Depending on the asset type and how it is used, a specialized
41+ * caching method can be selected that is most appropriate for that asset type.
42+ * The asset cache must be thread safe.
43+ * <p>
44+ * Some caches are used to manage cloneable assets, which track reachability
45+ * based on a shared key in all instances exposed in user code.
46+ * E.g. {@link WeakRefCloneAssetCache} uses this approach.
47+ * For those particular caches, either {@link #registerAssetClone(com.jme3.asset.AssetKey, java.lang.Object) }
48+ * or {@link #notifyNoAssetClone() } <b>MUST</b> be called to avoid memory
49+ * leaking following a successful {@link #addToCache(com.jme3.asset.AssetKey, java.lang.Object) }
50+ * or {@link #getFromCache(com.jme3.asset.AssetKey) } call!
51+ *
52+ * @author Kirill Vainer
53+ */
54+public interface AssetCache {
55+ /**
56+ * Adds an asset to the cache.
57+ * Once added, it should be possible to retrieve the asset
58+ * by using the {@link #getFromCache(com.jme3.asset.AssetKey) } method.
59+ * However the caching criteria may at some point choose that the asset
60+ * should be removed from the cache to save memory, in that case,
61+ * {@link #getFromCache(com.jme3.asset.AssetKey) } will return null.
62+ * <p><font color="red">Thread-Safe</font>
63+ *
64+ * @param <T> The type of the asset to cache.
65+ * @param key The asset key that can be used to look up the asset.
66+ * @param obj The asset data to cache.
67+ */
68+ public <T> void addToCache(AssetKey<T> key, T obj);
69+
70+ /**
71+ * This should be called by the asset manager when it has successfully
72+ * acquired a cached asset (with {@link #getFromCache(com.jme3.asset.AssetKey) })
73+ * and cloned it for use.
74+ * <p><font color="red">Thread-Safe</font>
75+ *
76+ * @param <T> The type of the asset to register.
77+ * @param key The asset key of the loaded asset (used to retrieve from cache)
78+ * @param clone The <strong>clone</strong> of the asset retrieved from
79+ * the cache.
80+ */
81+ public <T> void registerAssetClone(AssetKey<T> key, T clone);
82+
83+ /**
84+ * Notifies the cache that even though the methods {@link #addToCache(com.jme3.asset.AssetKey, java.lang.Object) }
85+ * or {@link #getFromCache(com.jme3.asset.AssetKey) } were used, there won't
86+ * be a call to {@link #registerAssetClone(com.jme3.asset.AssetKey, java.lang.Object) }
87+ * for some reason. For example, if an error occurred during loading
88+ * or if the addToCache/getFromCache were used from user code.
89+ */
90+ public void notifyNoAssetClone();
91+
92+ /**
93+ * Retrieves an asset from the cache.
94+ * It is possible to add an asset to the cache using
95+ * {@link #addToCache(com.jme3.asset.AssetKey, java.lang.Object) }.
96+ * The asset may be removed from the cache automatically even if
97+ * it was added previously, in that case, this method will return null.
98+ * <p><font color="red">Thread-Safe</font>
99+ *
100+ * @param <T> The type of the asset to retrieve
101+ * @param key The key used to lookup the asset.
102+ * @return The asset that was previously cached, or null if not found.
103+ */
104+ public <T> T getFromCache(AssetKey<T> key);
105+
106+ /**
107+ * Deletes an asset from the cache.
108+ * <p><font color="red">Thread-Safe</font>
109+ *
110+ * @param key The asset key to find the asset to delete.
111+ * @return True if the asset was successfully found in the cache
112+ * and removed.
113+ */
114+ public boolean deleteFromCache(AssetKey key);
115+
116+ /**
117+ * Deletes all assets from the cache.
118+ * <p><font color="red">Thread-Safe</font>
119+ */
120+ public void clearCache();
121+}
--- /dev/null
+++ b/engine/src/core/com/jme3/asset/cache/SimpleAssetCache.java
@@ -0,0 +1,71 @@
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.asset.cache;
33+
34+import com.jme3.asset.AssetKey;
35+import java.util.concurrent.ConcurrentHashMap;
36+
37+/**
38+ * <code>SimpleAssetCache</code> is an asset cache
39+ * that caches assets without any automatic removal policy. The user
40+ * is expected to manually call {@link #deleteFromCache(com.jme3.asset.AssetKey) }
41+ * to delete any assets.
42+ *
43+ * @author Kirill Vainer
44+ */
45+public class SimpleAssetCache implements AssetCache {
46+
47+ private final ConcurrentHashMap<AssetKey, Object> keyToAssetMap = new ConcurrentHashMap<AssetKey, Object>();
48+
49+ public <T> void addToCache(AssetKey<T> key, T obj) {
50+ keyToAssetMap.put(key, obj);
51+ }
52+
53+ public <T> void registerAssetClone(AssetKey<T> key, T clone) {
54+ }
55+
56+ public <T> T getFromCache(AssetKey<T> key) {
57+ return (T) keyToAssetMap.get(key);
58+ }
59+
60+ public boolean deleteFromCache(AssetKey key) {
61+ return keyToAssetMap.remove(key) != null;
62+ }
63+
64+ public void clearCache() {
65+ keyToAssetMap.clear();
66+ }
67+
68+ public void notifyNoAssetClone() {
69+ }
70+
71+}
--- /dev/null
+++ b/engine/src/core/com/jme3/asset/cache/WeakRefAssetCache.java
@@ -0,0 +1,123 @@
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.asset.cache;
33+
34+import com.jme3.asset.AssetKey;
35+import com.jme3.asset.AssetProcessor;
36+import java.lang.ref.ReferenceQueue;
37+import java.lang.ref.WeakReference;
38+import java.util.concurrent.ConcurrentHashMap;
39+import java.util.logging.Level;
40+import java.util.logging.Logger;
41+
42+/**
43+ * A garbage collector bound asset cache that handles non-clonable objects.
44+ * This cache assumes that the asset given to the user is the same asset
45+ * that has been stored in the cache, in other words,
46+ * {@link AssetProcessor#createClone(java.lang.Object) } for that asset
47+ * returns the same object as the argument.
48+ * This implementation will remove the asset from the cache
49+ * once the asset is no longer referenced in user code and memory is low,
50+ * e.g. the VM feels like purging the weak references for that asset.
51+ *
52+ * @author Kirill Vainer
53+ */
54+public class WeakRefAssetCache implements AssetCache {
55+
56+ private static final Logger logger = Logger.getLogger(WeakRefAssetCache.class.getName());
57+
58+ private final ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
59+
60+ private final ConcurrentHashMap<AssetKey, AssetRef> assetCache
61+ = new ConcurrentHashMap<AssetKey, AssetRef>();
62+
63+ private static class AssetRef extends WeakReference<Object> {
64+
65+ private final AssetKey assetKey;
66+
67+ public AssetRef(AssetKey assetKey, Object originalAsset, ReferenceQueue<Object> refQueue){
68+ super(originalAsset, refQueue);
69+ this.assetKey = assetKey;
70+ }
71+ }
72+
73+ private void removeCollectedAssets(){
74+ int removedAssets = 0;
75+ for (AssetRef ref; (ref = (AssetRef)refQueue.poll()) != null;){
76+ // Asset was collected, note that at this point the asset cache
77+ // might not even have this asset anymore, it is OK.
78+ if (assetCache.remove(ref.assetKey) != null){
79+ removedAssets ++;
80+ //System.out.println("WeakRefAssetCache: The asset " + ref.assetKey + " was purged from the cache");
81+ }
82+ }
83+ if (removedAssets >= 1) {
84+ logger.log(Level.FINE, "WeakRefAssetCache: {0} assets were purged from the cache.", removedAssets);
85+ }
86+ }
87+
88+ public <T> void addToCache(AssetKey<T> key, T obj) {
89+ removeCollectedAssets();
90+
91+ // NOTE: Some thread issues can hapen if another
92+ // thread is loading an asset with the same key ..
93+ AssetRef ref = new AssetRef(key, obj, refQueue);
94+ assetCache.put(key, ref);
95+
96+// Texture t = (Texture) obj;
97+// Image i = t.getImage();
98+// System.out.println("add to cache " + System.identityHashCode(i));
99+ }
100+
101+ public <T> T getFromCache(AssetKey<T> key) {
102+ AssetRef ref = assetCache.get(key);
103+ if (ref != null){
104+ return (T) ref.get();
105+ }else{
106+ return null;
107+ }
108+ }
109+
110+ public boolean deleteFromCache(AssetKey key) {
111+ return assetCache.remove(key) != null;
112+ }
113+
114+ public void clearCache() {
115+ assetCache.clear();
116+ }
117+
118+ public <T> void registerAssetClone(AssetKey<T> key, T clone) {
119+ }
120+
121+ public void notifyNoAssetClone() {
122+ }
123+}
--- /dev/null
+++ b/engine/src/core/com/jme3/asset/cache/WeakRefCloneAssetCache.java
@@ -0,0 +1,206 @@
1+/*
2+ * Copyright (c) 2009-2012 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+package com.jme3.asset.cache;
33+
34+import com.jme3.asset.AssetKey;
35+import com.jme3.asset.CloneableSmartAsset;
36+import java.lang.ref.PhantomReference;
37+import java.lang.ref.ReferenceQueue;
38+import java.lang.ref.WeakReference;
39+import java.util.ArrayList;
40+import java.util.concurrent.ConcurrentHashMap;
41+import java.util.logging.Level;
42+import java.util.logging.Logger;
43+
44+/**
45+ * <codeWeakRefCloneAssetCache</code> caches cloneable assets in a weak-key
46+ * cache, allowing them to be collected when memory is low.
47+ * The cache stores weak references to the asset keys, so that
48+ * when all clones of the original asset are collected, will cause the
49+ * asset to be automatically removed from the cache.
50+ *
51+* @author Kirill Vainer
52+ */
53+public class WeakRefCloneAssetCache implements AssetCache {
54+
55+ private static final Logger logger = Logger.getLogger(WeakRefAssetCache.class.getName());
56+
57+ private final ReferenceQueue<AssetKey> refQueue = new ReferenceQueue<AssetKey>();
58+
59+ /**
60+ * Maps cloned key to AssetRef which has a weak ref to the original
61+ * key and a strong ref to the original asset.
62+ */
63+ private final ConcurrentHashMap<AssetKey, AssetRef> smartCache
64+ = new ConcurrentHashMap<AssetKey, AssetRef>();
65+
66+ /**
67+ * Stored in the ReferenceQueue to find out when originalKey is collected
68+ * by GC. Once collected, the clonedKey is used to remove the asset
69+ * from the cache.
70+ */
71+ private static final class KeyRef extends PhantomReference<AssetKey> {
72+
73+ AssetKey clonedKey;
74+
75+ public KeyRef(AssetKey originalKey, ReferenceQueue<AssetKey> refQueue) {
76+ super(originalKey, refQueue);
77+ clonedKey = originalKey.clone();
78+ }
79+ }
80+
81+ /**
82+ * Stores the original key and original asset.
83+ * The asset info contains a cloneable asset (e.g. the original, from
84+ * which all clones are made). Also a weak reference to the
85+ * original key which is used when the clones are produced.
86+ */
87+ private static final class AssetRef extends WeakReference<AssetKey> {
88+
89+ CloneableSmartAsset asset;
90+
91+ public AssetRef(CloneableSmartAsset originalAsset, AssetKey originalKey) {
92+ super(originalKey);
93+ this.asset = originalAsset;
94+ }
95+ }
96+
97+ private final ThreadLocal<ArrayList<AssetKey>> assetLoadStack
98+ = new ThreadLocal<ArrayList<AssetKey>>() {
99+ @Override
100+ protected ArrayList<AssetKey> initialValue() {
101+ return new ArrayList<AssetKey>();
102+ }
103+ };
104+
105+ private void removeCollectedAssets(){
106+ int removedAssets = 0;
107+ for (KeyRef ref; (ref = (KeyRef)refQueue.poll()) != null;){
108+ // (Cannot use ref.get() since it was just collected by GC!)
109+ AssetKey key = ref.clonedKey;
110+
111+ // Asset was collected, note that at this point the asset cache
112+ // might not even have this asset anymore, it is OK.
113+ if (smartCache.remove(key) != null){
114+ removedAssets ++;
115+ //System.out.println("WeakRefAssetCache: The asset " + ref.assetKey + " was purged from the cache");
116+ }
117+ }
118+ if (removedAssets >= 1) {
119+ logger.log(Level.FINE, "WeakRefAssetCache: {0} assets were purged from the cache.", removedAssets);
120+ }
121+ }
122+
123+ public <T> void addToCache(AssetKey<T> originalKey, T obj) {
124+ // Make room for new asset
125+ removeCollectedAssets();
126+
127+ CloneableSmartAsset asset = (CloneableSmartAsset) obj;
128+
129+ // No circular references, since the original asset is
130+ // strongly referenced, we don't want the key strongly referenced.
131+ asset.setKey(null);
132+
133+ // Start tracking the collection of originalKey
134+ // (this adds the KeyRef to the ReferenceQueue)
135+ KeyRef ref = new KeyRef(originalKey, refQueue);
136+
137+ // Place the asset in the cache, but use a clone of
138+ // the original key.
139+ smartCache.put(ref.clonedKey, new AssetRef(asset, originalKey));
140+
141+ // Push the original key used to load the asset
142+ // so that it can be set on the clone later
143+ ArrayList<AssetKey> loadStack = assetLoadStack.get();
144+ loadStack.add(originalKey);
145+ }
146+
147+ public <T> void registerAssetClone(AssetKey<T> key, T clone) {
148+ ArrayList<AssetKey> loadStack = assetLoadStack.get();
149+ ((CloneableSmartAsset)clone).setKey(loadStack.remove(loadStack.size() - 1));
150+ }
151+
152+ public void notifyNoAssetClone() {
153+ ArrayList<AssetKey> loadStack = assetLoadStack.get();
154+ loadStack.remove(loadStack.size() - 1);
155+ }
156+
157+ public <T> T getFromCache(AssetKey<T> key) {
158+ AssetRef smartInfo;
159+ synchronized (smartCache){
160+ smartInfo = smartCache.get(key);
161+ }
162+
163+ if (smartInfo == null) {
164+ return null;
165+ } else {
166+ // NOTE: Optimization so that registerAssetClone()
167+ // can check this and determine that the asset clone
168+ // belongs to the asset retrieved here.
169+ AssetKey keyForTheClone = smartInfo.get();
170+ if (keyForTheClone == null){
171+ // The asset was JUST collected by GC
172+ // (between here and smartCache.get)
173+ return null;
174+ }
175+
176+ // Prevent original key from getting collected
177+ // while an asset is loaded for it.
178+ ArrayList<AssetKey> loadStack = assetLoadStack.get();
179+ loadStack.add(keyForTheClone);
180+
181+ return (T) smartInfo.asset;
182+ }
183+ }
184+
185+ public boolean deleteFromCache(AssetKey key) {
186+ ArrayList<AssetKey> loadStack = assetLoadStack.get();
187+
188+ if (!loadStack.isEmpty()){
189+ throw new UnsupportedOperationException("Cache cannot be modified"
190+ + "while assets are being loaded");
191+ }
192+
193+ return smartCache.remove(key) != null;
194+ }
195+
196+ public void clearCache() {
197+ ArrayList<AssetKey> loadStack = assetLoadStack.get();
198+
199+ if (!loadStack.isEmpty()){
200+ throw new UnsupportedOperationException("Cache cannot be modified"
201+ + "while assets are being loaded");
202+ }
203+
204+ smartCache.clear();
205+ }
206+}