1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17a4eae1abb4f2547dfbda84301ee764ce35464881John Reckpackage com.android.gallery3d.glrenderer;
18a4eae1abb4f2547dfbda84301ee764ce35464881John Reck
19a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport android.util.Log;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.WeakHashMap;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// BasicTexture is a Texture corresponds to a real GL texture.
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// The state of a BasicTexture indicates whether its data is loaded to GL memory.
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// If a BasicTexture is loaded into GL memory, it has a GL texture id.
28a4eae1abb4f2547dfbda84301ee764ce35464881John Reckpublic abstract class BasicTexture implements Texture {
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @SuppressWarnings("unused")
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "BasicTexture";
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected static final int UNSPECIFIED = -1;
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected static final int STATE_UNLOADED = 0;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected static final int STATE_LOADED = 1;
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected static final int STATE_ERROR = -1;
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
386b41f11759977c4d34755627858192b7e9cd33c7Bobby Georgescu    // Log a warning if a texture is larger along a dimension
396b41f11759977c4d34755627858192b7e9cd33c7Bobby Georgescu    private static final int MAX_TEXTURE_SIZE = 4096;
4049affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin
417da54d7e41e04ea5122009b40de19be0724e1ca4George Mount    protected int mId = -1;
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected int mState;
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected int mWidth = UNSPECIFIED;
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected int mHeight = UNSPECIFIED;
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
47a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    protected int mTextureWidth;
48a8f3473271cb4bfc5b47f520402bad7cddb5d3e8Owen Lin    protected int mTextureHeight;
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
501a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    private boolean mHasBorder;
511a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang
523950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang    protected GLCanvas mCanvasRef = null;
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static WeakHashMap<BasicTexture, Object> sAllTextures
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            = new WeakHashMap<BasicTexture, Object>();
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static ThreadLocal sInFinalizer = new ThreadLocal();
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected BasicTexture(GLCanvas canvas, int id, int state) {
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setAssociatedCanvas(canvas);
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mId = id;
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mState = state;
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (sAllTextures) {
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            sAllTextures.put(this, null);
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected BasicTexture() {
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        this(null, 0, STATE_UNLOADED);
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void setAssociatedCanvas(GLCanvas canvas) {
713950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang        mCanvasRef = canvas;
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    /**
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * Sets the content size of this texture. In OpenGL, the actual texture
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * size must be of power of 2, the size of the content may be smaller.
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     */
78a4eae1abb4f2547dfbda84301ee764ce35464881John Reck    public void setSize(int width, int height) {
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mWidth = width;
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mHeight = height;
8126353bc4c528057ae171d89ad3251586b832e69bJohn Reck        mTextureWidth = width > 0 ? Utils.nextPowerOf2(width) : 0;
8226353bc4c528057ae171d89ad3251586b832e69bJohn Reck        mTextureHeight = height > 0 ? Utils.nextPowerOf2(height) : 0;
8349affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin        if (mTextureWidth > MAX_TEXTURE_SIZE || mTextureHeight > MAX_TEXTURE_SIZE) {
8449affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin            Log.w(TAG, String.format("texture is too large: %d x %d",
8549affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin                    mTextureWidth, mTextureHeight), new Exception());
8649affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin        }
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
8944a1b22eb7098819ac0251764b9fa686d8339d66George Mount    public boolean isFlippedVertically() {
9044a1b22eb7098819ac0251764b9fa686d8339d66George Mount      return false;
9144a1b22eb7098819ac0251764b9fa686d8339d66George Mount    }
9244a1b22eb7098819ac0251764b9fa686d8339d66George Mount
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getId() {
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mId;
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
977817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getWidth() {
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mWidth;
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1027817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getHeight() {
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mHeight;
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // Returns the width rounded to the next power of 2.
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getTextureWidth() {
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mTextureWidth;
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // Returns the height rounded to the next power of 2.
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getTextureHeight() {
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mTextureHeight;
1151a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    }
1161a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang
1171a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // Returns true if the texture has one pixel transparent border around the
1181a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // actual content. This is used to avoid jigged edges.
1191a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    //
1201a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // The jigged edges appear because we use GL_CLAMP_TO_EDGE for texture wrap
1211a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // mode (GL_CLAMP is not available in OpenGL ES), so a pixel partially
1221a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // covered by the texture will use the color of the edge texel. If we add
1231a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // the transparent border, the color of the edge texel will be mixed with
1241a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // appropriate amount of transparent.
1251a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    //
1261a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // Currently our background is black, so we can draw the thumbnails without
1271a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    // enabling blending.
1281a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    public boolean hasBorder() {
1291a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang        return mHasBorder;
1301a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    }
1311a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang
1321a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang    protected void setBorder(boolean hasBorder) {
1331a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang        mHasBorder = hasBorder;
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1367817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void draw(GLCanvas canvas, int x, int y) {
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        canvas.drawTexture(this, x, y, getWidth(), getHeight());
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1417817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @Override
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void draw(GLCanvas canvas, int x, int y, int w, int h) {
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        canvas.drawTexture(this, x, y, w, h);
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // onBind is called before GLCanvas binds this texture.
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // It should make sure the data is uploaded to GL memory.
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    abstract protected boolean onBind(GLCanvas canvas);
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
150b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang    // Returns the GL texture target for this texture (e.g. GL_TEXTURE_2D).
151b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang    abstract protected int getTarget();
152b29a27f475a2c449abdda8d4e03d30914feed8c6Chih-Chung Chang
15337c605949219b8bf54c165c34d6405f5f2989f50Owen Lin    public boolean isLoaded() {
1543950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang        return mState == STATE_LOADED;
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // recycle() is called when the texture will never be used again,
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // so it can free all resources.
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void recycle() {
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        freeResource();
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // yield() is called when the texture will not be used temporarily,
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // so it can free some resources.
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // The default implementation unloads the texture from GL memory, so
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // the subclass should make sure it can reload the texture to GL memory
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // later, or it will have to override this method.
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void yield() {
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        freeResource();
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void freeResource() {
1733950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang        GLCanvas canvas = mCanvasRef;
1747da54d7e41e04ea5122009b40de19be0724e1ca4George Mount        if (canvas != null && mId != -1) {
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            canvas.unloadTexture(this);
1767da54d7e41e04ea5122009b40de19be0724e1ca4George Mount            mId = -1; // Don't free it again.
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
17837c605949219b8bf54c165c34d6405f5f2989f50Owen Lin        mState = STATE_UNLOADED;
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setAssociatedCanvas(null);
180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void finalize() {
184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        sInFinalizer.set(BasicTexture.class);
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        recycle();
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        sInFinalizer.set(null);
187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // This is for deciding if we can call Bitmap's recycle().
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // We cannot call Bitmap's recycle() in finalizer because at that point
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // the finalizer of Bitmap may already be called so recycle() will crash.
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static boolean inFinalizer() {
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return sInFinalizer.get() != null;
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static void yieldAllTextures() {
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (sAllTextures) {
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (BasicTexture t : sAllTextures.keySet()) {
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                t.yield();
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
2033950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang
2043950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang    public static void invalidateAllTextures() {
2053950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang        synchronized (sAllTextures) {
2063950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang            for (BasicTexture t : sAllTextures.keySet()) {
2073950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang                t.mState = STATE_UNLOADED;
2083950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang                t.setAssociatedCanvas(null);
2093950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang            }
2103950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang        }
2113950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang    }
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
213