Bug 731570 - Don't re-upload scrollbar texture on opacity change. r=kats

Rather than re-render the scrollbar texture and re-upload it when the opacity
changes, just render/upload it once and use a shader to modify the opacity.
This commit is contained in:
Chris Lord 2012-03-02 12:12:08 +00:00
parent 1c2a06b747
commit 1fdd807090
2 changed files with 95 additions and 24 deletions

View File

@ -172,8 +172,8 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
CairoImage shadowImage = new BufferedCairoImage(controller.getShadowPattern());
mShadowLayer = new NinePatchTileLayer(shadowImage);
mHorizScrollLayer = ScrollbarLayer.create(false);
mVertScrollLayer = ScrollbarLayer.create(true);
mHorizScrollLayer = ScrollbarLayer.create(this, false);
mVertScrollLayer = ScrollbarLayer.create(this, true);
mFadeRunnable = new FadeRunnable();
mFrameTimings = new int[60];

View File

@ -71,6 +71,25 @@ public class ScrollbarLayer extends TileLayer {
private float mOpacity;
private boolean mFinalized = false;
private LayerRenderer mRenderer;
private int mProgram;
private int mPositionHandle;
private int mTextureHandle;
private int mSampleHandle;
private int mTMatrixHandle;
private int mOpacityHandle;
// Fragment shader used to draw the scroll-bar with opacity
private static final String FRAGMENT_SHADER =
"precision mediump float;\n" +
"varying vec2 vTexCoord;\n" +
"uniform sampler2D sTexture;\n" +
"uniform float uOpacity;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(sTexture, vec2(vTexCoord.x, 1.0 - vTexCoord.y));\n" +
" gl_FragColor.a *= uOpacity;\n" +
"}\n";
// Dimensions of the texture image
private static final float TEX_HEIGHT = 8.0f;
private static final float TEX_WIDTH = 8.0f;
@ -121,14 +140,26 @@ public class ScrollbarLayer extends TileLayer {
BAR_SIZE/TEX_WIDTH , 1.0f
};
private ScrollbarLayer(CairoImage image, boolean vertical, ByteBuffer buffer) {
private ScrollbarLayer(LayerRenderer renderer, CairoImage image, boolean vertical, ByteBuffer buffer) {
super(false, image);
mVertical = vertical;
mBuffer = buffer;
mRenderer = renderer;
IntSize size = image.getSize();
mBitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
// Paint a spot to use as the scroll indicator
Paint foregroundPaint = new Paint();
foregroundPaint.setAntiAlias(true);
foregroundPaint.setStyle(Paint.Style.FILL);
foregroundPaint.setColor(Color.argb(127, 0, 0, 0));
mCanvas.drawColor(Color.argb(0, 0, 0, 0), PorterDuff.Mode.CLEAR);
mCanvas.drawCircle(CAP_RADIUS, CAP_RADIUS, CAP_RADIUS, foregroundPaint);
mBitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
}
protected void finalize() throws Throwable {
@ -141,14 +172,55 @@ public class ScrollbarLayer extends TileLayer {
}
}
public static ScrollbarLayer create(boolean vertical) {
public static ScrollbarLayer create(LayerRenderer renderer, boolean vertical) {
// just create an empty image for now, it will get drawn
// on demand anyway
int imageSize = IntSize.nextPowerOfTwo(BAR_SIZE);
ByteBuffer buffer = GeckoAppShell.allocateDirectBuffer(imageSize * imageSize * 4);
CairoImage image = new BufferedCairoImage(buffer, imageSize, imageSize,
CairoImage.FORMAT_ARGB32);
return new ScrollbarLayer(image, vertical, buffer);
return new ScrollbarLayer(renderer, image, vertical, buffer);
}
private void createProgram() {
int vertexShader = LayerRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
LayerRenderer.DEFAULT_VERTEX_SHADER);
int fragmentShader = LayerRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
FRAGMENT_SHADER);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
GLES20.glLinkProgram(mProgram); // creates OpenGL program executables
// Get handles to the shaders' vPosition, aTexCoord, sTexture, and uTMatrix members.
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
mTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTexCoord");
mSampleHandle = GLES20.glGetUniformLocation(mProgram, "sTexture");
mTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uTMatrix");
mOpacityHandle = GLES20.glGetUniformLocation(mProgram, "uOpacity");
}
private void activateProgram() {
// Add the program to the OpenGL environment
GLES20.glUseProgram(mProgram);
// Set the transformation matrix
GLES20.glUniformMatrix4fv(mTMatrixHandle, 1, false,
LayerRenderer.DEFAULT_TEXTURE_MATRIX, 0);
// Enable the arrays from which we get the vertex and texture coordinates
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glEnableVertexAttribArray(mTextureHandle);
GLES20.glUniform1i(mSampleHandle, 0);
GLES20.glUniform1f(mOpacityHandle, mOpacity);
}
private void deactivateProgram() {
GLES20.glDisableVertexAttribArray(mTextureHandle);
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glUseProgram(0);
}
/**
@ -162,7 +234,7 @@ public class ScrollbarLayer extends TileLayer {
}
beginTransaction(); // called on compositor thread
try {
setOpacity(Math.max(mOpacity - FADE_AMOUNT, 0.0f));
mOpacity = Math.max(mOpacity - FADE_AMOUNT, 0.0f);
invalidate();
} finally {
endTransaction();
@ -181,7 +253,7 @@ public class ScrollbarLayer extends TileLayer {
}
beginTransaction(); // called on compositor thread
try {
setOpacity(1.0f);
mOpacity = 1.0f;
invalidate();
} finally {
endTransaction();
@ -189,26 +261,21 @@ public class ScrollbarLayer extends TileLayer {
return true;
}
private void setOpacity(float opacity) {
mOpacity = opacity;
Paint foregroundPaint = new Paint();
foregroundPaint.setAntiAlias(true);
foregroundPaint.setStyle(Paint.Style.FILL);
// use a (a,r,g,b) color of (127,0,0,0), and multiply the alpha by mOpacity for fading
foregroundPaint.setColor(Color.argb(Math.round(mOpacity * 127), 0, 0, 0));
mCanvas.drawColor(Color.argb(0, 0, 0, 0), PorterDuff.Mode.CLEAR);
mCanvas.drawCircle(CAP_RADIUS, CAP_RADIUS, CAP_RADIUS, foregroundPaint);
mBitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
}
@Override
public void draw(RenderContext context) {
if (!initialized())
return;
// Create the shader program, if necessary
// XXX Can the context's LayerRenderer
if (mProgram == 0) {
createProgram();
}
// Enable the shader program
mRenderer.deactivateDefaultProgram();
activateProgram();
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
@ -241,8 +308,8 @@ public class ScrollbarLayer extends TileLayer {
// Get the buffer and handles from the context
FloatBuffer coordBuffer = context.coordBuffer;
int positionHandle = context.positionHandle;
int textureHandle = context.textureHandle;
int positionHandle = mPositionHandle;
int textureHandle = mTextureHandle;
// Make sure we are at position zero in the buffer in case other draw methods did not
// clean up after themselves
@ -398,6 +465,10 @@ public class ScrollbarLayer extends TileLayer {
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
// Enable the default shader program again
deactivateProgram();
mRenderer.activateDefaultProgram();
}
private RectF getVerticalRect(RenderContext context) {