1f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka/* 2f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Copyright (C) 2010 The Android Open Source Project 3f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 4f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * you may not use this file except in compliance with the License. 6f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * You may obtain a copy of the License at 7f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 8f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * 10f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Unless required by applicable law or agreed to in writing, software 11f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * See the License for the specific language governing permissions and 14f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * limitations under the License. 15f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka */ 16f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 17f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkapackage com.android.gallery3d.glrenderer; 18f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 19f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Bitmap; 20f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.graphics.Bitmap.Config; 21f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport android.opengl.GLUtils; 222c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyalimport android.util.Pair; 23f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 2463142a8ddcb6a21b666d2a731fdf1c585afd13eeSunny Goyalimport com.android.gallery3d.common.Utils; 25105593bea0ff8b152e3bce39deaec263a34208f8Adam Cohen 26f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkaimport java.util.HashMap; 27f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 28f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// UploadedTextures use a Bitmap for the content of the texture. 29f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// 30f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// Subclasses should implement onGetBitmap() to provide the Bitmap and 31f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// implement onFreeBitmap(mBitmap) which will be called when the Bitmap 32f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// is not needed anymore. 33f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// 34f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// isContentValid() is meaningful only when the isLoaded() returns true. 35f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// It means whether the content needs to be updated. 36f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// 37f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// The user of this class should call recycle() when the texture is not 38f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// needed anymore. 39f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// 40f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// By default an UploadedTexture is opaque (so it can be drawn faster without 41f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka// blending). The user or subclass can override it using setOpaque(). 42f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurkapublic abstract class UploadedTexture extends BasicTexture { 43f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 44f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // To prevent keeping allocation the borders, we store those used borders here. 45f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Since the length will be power of two, it won't use too much memory. 462c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal private static HashMap<BorderKey, Bitmap> sBorderLines = new HashMap<BorderKey, Bitmap>(); 47f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 482c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal private static class BorderKey extends Pair<Config, Integer> { 492c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal public BorderKey(Config config, boolean vertical, int length) { 502c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal super(config, vertical ? length : -length); 512c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal } 522c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal } 53f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 542c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal private boolean mContentValid = true; 55f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected Bitmap mBitmap; 56f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 57f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected UploadedTexture() { 58f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka super(null, 0, STATE_UNLOADED); 59f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 60f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 612c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal private static Bitmap getBorderLine(boolean vertical, Config config, int length) { 622c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal BorderKey key = new BorderKey(config, vertical, length); 63f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap bitmap = sBorderLines.get(key); 64f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (bitmap == null) { 65f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka bitmap = vertical 66f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka ? Bitmap.createBitmap(1, length, config) 67f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka : Bitmap.createBitmap(length, 1, config); 682c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal sBorderLines.put(key, bitmap); 69f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 70f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return bitmap; 71f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 72f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 73f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private Bitmap getBitmap() { 74f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mBitmap == null) { 75f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mBitmap = onGetBitmap(); 762c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal int w = mBitmap.getWidth(); 772c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal int h = mBitmap.getHeight(); 78f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mWidth == UNSPECIFIED) { 79f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka setSize(w, h); 80f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 81f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 82f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mBitmap; 83f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 84f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 85f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private void freeBitmap() { 8663142a8ddcb6a21b666d2a731fdf1c585afd13eeSunny Goyal Utils.assertTrue(mBitmap != null); 87f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka onFreeBitmap(mBitmap); 88f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mBitmap = null; 89f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 90f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 91f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 92f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getWidth() { 93f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mWidth == UNSPECIFIED) getBitmap(); 94f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mWidth; 95f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 96f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 97f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 98f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public int getHeight() { 99f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mWidth == UNSPECIFIED) getBitmap(); 100f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return mHeight; 101f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 102f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 103f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected abstract Bitmap onGetBitmap(); 104f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 105f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected abstract void onFreeBitmap(Bitmap bitmap); 106f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 107f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected void invalidateContent() { 108f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mBitmap != null) freeBitmap(); 109f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mContentValid = false; 110f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mWidth = UNSPECIFIED; 111f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mHeight = UNSPECIFIED; 112f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 113f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 114f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka /** 115f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Whether the content on GPU is valid. 116f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka */ 117f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public boolean isContentValid() { 118f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return isLoaded() && mContentValid; 119f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 120f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 121f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka /** 122f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * Updates the content on GPU's memory. 123f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka * @param canvas 124f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka */ 125f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void updateContent(GLCanvas canvas) { 126f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (!isLoaded()) { 127f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka uploadToCanvas(canvas); 128f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else if (!mContentValid) { 129f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap bitmap = getBitmap(); 130f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int format = GLUtils.getInternalFormat(bitmap); 131f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int type = GLUtils.getType(bitmap); 1322c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal canvas.texSubImage2D(this, 0, 0, bitmap, format, type); 133f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka freeBitmap(); 134f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mContentValid = true; 135f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 136f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 137f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 138f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka private void uploadToCanvas(GLCanvas canvas) { 139f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap bitmap = getBitmap(); 140f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (bitmap != null) { 141f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka try { 142f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int bWidth = bitmap.getWidth(); 143f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int bHeight = bitmap.getHeight(); 144f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int texWidth = getTextureWidth(); 145f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int texHeight = getTextureHeight(); 146f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 14763142a8ddcb6a21b666d2a731fdf1c585afd13eeSunny Goyal Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight); 148f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 149f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Upload the bitmap to a new texture. 150f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mId = canvas.getGLId().generateTexture(); 151f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka canvas.setTextureParameters(this); 152f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 153f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (bWidth == texWidth && bHeight == texHeight) { 154f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka canvas.initializeTexture(this, bitmap); 155f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 156f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int format = GLUtils.getInternalFormat(bitmap); 157f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka int type = GLUtils.getType(bitmap); 158f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Config config = bitmap.getConfig(); 159f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 160f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka canvas.initializeTextureSize(this, format, type); 1612c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal canvas.texSubImage2D(this, 0, 0, bitmap, format, type); 162f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 163f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Right border 1642c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal if (bWidth < texWidth) { 165f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap line = getBorderLine(true, config, texHeight); 1662c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal canvas.texSubImage2D(this, bWidth, 0, line, format, type); 167f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 168f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 169f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Bottom border 1702c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal if (bHeight < texHeight) { 171f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka Bitmap line = getBorderLine(false, config, texWidth); 1722c7071f9393741acb281a0e67a6381e1c4905cbcSunny Goyal canvas.texSubImage2D(this, 0, bHeight, line, format, type); 173f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 174f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 175f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } finally { 176f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka freeBitmap(); 177f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 178f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka // Update texture state. 179f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka setAssociatedCanvas(canvas); 180f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mState = STATE_LOADED; 181f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mContentValid = true; 182f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } else { 183f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka mState = STATE_ERROR; 184f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka throw new RuntimeException("Texture load fail, no bitmap"); 185f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 186f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 187f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 188f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 189f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka protected boolean onBind(GLCanvas canvas) { 190f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka updateContent(canvas); 191f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka return isContentValid(); 192f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 193f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka 194f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka @Override 195f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka public void recycle() { 196f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka super.recycle(); 197f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka if (mBitmap != null) freeBitmap(); 198f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka } 199f1b220be2b401f203cfb490f2e78af32700ef4bbMichael Jurka} 200