1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.renderscript; 18 19 import dalvik.system.CloseGuard; 20 import java.util.concurrent.locks.ReentrantReadWriteLock; 21 22 /** 23 * BaseObj is the base class for all RenderScript objects owned by a RS context. 24 * It is responsible for lifetime management and resource tracking. This class 25 * should not be used by a user application. 26 * 27 **/ 28 public class BaseObj { 29 BaseObj(long id, RenderScript rs) { 30 rs.validate(); 31 mRS = rs; 32 mID = id; 33 mDestroyed = false; 34 } 35 36 void setID(long id) { 37 if (mID != 0) { 38 throw new RSRuntimeException("Internal Error, reset of object ID."); 39 } 40 mID = id; 41 } 42 43 /** 44 * Lookup the native object ID for this object. Primarily used by the 45 * generated reflected code. 46 * 47 * @param rs Context to verify against internal context for 48 * match. 49 * 50 * @return long 51 */ 52 long getID(RenderScript rs) { 53 mRS.validate(); 54 if (mDestroyed) { 55 throw new RSInvalidStateException("using a destroyed object."); 56 } 57 if (mID == 0) { 58 throw new RSRuntimeException("Internal error: Object id 0."); 59 } 60 if ((rs != null) && (rs != mRS)) { 61 throw new RSInvalidStateException("using object with mismatched context."); 62 } 63 return mID; 64 } 65 66 void checkValid() { 67 if (mID == 0) { 68 throw new RSIllegalArgumentException("Invalid object."); 69 } 70 } 71 72 private long mID; 73 final CloseGuard guard = CloseGuard.get(); 74 private boolean mDestroyed; 75 private String mName; 76 RenderScript mRS; 77 78 /** 79 * setName assigns a name to an object. This object can later be looked up 80 * by this name. 81 * 82 * @param name The name to assign to the object. 83 */ 84 public void setName(String name) { 85 if (name == null) { 86 throw new RSIllegalArgumentException( 87 "setName requires a string of non-zero length."); 88 } 89 if(name.length() < 1) { 90 throw new RSIllegalArgumentException( 91 "setName does not accept a zero length string."); 92 } 93 if(mName != null) { 94 throw new RSIllegalArgumentException( 95 "setName object already has a name."); 96 } 97 98 try { 99 byte[] bytes = name.getBytes("UTF-8"); 100 mRS.nAssignName(mID, bytes); 101 mName = name; 102 } catch (java.io.UnsupportedEncodingException e) { 103 throw new RuntimeException(e); 104 } 105 } 106 107 /** 108 * @return name of the renderscript object 109 */ 110 public String getName() { 111 return mName; 112 } 113 114 private void helpDestroy() { 115 boolean shouldDestroy = false; 116 synchronized(this) { 117 if (!mDestroyed) { 118 shouldDestroy = true; 119 mDestroyed = true; 120 } 121 } 122 123 if (shouldDestroy) { 124 guard.close(); 125 // must include nObjDestroy in the critical section 126 ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock(); 127 rlock.lock(); 128 // AllocationAdapters are BaseObjs with an ID of 0 but should not be passed to nObjDestroy 129 if(mRS.isAlive() && mID != 0) { 130 mRS.nObjDestroy(mID); 131 } 132 rlock.unlock(); 133 mRS = null; 134 mID = 0; 135 } 136 } 137 138 protected void finalize() throws Throwable { 139 try { 140 if (guard != null) { 141 guard.warnIfOpen(); 142 } 143 helpDestroy(); 144 } finally { 145 super.finalize(); 146 } 147 } 148 149 /** 150 * Frees any native resources associated with this object. The 151 * primary use is to force immediate cleanup of resources when it is 152 * believed the GC will not respond quickly enough. 153 */ 154 public void destroy() { 155 if(mDestroyed) { 156 throw new RSInvalidStateException("Object already destroyed."); 157 } 158 helpDestroy(); 159 } 160 161 /** 162 * If an object came from an a3d file, java fields need to be 163 * created with objects from the native layer 164 */ 165 void updateFromNative() { 166 mRS.validate(); 167 mName = mRS.nGetName(getID(mRS)); 168 } 169 170 /** 171 * Calculates the hash code value for a BaseObj. 172 * 173 * @return int 174 */ 175 @Override 176 public int hashCode() { 177 return (int)((mID & 0xfffffff) ^ (mID >> 32)); 178 } 179 180 /** 181 * Compare the current BaseObj with another BaseObj for equality. 182 * 183 * @param obj The object to check equality with. 184 * 185 * @return boolean 186 */ 187 @Override 188 public boolean equals(Object obj) { 189 // Early-out check to see if both BaseObjs are actually the same 190 if (this == obj) 191 return true; 192 193 if (obj == null) { 194 return false; 195 } 196 197 if (getClass() != obj.getClass()) { 198 return false; 199 } 200 201 BaseObj b = (BaseObj) obj; 202 return mID == b.mID; 203 } 204 } 205 206