diff options
-rw-r--r-- | core/java/android/view/SurfaceView.java | 13 | ||||
-rw-r--r-- | graphics/java/android/graphics/BaseCanvas.java | 10 | ||||
-rw-r--r-- | graphics/java/android/graphics/BaseRecordingCanvas.java | 12 | ||||
-rw-r--r-- | libs/hwui/Android.bp | 2 | ||||
-rw-r--r-- | libs/hwui/DisplayList.h | 4 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 5 | ||||
-rw-r--r-- | libs/hwui/SkiaCanvas.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/SkiaCanvas.h | 2 | ||||
-rw-r--r-- | libs/hwui/hwui/Canvas.h | 2 | ||||
-rw-r--r-- | libs/hwui/jni/android_graphics_Canvas.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/HolePunch.cpp | 21 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/HolePunch.h | 30 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/RenderNodeDrawable.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.h | 10 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 21 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.h | 3 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/TransformCanvas.cpp | 43 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/TransformCanvas.h | 35 |
19 files changed, 235 insertions, 7 deletions
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 82106b09ca5c..2b96a14b04d4 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -33,7 +33,6 @@ import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; -import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; import android.graphics.RenderNode; @@ -670,10 +669,16 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (mClipSurfaceToBounds && mClipBounds != null) { mTmpRect.intersect(mClipBounds); } - canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom, - mCornerRadius, mCornerRadius, mRoundedViewportPaint); + canvas.punchHole( + mTmpRect.left, + mTmpRect.top, + mTmpRect.right, + mTmpRect.bottom, + mCornerRadius, + mCornerRadius + ); } else { - canvas.drawColor(0, PorterDuff.Mode.CLEAR); + canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f); } } diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index 54f9fa81b9b7..a612265793a3 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -673,6 +673,13 @@ public abstract class BaseCanvas { /** * @hide */ + public void punchHole(float left, float top, float right, float bottom, float rx, float ry) { + nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry); + } + + /** + * @hide + */ public void setHwBitmapsInSwModeEnabled(boolean enabled) { mAllowHwBitmapsInSwMode = enabled; } @@ -815,4 +822,7 @@ public abstract class BaseCanvas { private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath, float hOffset, float vOffset, int flags, long nativePaint); + + private static native void nPunchHole(long renderer, float left, float top, float right, + float bottom, float rx, float ry); } diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java index a8922e84514a..a998ba870f74 100644 --- a/graphics/java/android/graphics/BaseRecordingCanvas.java +++ b/graphics/java/android/graphics/BaseRecordingCanvas.java @@ -610,6 +610,14 @@ public class BaseRecordingCanvas extends Canvas { indices, indexOffset, indexCount, paint.getNativeInstance()); } + /** + * @hide + */ + @Override + public void punchHole(float left, float top, float right, float bottom, float rx, float ry) { + nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry); + } + @FastNative private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left, float top, long nativePaintOrZero, int canvasDensity, int screenDensity, @@ -735,4 +743,8 @@ public class BaseRecordingCanvas extends Canvas { @FastNative private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath, float hOffset, float vOffset, int flags, long nativePaint); + + @FastNative + private static native void nPunchHole(long renderer, float left, float top, float right, + float bottom, float rx, float ry); } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 9b9af6f75aeb..c75b21f739cd 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -464,10 +464,12 @@ cc_defaults { "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 ca5f853066f2..894b479c11db 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -72,6 +72,10 @@ public: 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 f5b2675c7fe6..e9eae3d14760 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -255,15 +255,19 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu 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 39ea53b6e3b3..988141fe191d 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 @@ private: UsageHint mUsageHint = UsageHint::Unknown; + bool mHasHolePunches; + // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER public: /** @@ -294,6 +297,8 @@ public: 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 28d2b4cec0e1..4c4a15295690 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 @@ const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const { 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 9ab2b106dbfa..e0a0be54fb39 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -60,6 +60,8 @@ public: 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 d1bdb712e911..c1feb767b459 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -155,6 +155,8 @@ public: 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 89fb8bb2a2a0..a611f7ce2d14 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 @@ static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) { 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 @@ static const JNINativeMethod gDrawMethods[] = { {"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 000000000000..2b2bca6df5a3 --- /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 000000000000..92c6f7721a08 --- /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 cb0ff8d871d4..5627a7e27232 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 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { 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 1136e58e43d8..90e9bc6a1a28 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -163,7 +163,7 @@ public: private: std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables; - + bool mHasHolePunches; public: void appendVD(VectorDrawableRoot* r) { appendVD(r, SkMatrix::I()); } @@ -171,6 +171,14 @@ public: 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 61f9960c4d8d..82814def6962 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -53,6 +53,27 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in 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 ff03e0c5f6d6..06f2a27d22a5 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 @@ public: 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 000000000000..6bfbb0d270b7 --- /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 000000000000..47f77f107441 --- /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; +}; |