Fix various draw ops that may incorrectly not scissor
bug:8965976
Also consolidates quickReject scissor-ing and scissor-less paths.
Renamed plain 'quickReject' method, as it has sideEffects beyond what
the java and skia canvases do.
Change-Id: I4bdf874d3c8f469d283eae1e71c5e7ea53d47016
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 5866404..f3592a3 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -298,7 +298,7 @@
static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
- return renderer->quickReject(left, top, right, bottom);
+ return renderer->quickRejectNoScissor(left, top, right, bottom);
}
static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz,
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index f25ec2d..0d4dd1a 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -356,22 +356,26 @@
level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
}
}
+
+ bool clipToBoundsNeeded = mClipToBounds;
if (mAlpha < 1) {
if (mCaching) {
ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
+ clipToBoundsNeeded = false; // clipping done by layer
} else if (!mHasOverlappingRendering) {
ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
} else {
int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
- if (mClipToBounds) {
+ if (clipToBoundsNeeded) {
flags |= SkCanvas::kClipToLayer_SaveFlag;
+ clipToBoundsNeeded = false; // clipping done by save layer
}
ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
(float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
(int)(mAlpha * 255), flags);
}
}
- if (mClipToBounds && !mCaching) {
+ if (clipToBoundsNeeded) {
ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
(float) mRight - mLeft, (float) mBottom - mTop);
}
@@ -406,9 +410,11 @@
renderer.concatMatrix(mTransformMatrix);
}
}
+ bool clipToBoundsNeeded = mClipToBounds;
if (mAlpha < 1) {
if (mCaching) {
renderer.setOverrideLayerAlpha(mAlpha);
+ clipToBoundsNeeded = false; // clipping done by layer
} else if (!mHasOverlappingRendering) {
renderer.scaleAlpha(mAlpha);
} else {
@@ -416,15 +422,16 @@
// have to pass it into this call. In fact, this information might be in the
// location/size info that we store with the new native transform data.
int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
- if (mClipToBounds) {
+ if (clipToBoundsNeeded) {
saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
+ clipToBoundsNeeded = false; // clipping done by saveLayer
}
handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
mClipToBounds);
}
}
- if (mClipToBounds && !mCaching) {
+ if (clipToBoundsNeeded) {
handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
PROPERTY_SAVECOUNT, mClipToBounds);
}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c68cc06..05f43a9 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -993,6 +993,10 @@
const Rect& rect = layer->layer;
const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
+ bool clipRequired = false;
+ quickRejectNoScissor(rect, &clipRequired); // safely ignore return, should never be rejected
+ mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+
if (fboLayer) {
endTiling();
@@ -1568,8 +1572,9 @@
return mSnapshot->getLocalClip();
}
-bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) {
- if (mSnapshot->isIgnored()) {
+bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
+ bool* clipRequired) {
+ if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
return true;
}
@@ -1580,23 +1585,10 @@
Rect clipRect(*mSnapshot->clipRect);
clipRect.snapToPixelBoundaries();
- return !clipRect.intersects(r);
-}
+ if (!clipRect.intersects(r)) return true;
-bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
- Rect& transformed, Rect& clip) {
- if (mSnapshot->isIgnored()) {
- return true;
- }
-
- transformed.set(left, top, right, bottom);
- currentTransform().mapRect(transformed);
- transformed.snapToPixelBoundaries();
-
- clip.set(*mSnapshot->clipRect);
- clip.snapToPixelBoundaries();
-
- return !clip.intersects(transformed);
+ if (clipRequired) *clipRequired = !clipRect.contains(r);
+ return false;
}
bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
@@ -1610,23 +1602,15 @@
}
bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
- if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
+ bool clipRequired = false;
+ if (quickRejectNoScissor(left, top, right, bottom, &clipRequired)) {
return true;
}
- Rect r(left, top, right, bottom);
- currentTransform().mapRect(r);
- r.snapToPixelBoundaries();
-
- Rect clipRect(*mSnapshot->clipRect);
- clipRect.snapToPixelBoundaries();
-
- bool rejected = !clipRect.intersects(r);
- if (!isDeferred() && !rejected) {
- mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r));
+ if (!isDeferred()) {
+ mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
}
-
- return rejected;
+ return false;
}
void OpenGLRenderer::debugClip() {
@@ -2163,6 +2147,9 @@
return DrawGlInfo::kStatusDone;
}
+ // TODO: use quickReject on bounds from vertices
+ mCaches.enableScissor();
+
float left = FLT_MAX;
float top = FLT_MAX;
float right = FLT_MIN;
@@ -2829,6 +2816,8 @@
return DrawGlInfo::kStatusDone;
}
+ mCaches.enableScissor();
+
float x = 0.0f;
float y = 0.0f;
const bool pureTranslate = currentTransform().isPureTranslate();
@@ -2984,6 +2973,9 @@
return DrawGlInfo::kStatusDone;
}
+ // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
+ mCaches.enableScissor();
+
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
fontRenderer.setFont(paint, mat4::identity());
fontRenderer.setTextureFiltering(true);
@@ -3059,10 +3051,9 @@
}
}
- Rect transformed;
- Rect clip;
+ bool clipRequired = false;
const bool rejected = quickRejectNoScissor(x, y,
- x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip);
+ x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired);
if (rejected) {
if (transform && !transform->isIdentity()) {
@@ -3073,7 +3064,7 @@
updateLayer(layer, true);
- mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clip.contains(transformed));
+ mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
mCaches.activeTexture(0);
if (CC_LIKELY(!layer->region.isEmpty())) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index ad9b1b9..5b7f90d 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -252,11 +252,31 @@
virtual void concatMatrix(SkMatrix* matrix);
ANDROID_API const Rect& getClipBounds();
- ANDROID_API bool quickReject(float left, float top, float right, float bottom);
+
+ /**
+ * Performs a quick reject but adjust the bounds to account for stroke width if necessary
+ */
+ bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
+
+ /**
+ * Returns false and sets scissor based upon bounds if drawing won't be clipped out
+ */
+ bool quickReject(float left, float top, float right, float bottom);
bool quickReject(const Rect& bounds) {
return quickReject(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
- bool quickRejectNoScissor(float left, float top, float right, float bottom);
+
+ /**
+ * Same as quickReject, without the scissor, instead returning clipRequired through pointer.
+ * clipRequired will be only set if not rejected
+ */
+ ANDROID_API bool quickRejectNoScissor(float left, float top, float right, float bottom,
+ bool* clipRequired = NULL);
+ bool quickRejectNoScissor(const Rect& bounds, bool* clipRequired = NULL) {
+ return quickRejectNoScissor(bounds.left, bounds.top, bounds.right, bounds.bottom,
+ clipRequired);
+ }
+
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool clipPath(SkPath* path, SkRegion::Op op);
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
@@ -604,18 +624,6 @@
void setStencilFromClip();
/**
- * Performs a quick reject but does not affect the scissor. Returns
- * the transformed rect to test and the current clip.
- */
- bool quickRejectNoScissor(float left, float top, float right, float bottom,
- Rect& transformed, Rect& clip);
-
- /**
- * Performs a quick reject but adjust the bounds to account for stroke width if necessary
- */
- bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);
-
- /**
* Given the local bounds of the layer, calculates ...
*/
void calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer);
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 87c6c105..7531769 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -24,7 +24,7 @@
namespace android {
namespace uirenderer {
-#define RECT_STRING "%4.2f %4.2f %4.2f %4.2f"
+#define RECT_STRING "%7.2f %7.2f %7.2f %7.2f"
#define RECT_ARGS(r) \
(r).left, (r).top, (r).right, (r).bottom