Holepunch layers for SurfaceView
Update RenderNodeDrawable to hole punch areas into
layers created for SurfaceView
Bug: 184297961
Test: Added CTS test to SurfaceViewTests
Change-Id: I1f03a4fe34c5a8b7411ebe728ea3d4195fcd1fac
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 9b9af6f..c75b21f 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -464,10 +464,12 @@
"canvas/CanvasOpBuffer.cpp",
"canvas/CanvasOpRasterizer.cpp",
"effects/StretchEffect.cpp",
+ "pipeline/skia/HolePunch.cpp",
"pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/RenderNodeDrawable.cpp",
"pipeline/skia/ReorderBarrierDrawables.cpp",
+ "pipeline/skia/TransformCanvas.cpp",
"renderthread/Frame.cpp",
"renderthread/RenderTask.cpp",
"renderthread/TimeLord.cpp",
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index ca5f853..894b479 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -72,6 +72,10 @@
return mImpl && !(mImpl->isEmpty());
}
+ [[nodiscard]] bool hasHolePunches() const {
+ return mImpl && mImpl->hasHolePunches();
+ }
+
[[nodiscard]] bool containsProjectionReceiver() const {
return mImpl && mImpl->containsProjectionReceiver();
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index f5b2675..e9eae3d 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -255,15 +255,19 @@
if (mDisplayList) {
info.out.hasFunctors |= mDisplayList.hasFunctor();
+ mHasHolePunches = mDisplayList.hasHolePunches();
bool isDirty = mDisplayList.prepareListAndChildren(
observer, info, childFunctorsNeedLayer,
- [](RenderNode* child, TreeObserver& observer, TreeInfo& info,
- bool functorsNeedLayer) {
+ [this](RenderNode* child, TreeObserver& observer, TreeInfo& info,
+ bool functorsNeedLayer) {
child->prepareTreeImpl(observer, info, functorsNeedLayer);
+ mHasHolePunches |= child->hasHolePunches();
});
if (isDirty) {
damageSelf(info);
}
+ } else {
+ mHasHolePunches = false;
}
pushLayerUpdate(info);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 39ea53b..988141f 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -35,6 +35,7 @@
#include "DisplayList.h"
#include "Matrix.h"
#include "RenderProperties.h"
+#include "pipeline/skia/HolePunch.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaLayer.h"
@@ -284,6 +285,8 @@
UsageHint mUsageHint = UsageHint::Unknown;
+ bool mHasHolePunches;
+
// METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
public:
/**
@@ -294,6 +297,8 @@
return std::move(mAvailableDisplayList);
}
+ bool hasHolePunches() { return mHasHolePunches; }
+
/**
* Attach unused displayList to this node for potential future reuse.
*/
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 28d2b4c..4c4a152 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -23,6 +23,7 @@
#include "hwui/MinikinUtils.h"
#include "hwui/PaintFilter.h"
#include "pipeline/skia/AnimatedDrawables.h"
+#include "pipeline/skia/HolePunch.h"
#include <SkAndroidFrameworkUtils.h>
#include <SkAnimatedImage.h>
@@ -244,6 +245,13 @@
return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr;
}
+void SkiaCanvas::punchHole(const SkRRect& rect) {
+ SkPaint paint = SkPaint();
+ paint.setColor(0);
+ paint.setBlendMode(SkBlendMode::kClear);
+ mCanvas->drawRRect(rect, paint);
+}
+
// ----------------------------------------------------------------------------
// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 9ab2b10..e0a0be5 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -60,6 +60,8 @@
LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
}
+ virtual void punchHole(const SkRRect& rect) override;
+
virtual void setBitmap(const SkBitmap& bitmap) override;
virtual bool isOpaque() override;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index d1bdb71..c1feb76 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -155,6 +155,8 @@
LOG_ALWAYS_FATAL("Not supported");
}
+ virtual void punchHole(const SkRRect& rect) = 0;
+
// ----------------------------------------------------------------------------
// Canvas state operations
// ----------------------------------------------------------------------------
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index 89fb8bb..a611f7c 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -35,6 +35,7 @@
#include "SkGraphics.h"
#include "SkRegion.h"
#include "SkVertices.h"
+#include "SkRRect.h"
namespace minikin {
class MeasuredText;
@@ -667,6 +668,11 @@
Canvas::setCompatibilityVersion(apiLevel);
}
+static void punchHole(JNIEnv* env, jobject, jlong canvasPtr, jfloat left, jfloat top, jfloat right,
+ jfloat bottom, jfloat rx, jfloat ry) {
+ auto canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry));
+}
}; // namespace CanvasJNI
@@ -740,6 +746,7 @@
{"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
{"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
{"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
+ {"nPunchHole", "(JFFFFFF)V", (void*) CanvasJNI::punchHole}
};
int register_android_graphics_Canvas(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/HolePunch.cpp b/libs/hwui/pipeline/skia/HolePunch.cpp
new file mode 100644
index 0000000..2b2bca6
--- /dev/null
+++ b/libs/hwui/pipeline/skia/HolePunch.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "HolePunch.h"
+#include <string>
+
+using namespace android::uirenderer::skiapipeline;
+
+const std::string HOLE_PUNCH_ANNOTATION = "surface_hole_punch";
diff --git a/libs/hwui/pipeline/skia/HolePunch.h b/libs/hwui/pipeline/skia/HolePunch.h
new file mode 100644
index 0000000..92c6f77
--- /dev/null
+++ b/libs/hwui/pipeline/skia/HolePunch.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include "SkRRect.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+const static std::string HOLE_PUNCH_ANNOTATION;
+
+} // namespace skiapipeline
+} // namespace uirenderer
+} // namespace android
\ No newline at end of file
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index cb0ff8d..5627a7e 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -18,6 +18,7 @@
#include <SkPaintFilterCanvas.h>
#include "RenderNode.h"
#include "SkiaDisplayList.h"
+#include "TransformCanvas.h"
#include "utils/TraceUtils.h"
#include <include/effects/SkImageFilters.h>
@@ -256,6 +257,11 @@
canvas->drawAnnotation(bounds, String8::format(
"SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
}
+
+ if (renderNode->hasHolePunches()) {
+ TransformCanvas transformCanvas(canvas);
+ displayList->draw(&transformCanvas);
+ }
canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
SkCanvas::kStrict_SrcRectConstraint);
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 1136e58..90e9bc6 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -163,7 +163,7 @@
private:
std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables;
-
+ bool mHasHolePunches;
public:
void appendVD(VectorDrawableRoot* r) { appendVD(r, SkMatrix::I()); }
@@ -171,6 +171,14 @@
mVectorDrawables.push_back(Pair<VectorDrawableRoot*, SkMatrix>(r, mat));
}
+ void setHasHolePunches(bool hasHolePunches) {
+ mHasHolePunches = hasHolePunches;
+ }
+
+ bool hasHolePunches() {
+ return mHasHolePunches;
+ }
+
std::vector<AnimatedImageDrawable*> mAnimatedImages;
DisplayListData mDisplayList;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 61f9960..82814de 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -53,6 +53,27 @@
mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
SkiaCanvas::reset(&mRecorder);
+ mDisplayList->setHasHolePunches(false);
+}
+
+void SkiaRecordingCanvas::punchHole(const SkRRect& rect) {
+ // Add the marker annotation to allow HWUI to determine where the current
+ // clip/transformation should be applied
+ SkVector vector = rect.getSimpleRadii();
+ const int dataSize = 2;
+ float data[dataSize];
+ data[0] = vector.x();
+ data[1] = vector.y();
+ mRecorder.drawAnnotation(rect.rect(), HOLE_PUNCH_ANNOTATION.c_str(),
+ SkData::MakeWithCopy(data, dataSize));
+
+ // Clear the current rect within the layer itself
+ SkPaint paint = SkPaint();
+ paint.setColor(0);
+ paint.setBlendMode(SkBlendMode::kClear);
+ mRecorder.drawRRect(rect, paint);
+
+ mDisplayList->setHasHolePunches(true);
}
std::unique_ptr<SkiaDisplayList> SkiaRecordingCanvas::finishRecording() {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index ff03e0c..06f2a27 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -15,6 +15,7 @@
*/
#pragma once
+#include "HolePunch.h"
#include "RecordingCanvas.h"
#include "ReorderBarrierDrawables.h"
#include "SkiaCanvas.h"
@@ -43,6 +44,8 @@
initDisplayList(renderNode, width, height);
}
+ virtual void punchHole(const SkRRect& rect) override;
+
virtual void finishRecording(uirenderer::RenderNode* destination) override;
std::unique_ptr<SkiaDisplayList> finishRecording();
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.cpp b/libs/hwui/pipeline/skia/TransformCanvas.cpp
new file mode 100644
index 0000000..6bfbb0d
--- /dev/null
+++ b/libs/hwui/pipeline/skia/TransformCanvas.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "TransformCanvas.h"
+#include "HolePunch.h"
+#include "SkData.h"
+#include "SkDrawable.h"
+
+using namespace android::uirenderer::skiapipeline;
+
+void TransformCanvas::onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) {
+ if (HOLE_PUNCH_ANNOTATION == key) {
+ auto* rectParams = static_cast<const float*>(value->data());
+ float radiusX = rectParams[0];
+ float radiusY = rectParams[1];
+ SkRRect roundRect = SkRRect::MakeRectXY(rect, radiusX, radiusY);
+
+ SkPaint paint;
+ paint.setColor(0);
+ paint.setBlendMode(SkBlendMode::kClear);
+ mWrappedCanvas->drawRRect(roundRect, paint);
+ }
+}
+
+void TransformCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
+ drawable->draw(this, matrix);
+}
+
+bool TransformCanvas::onFilter(SkPaint& paint) const {
+ return false;
+}
diff --git a/libs/hwui/pipeline/skia/TransformCanvas.h b/libs/hwui/pipeline/skia/TransformCanvas.h
new file mode 100644
index 0000000..47f77f1
--- /dev/null
+++ b/libs/hwui/pipeline/skia/TransformCanvas.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <include/core/SkCanvas.h>
+#include "SkPaintFilterCanvas.h"
+
+class TransformCanvas : public SkPaintFilterCanvas {
+public:
+ TransformCanvas(SkCanvas* target) : SkPaintFilterCanvas(target), mWrappedCanvas(target) {}
+
+protected:
+ bool onFilter(SkPaint& paint) const override;
+
+protected:
+ void onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) override;
+ void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override;
+
+private:
+ // We don't own the canvas so just maintain a raw pointer to it
+ SkCanvas* mWrappedCanvas;
+};