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