1104c45677660586026a7e74ef8c47d396403d50eMichael Jurka/* 2104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Copyright (C) 2010 The Android Open Source Project 3104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 4104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * you may not use this file except in compliance with the License. 6104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * You may obtain a copy of the License at 7104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 8104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * 10104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Unless required by applicable law or agreed to in writing, software 11104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * See the License for the specific language governing permissions and 14104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * limitations under the License. 15104c45677660586026a7e74ef8c47d396403d50eMichael Jurka */ 16104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 17104c45677660586026a7e74ef8c47d396403d50eMichael Jurkapackage com.android.gallery3d.glrenderer; 18104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 19104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport android.util.Log; 20104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 21104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport com.android.gallery3d.common.Utils; 22104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 23104c45677660586026a7e74ef8c47d396403d50eMichael Jurkaimport java.util.WeakHashMap; 24104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 25104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// BasicTexture is a Texture corresponds to a real GL texture. 26104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// The state of a BasicTexture indicates whether its data is loaded to GL memory. 27104c45677660586026a7e74ef8c47d396403d50eMichael Jurka// If a BasicTexture is loaded into GL memory, it has a GL texture id. 28104c45677660586026a7e74ef8c47d396403d50eMichael Jurkapublic abstract class BasicTexture implements Texture { 29104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 30104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @SuppressWarnings("unused") 31104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static final String TAG = "BasicTexture"; 32104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected static final int UNSPECIFIED = -1; 33104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 34104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected static final int STATE_UNLOADED = 0; 35104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected static final int STATE_LOADED = 1; 36104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected static final int STATE_ERROR = -1; 37104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 38104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Log a warning if a texture is larger along a dimension 39104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static final int MAX_TEXTURE_SIZE = 4096; 40104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 41104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected int mId = -1; 42104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected int mState; 43104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 44104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected int mWidth = UNSPECIFIED; 45104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected int mHeight = UNSPECIFIED; 46104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 47104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected int mTextureWidth; 48104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected int mTextureHeight; 49104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 50104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private boolean mHasBorder; 51104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 52104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected GLCanvas mCanvasRef = null; 53104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static WeakHashMap<BasicTexture, Object> sAllTextures 54104c45677660586026a7e74ef8c47d396403d50eMichael Jurka = new WeakHashMap<BasicTexture, Object>(); 55104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private static ThreadLocal sInFinalizer = new ThreadLocal(); 56104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 57104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected BasicTexture(GLCanvas canvas, int id, int state) { 58104c45677660586026a7e74ef8c47d396403d50eMichael Jurka setAssociatedCanvas(canvas); 59104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mId = id; 60104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mState = state; 61104c45677660586026a7e74ef8c47d396403d50eMichael Jurka synchronized (sAllTextures) { 62104c45677660586026a7e74ef8c47d396403d50eMichael Jurka sAllTextures.put(this, null); 63104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 64104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 65104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 66104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected BasicTexture() { 67104c45677660586026a7e74ef8c47d396403d50eMichael Jurka this(null, 0, STATE_UNLOADED); 68104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 69104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 70104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected void setAssociatedCanvas(GLCanvas canvas) { 71104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mCanvasRef = canvas; 72104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 73104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 74104c45677660586026a7e74ef8c47d396403d50eMichael Jurka /** 75104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * Sets the content size of this texture. In OpenGL, the actual texture 76104c45677660586026a7e74ef8c47d396403d50eMichael Jurka * size must be of power of 2, the size of the content may be smaller. 77104c45677660586026a7e74ef8c47d396403d50eMichael Jurka */ 78104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public void setSize(int width, int height) { 79104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mWidth = width; 80104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mHeight = height; 81104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mTextureWidth = width > 0 ? Utils.nextPowerOf2(width) : 0; 82104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mTextureHeight = height > 0 ? Utils.nextPowerOf2(height) : 0; 83104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (mTextureWidth > MAX_TEXTURE_SIZE || mTextureHeight > MAX_TEXTURE_SIZE) { 84104c45677660586026a7e74ef8c47d396403d50eMichael Jurka Log.w(TAG, String.format("texture is too large: %d x %d", 85104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mTextureWidth, mTextureHeight), new Exception()); 86104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 87104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 88104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 89104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public boolean isFlippedVertically() { 90104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return false; 91104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 92104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 93104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int getId() { 94104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mId; 95104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 96104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 97104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 98104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int getWidth() { 99104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mWidth; 100104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 101104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 102104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 103104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int getHeight() { 104104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mHeight; 105104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 106104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 107104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Returns the width rounded to the next power of 2. 108104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int getTextureWidth() { 109104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mTextureWidth; 110104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 111104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 112104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Returns the height rounded to the next power of 2. 113104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public int getTextureHeight() { 114104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mTextureHeight; 115104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 116104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 117104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Returns true if the texture has one pixel transparent border around the 118104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // actual content. This is used to avoid jigged edges. 119104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // 120104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap 121104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially 122104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // covered by the texture will use the color of the edge texel. If we add 123104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // the transparent border, the color of the edge texel will be mixed with 124104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // appropriate amount of transparent. 125104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // 126104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Currently our background is black, so we can draw the thumbnails without 127104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // enabling blending. 128104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public boolean hasBorder() { 129104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mHasBorder; 130104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 131104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 132104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected void setBorder(boolean hasBorder) { 133104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mHasBorder = hasBorder; 134104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 135104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 136104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 137104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public void draw(GLCanvas canvas, int x, int y) { 138104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.drawTexture(this, x, y, getWidth(), getHeight()); 139104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 140104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 141104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 142104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public void draw(GLCanvas canvas, int x, int y, int w, int h) { 143104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.drawTexture(this, x, y, w, h); 144104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 145104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 146104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // onBind is called before GLCanvas binds this texture. 147104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // It should make sure the data is uploaded to GL memory. 148104c45677660586026a7e74ef8c47d396403d50eMichael Jurka abstract protected boolean onBind(GLCanvas canvas); 149104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 150104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // Returns the GL texture target for this texture (e.g. GL_TEXTURE_2D). 151104c45677660586026a7e74ef8c47d396403d50eMichael Jurka abstract protected int getTarget(); 152104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 153104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public boolean isLoaded() { 154104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return mState == STATE_LOADED; 155104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 156104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 157104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // recycle() is called when the texture will never be used again, 158104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // so it can free all resources. 159104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public void recycle() { 160104c45677660586026a7e74ef8c47d396403d50eMichael Jurka freeResource(); 161104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 162104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 163104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // yield() is called when the texture will not be used temporarily, 164104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // so it can free some resources. 165104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // The default implementation unloads the texture from GL memory, so 166104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // the subclass should make sure it can reload the texture to GL memory 167104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // later, or it will have to override this method. 168104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public void yield() { 169104c45677660586026a7e74ef8c47d396403d50eMichael Jurka freeResource(); 170104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 171104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 172104c45677660586026a7e74ef8c47d396403d50eMichael Jurka private void freeResource() { 173104c45677660586026a7e74ef8c47d396403d50eMichael Jurka GLCanvas canvas = mCanvasRef; 174104c45677660586026a7e74ef8c47d396403d50eMichael Jurka if (canvas != null && mId != -1) { 175104c45677660586026a7e74ef8c47d396403d50eMichael Jurka canvas.unloadTexture(this); 176104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mId = -1; // Don't free it again. 177104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 178104c45677660586026a7e74ef8c47d396403d50eMichael Jurka mState = STATE_UNLOADED; 179104c45677660586026a7e74ef8c47d396403d50eMichael Jurka setAssociatedCanvas(null); 180104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 181104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 182104c45677660586026a7e74ef8c47d396403d50eMichael Jurka @Override 183104c45677660586026a7e74ef8c47d396403d50eMichael Jurka protected void finalize() { 184104c45677660586026a7e74ef8c47d396403d50eMichael Jurka sInFinalizer.set(BasicTexture.class); 185104c45677660586026a7e74ef8c47d396403d50eMichael Jurka recycle(); 186104c45677660586026a7e74ef8c47d396403d50eMichael Jurka sInFinalizer.set(null); 187104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 188104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 189104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // This is for deciding if we can call Bitmap's recycle(). 190104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // We cannot call Bitmap's recycle() in finalizer because at that point 191104c45677660586026a7e74ef8c47d396403d50eMichael Jurka // the finalizer of Bitmap may already be called so recycle() will crash. 192104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static boolean inFinalizer() { 193104c45677660586026a7e74ef8c47d396403d50eMichael Jurka return sInFinalizer.get() != null; 194104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 195104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 196104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static void yieldAllTextures() { 197104c45677660586026a7e74ef8c47d396403d50eMichael Jurka synchronized (sAllTextures) { 198104c45677660586026a7e74ef8c47d396403d50eMichael Jurka for (BasicTexture t : sAllTextures.keySet()) { 199104c45677660586026a7e74ef8c47d396403d50eMichael Jurka t.yield(); 200104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 201104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 202104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 203104c45677660586026a7e74ef8c47d396403d50eMichael Jurka 204104c45677660586026a7e74ef8c47d396403d50eMichael Jurka public static void invalidateAllTextures() { 205104c45677660586026a7e74ef8c47d396403d50eMichael Jurka synchronized (sAllTextures) { 206104c45677660586026a7e74ef8c47d396403d50eMichael Jurka for (BasicTexture t : sAllTextures.keySet()) { 207104c45677660586026a7e74ef8c47d396403d50eMichael Jurka t.mState = STATE_UNLOADED; 208104c45677660586026a7e74ef8c47d396403d50eMichael Jurka t.setAssociatedCanvas(null); 209104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 210104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 211104c45677660586026a7e74ef8c47d396403d50eMichael Jurka } 212104c45677660586026a7e74ef8c47d396403d50eMichael Jurka} 213