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