summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Canvas.h4
-rw-r--r--libs/hwui/DisplayListCanvas.cpp8
-rw-r--r--libs/hwui/OpenGLRenderer.cpp19
-rwxr-xr-xlibs/hwui/OpenGLRenderer.h8
-rw-r--r--libs/hwui/SkiaCanvas.cpp6
5 files changed, 34 insertions, 11 deletions
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
index aa24673..562bb80 100644
--- a/libs/hwui/Canvas.h
+++ b/libs/hwui/Canvas.h
@@ -47,6 +47,10 @@ public:
* It is useful for testing and clients (e.g. Picture/Movie) that expect to
* draw their contents into an SkCanvas.
*
+ * The SkCanvas returned is *only* valid until another Canvas call is made
+ * that would change state (e.g. matrix or clip). Clients of asSkCanvas()
+ * are responsible for *not* persisting this pointer.
+ *
* Further, the returned SkCanvas should NOT be unref'd and is valid until
* this canvas is destroyed or a new bitmap is set.
*/
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 02a4877..b08187b 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -99,6 +99,14 @@ SkCanvas* DisplayListCanvas::asSkCanvas() {
if (!mSkiaCanvasProxy) {
mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
}
+
+ // SkCanvas instances default to identity transform, but should inherit
+ // the state of this Canvas; if this code was in the SkiaCanvasProxy
+ // constructor, we couldn't cache mSkiaCanvasProxy.
+ SkMatrix parentTransform;
+ getMatrix(&parentTransform);
+ mSkiaCanvasProxy.get()->setMatrix(parentTransform);
+
return mSkiaCanvasProxy.get();
}
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 433e178..3d48fa6 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1097,7 +1097,7 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top,
}
void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
- if (bounds.intersect(mState.currentClipRect())) {
+ if (CC_LIKELY(!bounds.isEmpty() && bounds.intersect(mState.currentClipRect()))) {
bounds.snapToPixelBoundaries();
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
if (!dirty.isEmpty()) {
@@ -1146,7 +1146,7 @@ void OpenGLRenderer::clearLayerRegions() {
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
.build();
- renderGlop(glop, false);
+ renderGlop(glop, GlopRenderType::LayerClear);
if (scissorChanged) mRenderState.scissor().setEnabled(true);
} else {
@@ -1454,10 +1454,15 @@ void OpenGLRenderer::debugClip() {
#endif
}
-void OpenGLRenderer::renderGlop(const Glop& glop, bool clearLayer) {
+void OpenGLRenderer::renderGlop(const Glop& glop, GlopRenderType type) {
// TODO: It would be best if we could do this before quickRejectSetupScissor()
// changes the scissor test state
- if (clearLayer) clearLayerRegions();
+ if (type != GlopRenderType::LayerClear) {
+ // Regular draws need to clear the dirty area on the layer before they start drawing on top
+ // of it. If this draw *is* a layer clear, it skips the clear step (since it would
+ // infinitely recurse)
+ clearLayerRegions();
+ }
if (mState.getDirtyClip()) {
if (mRenderState.scissor().isEnabled()) {
@@ -1467,7 +1472,7 @@ void OpenGLRenderer::renderGlop(const Glop& glop, bool clearLayer) {
setStencilFromClip();
}
mRenderState.render(glop);
- if (!mRenderState.stencil().isWriteEnabled()) {
+ if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
// TODO: specify more clearly when a draw should dirty the layer.
// is writing to the stencil the only time we should ignore this?
dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
@@ -1540,7 +1545,7 @@ void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entr
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
.build();
- renderGlop(glop);
+ renderGlop(glop, GlopRenderType::Multi);
}
void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
@@ -1738,7 +1743,7 @@ void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entr
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
.build();
- renderGlop(glop);
+ renderGlop(glop, GlopRenderType::Multi);
}
void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5850dc6..800a9f9 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -535,7 +535,13 @@ protected:
RenderState& mRenderState;
private:
- void renderGlop(const Glop& glop, bool clearLayer = true);
+ enum class GlopRenderType {
+ Standard,
+ Multi,
+ LayerClear
+ };
+
+ void renderGlop(const Glop& glop, GlopRenderType type = GlopRenderType::Standard);
/**
* Discards the content of the framebuffer if supported by the driver.
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index a323065..6cf66cd 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -419,12 +419,12 @@ bool SkiaCanvas::quickRejectPath(const SkPath& path) const {
bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
mCanvas->clipRect(rect, op);
- return mCanvas->isClipEmpty();
+ return !mCanvas->isClipEmpty();
}
bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) {
mCanvas->clipPath(*path, op);
- return mCanvas->isClipEmpty();
+ return !mCanvas->isClipEmpty();
}
bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
@@ -438,7 +438,7 @@ bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
} else {
mCanvas->clipRect(SkRect::MakeEmpty(), op);
}
- return mCanvas->isClipEmpty();
+ return !mCanvas->isClipEmpty();
}
// ----------------------------------------------------------------------------