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