mobile/android/base/gfx/TileLayer.java

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 package org.mozilla.gecko.gfx;
michael@0 7
michael@0 8 import android.graphics.Rect;
michael@0 9 import android.opengl.GLES20;
michael@0 10 import android.util.Log;
michael@0 11
michael@0 12 import java.nio.ByteBuffer;
michael@0 13
michael@0 14 /**
michael@0 15 * Base class for tile layers, which encapsulate the logic needed to draw textured tiles in OpenGL
michael@0 16 * ES.
michael@0 17 */
michael@0 18 public abstract class TileLayer extends Layer {
michael@0 19 private static final String LOGTAG = "GeckoTileLayer";
michael@0 20
michael@0 21 private final Rect mDirtyRect;
michael@0 22 private IntSize mSize;
michael@0 23 private int[] mTextureIDs;
michael@0 24
michael@0 25 protected final CairoImage mImage;
michael@0 26
michael@0 27 public enum PaintMode { NORMAL, REPEAT, STRETCH };
michael@0 28 private PaintMode mPaintMode;
michael@0 29
michael@0 30 public TileLayer(CairoImage image, PaintMode paintMode) {
michael@0 31 super(image.getSize());
michael@0 32
michael@0 33 mPaintMode = paintMode;
michael@0 34 mImage = image;
michael@0 35 mSize = new IntSize(0, 0);
michael@0 36 mDirtyRect = new Rect();
michael@0 37 }
michael@0 38
michael@0 39 protected boolean repeats() { return mPaintMode == PaintMode.REPEAT; }
michael@0 40 protected boolean stretches() { return mPaintMode == PaintMode.STRETCH; }
michael@0 41 protected int getTextureID() { return mTextureIDs[0]; }
michael@0 42 protected boolean initialized() { return mImage != null && mTextureIDs != null; }
michael@0 43
michael@0 44 @Override
michael@0 45 protected void finalize() throws Throwable {
michael@0 46 try {
michael@0 47 if (mTextureIDs != null)
michael@0 48 TextureReaper.get().add(mTextureIDs);
michael@0 49 } finally {
michael@0 50 super.finalize();
michael@0 51 }
michael@0 52 }
michael@0 53
michael@0 54 public void destroy() {
michael@0 55 try {
michael@0 56 if (mImage != null) {
michael@0 57 mImage.destroy();
michael@0 58 }
michael@0 59 } catch (Exception ex) {
michael@0 60 Log.e(LOGTAG, "error clearing buffers: ", ex);
michael@0 61 }
michael@0 62 }
michael@0 63
michael@0 64 public void setPaintMode(PaintMode mode) {
michael@0 65 mPaintMode = mode;
michael@0 66 }
michael@0 67
michael@0 68 /**
michael@0 69 * Invalidates the entire buffer so that it will be uploaded again. Only valid inside a
michael@0 70 * transaction.
michael@0 71 */
michael@0 72
michael@0 73 public void invalidate() {
michael@0 74 if (!inTransaction())
michael@0 75 throw new RuntimeException("invalidate() is only valid inside a transaction");
michael@0 76 IntSize bufferSize = mImage.getSize();
michael@0 77 mDirtyRect.set(0, 0, bufferSize.width, bufferSize.height);
michael@0 78 }
michael@0 79
michael@0 80 private void validateTexture() {
michael@0 81 /* Calculate the ideal texture size. This must be a power of two if
michael@0 82 * the texture is repeated or OpenGL ES 2.0 isn't supported, as
michael@0 83 * OpenGL ES 2.0 is required for NPOT texture support (without
michael@0 84 * extensions), but doesn't support repeating NPOT textures.
michael@0 85 *
michael@0 86 * XXX Currently, we don't pick a GLES 2.0 context, so always round.
michael@0 87 */
michael@0 88 IntSize textureSize = mImage.getSize().nextPowerOfTwo();
michael@0 89
michael@0 90 if (!textureSize.equals(mSize)) {
michael@0 91 mSize = textureSize;
michael@0 92
michael@0 93 // Delete the old texture
michael@0 94 if (mTextureIDs != null) {
michael@0 95 TextureReaper.get().add(mTextureIDs);
michael@0 96 mTextureIDs = null;
michael@0 97
michael@0 98 // Free the texture immediately, so we don't incur a
michael@0 99 // temporarily increased memory usage.
michael@0 100 TextureReaper.get().reap();
michael@0 101 }
michael@0 102 }
michael@0 103 }
michael@0 104
michael@0 105 @Override
michael@0 106 protected void performUpdates(RenderContext context) {
michael@0 107 super.performUpdates(context);
michael@0 108
michael@0 109 // Reallocate the texture if the size has changed
michael@0 110 validateTexture();
michael@0 111
michael@0 112 // Don't do any work if the image has an invalid size.
michael@0 113 if (!mImage.getSize().isPositive())
michael@0 114 return;
michael@0 115
michael@0 116 // If we haven't allocated a texture, assume the whole region is dirty
michael@0 117 if (mTextureIDs == null) {
michael@0 118 uploadFullTexture();
michael@0 119 } else {
michael@0 120 uploadDirtyRect(mDirtyRect);
michael@0 121 }
michael@0 122
michael@0 123 mDirtyRect.setEmpty();
michael@0 124 }
michael@0 125
michael@0 126 private void uploadFullTexture() {
michael@0 127 IntSize bufferSize = mImage.getSize();
michael@0 128 uploadDirtyRect(new Rect(0, 0, bufferSize.width, bufferSize.height));
michael@0 129 }
michael@0 130
michael@0 131 private void uploadDirtyRect(Rect dirtyRect) {
michael@0 132 // If we have nothing to upload, just return for now
michael@0 133 if (dirtyRect.isEmpty())
michael@0 134 return;
michael@0 135
michael@0 136 // It's possible that the buffer will be null, check for that and return
michael@0 137 ByteBuffer imageBuffer = mImage.getBuffer();
michael@0 138 if (imageBuffer == null)
michael@0 139 return;
michael@0 140
michael@0 141 if (mTextureIDs == null) {
michael@0 142 mTextureIDs = new int[1];
michael@0 143 GLES20.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
michael@0 144 }
michael@0 145
michael@0 146 int cairoFormat = mImage.getFormat();
michael@0 147 CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
michael@0 148
michael@0 149 bindAndSetGLParameters();
michael@0 150
michael@0 151 // XXX TexSubImage2D is too broken to rely on on Adreno, and very slow
michael@0 152 // on other chipsets, so we always upload the entire buffer.
michael@0 153 IntSize bufferSize = mImage.getSize();
michael@0 154 if (mSize.equals(bufferSize)) {
michael@0 155 GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width,
michael@0 156 mSize.height, 0, glInfo.format, glInfo.type, imageBuffer);
michael@0 157 } else {
michael@0 158 // Our texture has been expanded to the next power of two.
michael@0 159 // XXX We probably never want to take this path, so throw an exception.
michael@0 160 throw new RuntimeException("Buffer/image size mismatch in TileLayer!");
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 private void bindAndSetGLParameters() {
michael@0 165 GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
michael@0 166 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIDs[0]);
michael@0 167 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
michael@0 168 GLES20.GL_LINEAR);
michael@0 169 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
michael@0 170 GLES20.GL_LINEAR);
michael@0 171
michael@0 172 int repeatMode = repeats() ? GLES20.GL_REPEAT : GLES20.GL_CLAMP_TO_EDGE;
michael@0 173 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, repeatMode);
michael@0 174 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, repeatMode);
michael@0 175 }
michael@0 176 }
michael@0 177

mercurial