• 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.graphics.Bitmap;
20 import android.graphics.Bitmap.Config;
21 import android.opengl.GLUtils;
22 import android.util.Pair;
23 
24 import com.android.gallery3d.common.Utils;
25 
26 import java.util.HashMap;
27 
28 // UploadedTextures use a Bitmap for the content of the texture.
29 //
30 // Subclasses should implement onGetBitmap() to provide the Bitmap and
31 // implement onFreeBitmap(mBitmap) which will be called when the Bitmap
32 // is not needed anymore.
33 //
34 // isContentValid() is meaningful only when the isLoaded() returns true.
35 // It means whether the content needs to be updated.
36 //
37 // The user of this class should call recycle() when the texture is not
38 // needed anymore.
39 //
40 // By default an UploadedTexture is opaque (so it can be drawn faster without
41 // blending). The user or subclass can override it using setOpaque().
42 public abstract class UploadedTexture extends BasicTexture {
43 
44     // To prevent keeping allocation the borders, we store those used borders here.
45     // Since the length will be power of two, it won't use too much memory.
46     private static HashMap<BorderKey, Bitmap> sBorderLines = new HashMap<BorderKey, Bitmap>();
47 
48     private static class BorderKey extends Pair<Config, Integer> {
BorderKey(Config config, boolean vertical, int length)49         public BorderKey(Config config, boolean vertical, int length) {
50             super(config, vertical ? length : -length);
51         }
52     }
53 
54     private boolean mContentValid = true;
55     protected Bitmap mBitmap;
56 
UploadedTexture()57     protected UploadedTexture() {
58         super(null, 0, STATE_UNLOADED);
59     }
60 
getBorderLine(boolean vertical, Config config, int length)61     private static Bitmap getBorderLine(boolean vertical, Config config, int length) {
62         BorderKey key = new BorderKey(config, vertical, length);
63         Bitmap bitmap = sBorderLines.get(key);
64         if (bitmap == null) {
65             bitmap = vertical
66                     ? Bitmap.createBitmap(1, length, config)
67                     : Bitmap.createBitmap(length, 1, config);
68             sBorderLines.put(key, bitmap);
69         }
70         return bitmap;
71     }
72 
getBitmap()73     private Bitmap getBitmap() {
74         if (mBitmap == null) {
75             mBitmap = onGetBitmap();
76             int w = mBitmap.getWidth();
77             int h = mBitmap.getHeight();
78             if (mWidth == UNSPECIFIED) {
79                 setSize(w, h);
80             }
81         }
82         return mBitmap;
83     }
84 
freeBitmap()85     private void freeBitmap() {
86         Utils.assertTrue(mBitmap != null);
87         onFreeBitmap(mBitmap);
88         mBitmap = null;
89     }
90 
91     @Override
getWidth()92     public int getWidth() {
93         if (mWidth == UNSPECIFIED) getBitmap();
94         return mWidth;
95     }
96 
97     @Override
getHeight()98     public int getHeight() {
99         if (mWidth == UNSPECIFIED) getBitmap();
100         return mHeight;
101     }
102 
onGetBitmap()103     protected abstract Bitmap onGetBitmap();
104 
onFreeBitmap(Bitmap bitmap)105     protected abstract void onFreeBitmap(Bitmap bitmap);
106 
invalidateContent()107     protected void invalidateContent() {
108         if (mBitmap != null) freeBitmap();
109         mContentValid = false;
110         mWidth = UNSPECIFIED;
111         mHeight = UNSPECIFIED;
112     }
113 
114     /**
115      * Whether the content on GPU is valid.
116      */
isContentValid()117     public boolean isContentValid() {
118         return isLoaded() && mContentValid;
119     }
120 
121     /**
122      * Updates the content on GPU's memory.
123      * @param canvas
124      */
updateContent(GLCanvas canvas)125     public void updateContent(GLCanvas canvas) {
126         if (!isLoaded()) {
127             uploadToCanvas(canvas);
128         } else if (!mContentValid) {
129             Bitmap bitmap = getBitmap();
130             int format = GLUtils.getInternalFormat(bitmap);
131             int type = GLUtils.getType(bitmap);
132             canvas.texSubImage2D(this, 0, 0, bitmap, format, type);
133             freeBitmap();
134             mContentValid = true;
135         }
136     }
137 
uploadToCanvas(GLCanvas canvas)138     private void uploadToCanvas(GLCanvas canvas) {
139         Bitmap bitmap = getBitmap();
140         if (bitmap != null) {
141             try {
142                 int bWidth = bitmap.getWidth();
143                 int bHeight = bitmap.getHeight();
144                 int texWidth = getTextureWidth();
145                 int texHeight = getTextureHeight();
146 
147                 Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
148 
149                 // Upload the bitmap to a new texture.
150                 mId = canvas.getGLId().generateTexture();
151                 canvas.setTextureParameters(this);
152 
153                 if (bWidth == texWidth && bHeight == texHeight) {
154                     canvas.initializeTexture(this, bitmap);
155                 } else {
156                     int format = GLUtils.getInternalFormat(bitmap);
157                     int type = GLUtils.getType(bitmap);
158                     Config config = bitmap.getConfig();
159 
160                     canvas.initializeTextureSize(this, format, type);
161                     canvas.texSubImage2D(this, 0, 0, bitmap, format, type);
162 
163                     // Right border
164                     if (bWidth < texWidth) {
165                         Bitmap line = getBorderLine(true, config, texHeight);
166                         canvas.texSubImage2D(this, bWidth, 0, line, format, type);
167                     }
168 
169                     // Bottom border
170                     if (bHeight < texHeight) {
171                         Bitmap line = getBorderLine(false, config, texWidth);
172                         canvas.texSubImage2D(this, 0, bHeight, line, format, type);
173                     }
174                 }
175             } finally {
176                 freeBitmap();
177             }
178             // Update texture state.
179             setAssociatedCanvas(canvas);
180             mState = STATE_LOADED;
181             mContentValid = true;
182         } else {
183             mState = STATE_ERROR;
184             throw new RuntimeException("Texture load fail, no bitmap");
185         }
186     }
187 
188     @Override
onBind(GLCanvas canvas)189     protected boolean onBind(GLCanvas canvas) {
190         updateContent(canvas);
191         return isContentValid();
192     }
193 
194     @Override
recycle()195     public void recycle() {
196         super.recycle();
197         if (mBitmap != null) freeBitmap();
198     }
199 }
200