Deferred layer updates

Change-Id: I83d9e564fe274db658dcee9e0cc5bbf9223ebb49
This commit is contained in:
Romain Guy
2012-03-02 13:37:47 -08:00
parent d8f45c16a8
commit 2bf68f063b
9 changed files with 112 additions and 39 deletions

View File

@@ -157,6 +157,8 @@ class GLES20Canvas extends HardwareCanvas {
static native void nDestroyLayer(int layerId);
static native void nDestroyLayerDeferred(int layerId);
static native void nFlushLayer(int layerId);
static native void nUpdateRenderLayer(int layerId, int renderer, int displayList,
int left, int top, int right, int bottom);
static native boolean nCopyLayer(int layerId, int bitmap);
///////////////////////////////////////////////////////////////////////////
@@ -191,6 +193,13 @@ class GLES20Canvas extends HardwareCanvas {
private static native int nGetMaximumTextureWidth();
private static native int nGetMaximumTextureHeight();
/**
* Returns the native OpenGLRenderer object.
*/
int getRenderer() {
return mRenderer;
}
///////////////////////////////////////////////////////////////////////////
// Setup
///////////////////////////////////////////////////////////////////////////

View File

@@ -18,6 +18,7 @@ package android.view;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
/**
* An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
@@ -95,4 +96,11 @@ class GLES20RenderLayer extends GLES20Layer {
@Override
void setTransform(Matrix matrix) {
}
@Override
void redraw(DisplayList displayList, Rect dirtyRect) {
GLES20Canvas.nUpdateRenderLayer(mLayer, mCanvas.getRenderer(),
((GLES20DisplayList) displayList).getNativeDisplayList(),
dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
}
}

View File

@@ -18,6 +18,7 @@ package android.view;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
/**
@@ -81,4 +82,8 @@ class GLES20TextureLayer extends GLES20Layer {
void setTransform(Matrix matrix) {
GLES20Canvas.nSetTextureLayerTransform(mLayer, matrix.native_instance);
}
@Override
void redraw(DisplayList displayList, Rect dirtyRect) {
}
}

View File

@@ -19,6 +19,7 @@ package android.view;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
/**
* A hardware layer can be used to render graphics operations into a hardware
@@ -163,4 +164,13 @@ abstract class HardwareLayer {
* @param matrix The transform to apply to the layer.
*/
abstract void setTransform(Matrix matrix);
/**
* Specifies the display list to use to refresh the layer.
*
* @param displayList The display list containing the drawing commands to
* execute in this layer
* @param dirtyRect The dirty region of the layer that needs to be redrawn
*/
abstract void redraw(DisplayList displayList, Rect dirtyRect);
}

View File

@@ -315,7 +315,7 @@ public class TextureView extends View {
}
@Override
HardwareLayer getHardwareLayer() {
HardwareLayer getHardwareLayer(boolean immediateRefresh) {
if (mLayer == null) {
if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
return null;

View File

@@ -10125,7 +10125,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* dynamic.
*/
boolean hasStaticLayer() {
return mLayerType == LAYER_TYPE_NONE;
return true;
}
/**
@@ -10172,7 +10172,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
if (mAttachInfo.mHardwareRenderer != null &&
mAttachInfo.mHardwareRenderer.isEnabled() &&
mAttachInfo.mHardwareRenderer.validate()) {
getHardwareLayer();
getHardwareLayer(true);
}
break;
case LAYER_TYPE_SOFTWARE:
@@ -10194,7 +10194,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @return A HardwareLayer ready to render, or null if an error occurred.
*/
HardwareLayer getHardwareLayer() {
HardwareLayer getHardwareLayer(boolean immediateRefresh) {
if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null ||
!mAttachInfo.mHardwareRenderer.isEnabled()) {
return null;
@@ -10224,41 +10224,32 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
return null;
}
HardwareCanvas currentCanvas = mAttachInfo.mHardwareCanvas;
final HardwareCanvas canvas = mHardwareLayer.start(currentCanvas);
// Make sure all the GPU resources have been properly allocated
if (canvas == null) {
mHardwareLayer.end(currentCanvas);
return null;
}
mAttachInfo.mHardwareCanvas = canvas;
try {
canvas.setViewport(width, height);
canvas.onPreDraw(mLocalDirtyRect);
if (!immediateRefresh) {
mHardwareLayer.redraw(getDisplayList(), mLocalDirtyRect);
mLocalDirtyRect.setEmpty();
final int restoreCount = canvas.save();
computeScroll();
canvas.translate(-mScrollX, -mScrollY);
mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
mPrivateFlags &= ~DIRTY_MASK;
dispatchDraw(canvas);
} else {
draw(canvas);
} else {
HardwareCanvas currentCanvas = mAttachInfo.mHardwareCanvas;
final HardwareCanvas canvas = mHardwareLayer.start(currentCanvas);
// Make sure all the GPU resources have been properly allocated
if (canvas == null) {
mHardwareLayer.end(currentCanvas);
return null;
}
mAttachInfo.mHardwareCanvas = canvas;
try {
canvas.setViewport(width, height);
canvas.onPreDraw(mLocalDirtyRect);
mLocalDirtyRect.setEmpty();
canvas.drawDisplayList(getDisplayList(), mRight - mLeft, mBottom - mTop, null,
DisplayList.FLAG_CLIP_CHILDREN);
} finally {
canvas.onPostDraw();
mHardwareLayer.end(currentCanvas);
mAttachInfo.mHardwareCanvas = currentCanvas;
}
canvas.restoreToCount(restoreCount);
} finally {
canvas.onPostDraw();
mHardwareLayer.end(currentCanvas);
mAttachInfo.mHardwareCanvas = currentCanvas;
}
}
@@ -11226,7 +11217,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
if (hasNoCache) {
boolean layerRendered = false;
if (layerType == LAYER_TYPE_HARDWARE) {
final HardwareLayer layer = getHardwareLayer();
final HardwareLayer layer = getHardwareLayer(false);
if (layer != null && layer.isValid()) {
mLayerPaint.setAlpha((int) (alpha * 255));
((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint);

View File

@@ -770,6 +770,12 @@ static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject cl
LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, renderTarget, transform);
}
static void android_view_GLES20Canvas_updateRenderLayer(JNIEnv* env, jobject clazz,
Layer* layer, OpenGLRenderer* renderer, DisplayList* displayList,
jint left, jint top, jint right, jint bottom) {
layer->updateDeferred(renderer, displayList, left, top, right, bottom);
}
static void android_view_GLES20Canvas_setTextureLayerTransform(JNIEnv* env, jobject clazz,
Layer* layer, SkMatrix* matrix) {
@@ -953,13 +959,15 @@ static JNINativeMethod gMethods[] = {
{ "nCreateTextureLayer", "(Z[I)I", (void*) android_view_GLES20Canvas_createTextureLayer },
{ "nUpdateTextureLayer", "(IIIZLandroid/graphics/SurfaceTexture;)V",
(void*) android_view_GLES20Canvas_updateTextureLayer },
{ "nSetTextureLayerTransform", "(II)V", (void*) android_view_GLES20Canvas_setTextureLayerTransform },
{ "nUpdateRenderLayer", "(IIIIIII)V", (void*) android_view_GLES20Canvas_updateRenderLayer },
{ "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer },
{ "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred },
{ "nFlushLayer", "(I)V", (void*) android_view_GLES20Canvas_flushLayer },
{ "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer },
{ "nCopyLayer", "(II)Z", (void*) android_view_GLES20Canvas_copyLayer },
{ "nSetTextureLayerTransform", "(II)V", (void*) android_view_GLES20Canvas_setTextureLayerTransform },
{ "nGetMaximumTextureWidth", "()I", (void*) android_view_GLES20Canvas_getMaxTextureWidth },
{ "nGetMaximumTextureHeight", "()I", (void*) android_view_GLES20Canvas_getMaxTextureHeight },

View File

@@ -37,6 +37,10 @@ namespace uirenderer {
// Layers
///////////////////////////////////////////////////////////////////////////////
// Forward declarations
class OpenGLRenderer;
class DisplayList;
/**
* A layer has dimensions and is backed by an OpenGL texture or FBO.
*/
@@ -51,6 +55,9 @@ struct Layer {
texture.width = layerWidth;
texture.height = layerHeight;
colorFilter = NULL;
deferredUpdateScheduled = false;
renderer = NULL;
displayList = NULL;
}
~Layer() {
@@ -77,6 +84,15 @@ struct Layer {
regionRect.translate(layer.left, layer.top);
}
void updateDeferred(OpenGLRenderer* renderer, DisplayList* displayList,
int left, int top, int right, int bottom) {
this->renderer = renderer;
this->displayList = displayList;
const Rect r(left, top, right, bottom);
dirtyRect.unionWith(r);
deferredUpdateScheduled = true;
}
inline uint32_t getWidth() {
return texture.width;
}
@@ -234,6 +250,14 @@ struct Layer {
uint16_t* meshIndices;
GLsizei meshElementCount;
/**
* Used for deferred updates.
*/
bool deferredUpdateScheduled;
OpenGLRenderer* renderer;
DisplayList* displayList;
Rect dirtyRect;
private:
/**
* Name of the FBO used to render the layer. If the name is 0

View File

@@ -2364,6 +2364,24 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
return;
}
if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
OpenGLRenderer* renderer = layer->renderer;
Rect& dirty = layer->dirtyRect;
interrupt();
renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend());
renderer->drawDisplayList(layer->displayList, layer->getWidth(), layer->getHeight(),
dirty, DisplayList::kReplayFlag_ClipChildren);
renderer->finish();
resume();
dirty.setEmpty();
layer->deferredUpdateScheduled = false;
layer->renderer = NULL;
layer->displayList = NULL;
}
mCaches.activeTexture(0);
int alpha;