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