Deferred layer updates
Change-Id: I83d9e564fe274db658dcee9e0cc5bbf9223ebb49
This commit is contained in:
@@ -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
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user