Home | History | Annotate | Download | only in ui
      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