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 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 public void setSize(int width, int height) { 76 mWidth = width; 77 mHeight = height; 78 mTextureWidth = width > 0 ? Utils.nextPowerOf2(width) : 0; 79 mTextureHeight = height > 0 ? Utils.nextPowerOf2(height) : 0; 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 @Override 91 public int getWidth() { 92 return mWidth; 93 } 94 95 @Override 96 public int getHeight() { 97 return mHeight; 98 } 99 100 // Returns the width rounded to the next power of 2. 101 public int getTextureWidth() { 102 return mTextureWidth; 103 } 104 105 // Returns the height rounded to the next power of 2. 106 public int getTextureHeight() { 107 return mTextureHeight; 108 } 109 110 @Override 111 public void draw(GLCanvas canvas, int x, int y) { 112 canvas.drawTexture(this, x, y, getWidth(), getHeight()); 113 } 114 115 @Override 116 public void draw(GLCanvas canvas, int x, int y, int w, int h) { 117 canvas.drawTexture(this, x, y, w, h); 118 } 119 120 // onBind is called before GLCanvas binds this texture. 121 // It should make sure the data is uploaded to GL memory. 122 abstract protected boolean onBind(GLCanvas canvas); 123 124 public boolean isLoaded() { 125 return mState == STATE_LOADED; 126 } 127 128 // recycle() is called when the texture will never be used again, 129 // so it can free all resources. 130 public void recycle() { 131 freeResource(); 132 } 133 134 // yield() is called when the texture will not be used temporarily, 135 // so it can free some resources. 136 // The default implementation unloads the texture from GL memory, so 137 // the subclass should make sure it can reload the texture to GL memory 138 // later, or it will have to override this method. 139 public void yield() { 140 freeResource(); 141 } 142 143 private void freeResource() { 144 GLCanvas canvas = mCanvasRef; 145 if (canvas != null && mId != -1) { 146 canvas.unloadTexture(this); 147 mId = -1; // Don't free it again. 148 } 149 mState = STATE_UNLOADED; 150 setAssociatedCanvas(null); 151 } 152 153 @Override 154 protected void finalize() { 155 sInFinalizer.set(BasicTexture.class); 156 recycle(); 157 sInFinalizer.set(null); 158 } 159 160 public static void yieldAllTextures() { 161 synchronized (sAllTextures) { 162 for (BasicTexture t : sAllTextures.keySet()) { 163 t.yield(); 164 } 165 } 166 } 167 168 public static void invalidateAllTextures() { 169 synchronized (sAllTextures) { 170 for (BasicTexture t : sAllTextures.keySet()) { 171 t.mState = STATE_UNLOADED; 172 t.setAssociatedCanvas(null); 173 } 174 } 175 } 176 } 177