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     protected GLCanvas mCanvasRef = null;
50     private static WeakHashMap<BasicTexture, Object> sAllTextures
51             = new WeakHashMap<BasicTexture, Object>();
52     private static ThreadLocal sInFinalizer = new ThreadLocal();
53 
BasicTexture(GLCanvas canvas, int id, int state)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 
BasicTexture()63     protected BasicTexture() {
64         this(null, 0, STATE_UNLOADED);
65     }
66 
setAssociatedCanvas(GLCanvas canvas)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      */
setSize(int width, int height)75     public void setSize(int width, int height) {
76         mWidth = width;
77         mHeight = height;
78         mTextureWidth = width > 0 ? Utils.nextPowerOf2(width) : 0;
79         mTextureHeight = height > 0 ? Utils.nextPowerOf2(height) : 0;
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 
getId()86     public int getId() {
87         return mId;
88     }
89 
90     @Override
getWidth()91     public int getWidth() {
92         return mWidth;
93     }
94 
95     @Override
getHeight()96     public int getHeight() {
97         return mHeight;
98     }
99 
100     // Returns the width rounded to the next power of 2.
getTextureWidth()101     public int getTextureWidth() {
102         return mTextureWidth;
103     }
104 
105     // Returns the height rounded to the next power of 2.
getTextureHeight()106     public int getTextureHeight() {
107         return mTextureHeight;
108     }
109 
110     @Override
draw(GLCanvas canvas, int x, int y)111     public void draw(GLCanvas canvas, int x, int y) {
112         canvas.drawTexture(this, x, y, getWidth(), getHeight());
113     }
114 
115     @Override
draw(GLCanvas canvas, int x, int y, int w, int h)116     public void draw(GLCanvas canvas, int x, int y, int w, int h) {
117         canvas.drawTexture(this, x, y, w, h);
118     }
119 
120     // onBind is called before GLCanvas binds this texture.
121     // It should make sure the data is uploaded to GL memory.
onBind(GLCanvas canvas)122     abstract protected boolean onBind(GLCanvas canvas);
123 
isLoaded()124     public boolean isLoaded() {
125         return mState == STATE_LOADED;
126     }
127 
128     // recycle() is called when the texture will never be used again,
129     // so it can free all resources.
recycle()130     public void recycle() {
131         freeResource();
132     }
133 
134     // yield() is called when the texture will not be used temporarily,
135     // so it can free some resources.
136     // The default implementation unloads the texture from GL memory, so
137     // the subclass should make sure it can reload the texture to GL memory
138     // later, or it will have to override this method.
yield()139     public void yield() {
140         freeResource();
141     }
142 
freeResource()143     private void freeResource() {
144         GLCanvas canvas = mCanvasRef;
145         if (canvas != null && mId != -1) {
146             canvas.unloadTexture(this);
147             mId = -1; // Don't free it again.
148         }
149         mState = STATE_UNLOADED;
150         setAssociatedCanvas(null);
151     }
152 
153     @Override
finalize()154     protected void finalize() {
155         sInFinalizer.set(BasicTexture.class);
156         recycle();
157         sInFinalizer.set(null);
158     }
159 
yieldAllTextures()160     public static void yieldAllTextures() {
161         synchronized (sAllTextures) {
162             for (BasicTexture t : sAllTextures.keySet()) {
163                 t.yield();
164             }
165         }
166     }
167 
invalidateAllTextures()168     public static void invalidateAllTextures() {
169         synchronized (sAllTextures) {
170             for (BasicTexture t : sAllTextures.keySet()) {
171                 t.mState = STATE_UNLOADED;
172                 t.setAssociatedCanvas(null);
173             }
174         }
175     }
176 }
177