1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org
.mozilla
.gecko
.gfx
;
8 import android
.graphics
.Rect
;
9 import android
.opengl
.GLES20
;
10 import android
.util
.Log
;
12 import java
.nio
.ByteBuffer
;
15 * Base class for tile layers, which encapsulate the logic needed to draw textured tiles in OpenGL
18 public abstract class TileLayer
extends Layer
{
19 private static final String LOGTAG
= "GeckoTileLayer";
21 private final Rect mDirtyRect
;
22 private IntSize mSize
;
23 private int[] mTextureIDs
;
25 protected final CairoImage mImage
;
27 public CairoImage
getImage() {
31 public enum PaintMode
{ NORMAL
, REPEAT
, STRETCH
};
32 private PaintMode mPaintMode
;
34 public TileLayer(CairoImage image
, PaintMode paintMode
) {
35 super(image
== null ?
null : image
.getSize());
37 mPaintMode
= paintMode
;
39 mSize
= new IntSize(0, 0);
40 mDirtyRect
= new Rect();
43 protected boolean repeats() { return mPaintMode
== PaintMode
.REPEAT
; }
44 protected boolean stretches() { return mPaintMode
== PaintMode
.STRETCH
; }
45 protected int getTextureID() { return mTextureIDs
[0]; }
46 protected boolean initialized() { return mImage
!= null && mTextureIDs
!= null; }
49 protected void finalize() throws Throwable
{
51 if (mTextureIDs
!= null)
52 TextureReaper
.get().add(mTextureIDs
);
58 public void destroy() {
63 } catch (Exception ex
) {
64 Log
.e(LOGTAG
, "error clearing buffers: ", ex
);
68 public void setPaintMode(PaintMode mode
) {
73 * Invalidates the entire buffer so that it will be uploaded again. Only valid inside a
76 public void invalidate() {
78 throw new RuntimeException("invalidate() is only valid inside a transaction");
79 IntSize bufferSize
= mImage
.getSize();
80 mDirtyRect
.set(0, 0, bufferSize
.width
, bufferSize
.height
);
83 private void validateTexture() {
84 /* Calculate the ideal texture size. This must be a power of two if
85 * the texture is repeated or OpenGL ES 2.0 isn't supported, as
86 * OpenGL ES 2.0 is required for NPOT texture support (without
87 * extensions), but doesn't support repeating NPOT textures.
89 * XXX Currently, we don't pick a GLES 2.0 context, so always round.
91 IntSize textureSize
= mImage
.getSize().nextPowerOfTwo();
93 if (!textureSize
.equals(mSize
)) {
96 // Delete the old texture
97 if (mTextureIDs
!= null) {
98 TextureReaper
.get().add(mTextureIDs
);
101 // Free the texture immediately, so we don't incur a
102 // temporarily increased memory usage.
103 TextureReaper
.get().reap();
109 protected void performUpdates(RenderContext context
) {
110 super.performUpdates(context
);
112 // Reallocate the texture if the size has changed
115 // Don't do any work if the image has an invalid size.
116 if (!mImage
.getSize().isPositive())
119 // If we haven't allocated a texture, assume the whole region is dirty
120 if (mTextureIDs
== null) {
123 uploadDirtyRect(mDirtyRect
);
126 mDirtyRect
.setEmpty();
129 private void uploadFullTexture() {
130 IntSize bufferSize
= mImage
.getSize();
131 uploadDirtyRect(new Rect(0, 0, bufferSize
.width
, bufferSize
.height
));
134 private void uploadDirtyRect(Rect dirtyRect
) {
135 // If we have nothing to upload, just return for now
136 if (dirtyRect
.isEmpty())
139 // It's possible that the buffer will be null, check for that and return
140 ByteBuffer imageBuffer
= mImage
.getBuffer();
141 if (imageBuffer
== null)
144 if (mTextureIDs
== null) {
145 mTextureIDs
= new int[1];
146 GLES20
.glGenTextures(mTextureIDs
.length
, mTextureIDs
, 0);
149 int cairoFormat
= mImage
.getFormat();
150 CairoGLInfo glInfo
= new CairoGLInfo(cairoFormat
);
152 bindAndSetGLParameters();
154 // XXX TexSubImage2D is too broken to rely on Adreno, and very slow
155 // on other chipsets, so we always upload the entire buffer.
156 IntSize bufferSize
= mImage
.getSize();
158 GLES20
.glTexImage2D(GLES20
.GL_TEXTURE_2D
, 0, glInfo
.internalFormat
, mSize
.width
,
159 mSize
.height
, 0, glInfo
.format
, glInfo
.type
, imageBuffer
);
163 private void bindAndSetGLParameters() {
164 GLES20
.glActiveTexture(GLES20
.GL_TEXTURE0
);
165 GLES20
.glBindTexture(GLES20
.GL_TEXTURE_2D
, mTextureIDs
[0]);
166 GLES20
.glTexParameterf(GLES20
.GL_TEXTURE_2D
, GLES20
.GL_TEXTURE_MIN_FILTER
,
168 GLES20
.glTexParameterf(GLES20
.GL_TEXTURE_2D
, GLES20
.GL_TEXTURE_MAG_FILTER
,
171 int repeatMode
= repeats() ? GLES20
.GL_REPEAT
: GLES20
.GL_CLAMP_TO_EDGE
;
172 GLES20
.glTexParameterf(GLES20
.GL_TEXTURE_2D
, GLES20
.GL_TEXTURE_WRAP_S
, repeatMode
);
173 GLES20
.glTexParameterf(GLES20
.GL_TEXTURE_2D
, GLES20
.GL_TEXTURE_WRAP_T
, repeatMode
);