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