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