1 /* 2 * Copyright (C) 2010 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 com.android.gallery3d.ui; 18 19 import com.android.gallery3d.common.Utils; 20 21 import java.lang.ref.WeakReference; 22 import java.util.WeakHashMap; 23 24 // BasicTexture is a Texture corresponds to a real GL texture. 25 // The state of a BasicTexture indicates whether its data is loaded to GL memory. 26 // If a BasicTexture is loaded into GL memory, it has a GL texture id. 27 abstract class BasicTexture implements Texture { 28 29 @SuppressWarnings("unused") 30 private static final String TAG = "BasicTexture"; 31 protected static final int UNSPECIFIED = -1; 32 33 protected static final int STATE_UNLOADED = 0; 34 protected static final int STATE_LOADED = 1; 35 protected static final int STATE_ERROR = -1; 36 37 protected int mId; 38 protected int mState; 39 40 protected int mWidth = UNSPECIFIED; 41 protected int mHeight = UNSPECIFIED; 42 43 private int mTextureWidth; 44 private int mTextureHeight; 45 46 private boolean mHasBorder; 47 48 protected WeakReference<GLCanvas> mCanvasRef = null; 49 private static WeakHashMap<BasicTexture, Object> sAllTextures 50 = new WeakHashMap<BasicTexture, Object>(); 51 private static ThreadLocal sInFinalizer = new ThreadLocal(); 52 53 protected BasicTexture(GLCanvas canvas, int id, int state) { 54 setAssociatedCanvas(canvas); 55 mId = id; 56 mState = state; 57 synchronized (sAllTextures) { 58 sAllTextures.put(this, null); 59 } 60 } 61 62 protected BasicTexture() { 63 this(null, 0, STATE_UNLOADED); 64 } 65 66 protected void setAssociatedCanvas(GLCanvas canvas) { 67 mCanvasRef = canvas == null 68 ? null 69 : new WeakReference<GLCanvas>(canvas); 70 } 71 72 /** 73 * Sets the content size of this texture. In OpenGL, the actual texture 74 * size must be of power of 2, the size of the content may be smaller. 75 */ 76 protected void setSize(int width, int height) { 77 mWidth = width; 78 mHeight = height; 79 mTextureWidth = Utils.nextPowerOf2(width); 80 mTextureHeight = Utils.nextPowerOf2(height); 81 } 82 83 public int getId() { 84 return mId; 85 } 86 87 public int getWidth() { 88 return mWidth; 89 } 90 91 public int getHeight() { 92 return mHeight; 93 } 94 95 // Returns the width rounded to the next power of 2. 96 public int getTextureWidth() { 97 return mTextureWidth; 98 } 99 100 // Returns the height rounded to the next power of 2. 101 public int getTextureHeight() { 102 return mTextureHeight; 103 } 104 105 // Returns true if the texture has one pixel transparent border around the 106 // actual content. This is used to avoid jigged edges. 107 // 108 // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap 109 // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially 110 // covered by the texture will use the color of the edge texel. If we add 111 // the transparent border, the color of the edge texel will be mixed with 112 // appropriate amount of transparent. 113 // 114 // Currently our background is black, so we can draw the thumbnails without 115 // enabling blending. 116 public boolean hasBorder() { 117 return mHasBorder; 118 } 119 120 protected void setBorder(boolean hasBorder) { 121 mHasBorder = hasBorder; 122 } 123 124 public void draw(GLCanvas canvas, int x, int y) { 125 canvas.drawTexture(this, x, y, getWidth(), getHeight()); 126 } 127 128 public void draw(GLCanvas canvas, int x, int y, int w, int h) { 129 canvas.drawTexture(this, x, y, w, h); 130 } 131 132 // onBind is called before GLCanvas binds this texture. 133 // It should make sure the data is uploaded to GL memory. 134 abstract protected boolean onBind(GLCanvas canvas); 135 136 public boolean isLoaded(GLCanvas canvas) { 137 return mState == STATE_LOADED && mCanvasRef.get() == canvas; 138 } 139 140 // recycle() is called when the texture will never be used again, 141 // so it can free all resources. 142 public void recycle() { 143 freeResource(); 144 } 145 146 // yield() is called when the texture will not be used temporarily, 147 // so it can free some resources. 148 // The default implementation unloads the texture from GL memory, so 149 // the subclass should make sure it can reload the texture to GL memory 150 // later, or it will have to override this method. 151 public void yield() { 152 freeResource(); 153 } 154 155 private void freeResource() { 156 GLCanvas canvas = mCanvasRef == null ? null : mCanvasRef.get(); 157 if (canvas != null && isLoaded(canvas)) { 158 canvas.unloadTexture(this); 159 } 160 mState = BasicTexture.STATE_UNLOADED; 161 setAssociatedCanvas(null); 162 } 163 164 @Override 165 protected void finalize() { 166 sInFinalizer.set(BasicTexture.class); 167 recycle(); 168 sInFinalizer.set(null); 169 } 170 171 // This is for deciding if we can call Bitmap's recycle(). 172 // We cannot call Bitmap's recycle() in finalizer because at that point 173 // the finalizer of Bitmap may already be called so recycle() will crash. 174 public static boolean inFinalizer() { 175 return sInFinalizer.get() != null; 176 } 177 178 public static void yieldAllTextures() { 179 synchronized (sAllTextures) { 180 for (BasicTexture t : sAllTextures.keySet()) { 181 t.yield(); 182 } 183 } 184 } 185 } 186