Merge "Holepunch layers for SurfaceView" into sc-dev

This commit is contained in:
Nader Jawad
2021-04-07 17:35:45 +00:00
committed by Android (Google) Code Review
19 changed files with 235 additions and 7 deletions

View File

@@ -33,7 +33,6 @@ import android.graphics.Color;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Region; import android.graphics.Region;
import android.graphics.RenderNode; import android.graphics.RenderNode;
@@ -670,10 +669,16 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
if (mClipSurfaceToBounds && mClipBounds != null) { if (mClipSurfaceToBounds && mClipBounds != null) {
mTmpRect.intersect(mClipBounds); mTmpRect.intersect(mClipBounds);
} }
canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom, canvas.punchHole(
mCornerRadius, mCornerRadius, mRoundedViewportPaint); mTmpRect.left,
mTmpRect.top,
mTmpRect.right,
mTmpRect.bottom,
mCornerRadius,
mCornerRadius
);
} else { } else {
canvas.drawColor(0, PorterDuff.Mode.CLEAR); canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f);
} }
} }

View File

@@ -670,6 +670,13 @@ public abstract class BaseCanvas {
indices, indexOffset, indexCount, paint.getNativeInstance()); indices, indexOffset, indexCount, paint.getNativeInstance());
} }
/**
* @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 * @hide
*/ */
@@ -815,4 +822,7 @@ public abstract class BaseCanvas {
private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath, private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
float hOffset, float vOffset, int flags, long nativePaint); 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);
} }

View File

@@ -610,6 +610,14 @@ public class BaseRecordingCanvas extends Canvas {
indices, indexOffset, indexCount, paint.getNativeInstance()); 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 @FastNative
private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left, private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left,
float top, long nativePaintOrZero, int canvasDensity, int screenDensity, float top, long nativePaintOrZero, int canvasDensity, int screenDensity,
@@ -735,4 +743,8 @@ public class BaseRecordingCanvas extends Canvas {
@FastNative @FastNative
private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath, private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
float hOffset, float vOffset, int flags, long nativePaint); 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);
} }

View File

@@ -464,10 +464,12 @@ cc_defaults {
"canvas/CanvasOpBuffer.cpp", "canvas/CanvasOpBuffer.cpp",
"canvas/CanvasOpRasterizer.cpp", "canvas/CanvasOpRasterizer.cpp",
"effects/StretchEffect.cpp", "effects/StretchEffect.cpp",
"pipeline/skia/HolePunch.cpp",
"pipeline/skia/SkiaDisplayList.cpp", "pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaRecordingCanvas.cpp", "pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/RenderNodeDrawable.cpp", "pipeline/skia/RenderNodeDrawable.cpp",
"pipeline/skia/ReorderBarrierDrawables.cpp", "pipeline/skia/ReorderBarrierDrawables.cpp",
"pipeline/skia/TransformCanvas.cpp",
"renderthread/Frame.cpp", "renderthread/Frame.cpp",
"renderthread/RenderTask.cpp", "renderthread/RenderTask.cpp",
"renderthread/TimeLord.cpp", "renderthread/TimeLord.cpp",

View File

@@ -72,6 +72,10 @@ public:
return mImpl && !(mImpl->isEmpty()); return mImpl && !(mImpl->isEmpty());
} }
[[nodiscard]] bool hasHolePunches() const {
return mImpl && mImpl->hasHolePunches();
}
[[nodiscard]] bool containsProjectionReceiver() const { [[nodiscard]] bool containsProjectionReceiver() const {
return mImpl && mImpl->containsProjectionReceiver(); return mImpl && mImpl->containsProjectionReceiver();
} }

View File

@@ -255,15 +255,19 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu
if (mDisplayList) { if (mDisplayList) {
info.out.hasFunctors |= mDisplayList.hasFunctor(); info.out.hasFunctors |= mDisplayList.hasFunctor();
mHasHolePunches = mDisplayList.hasHolePunches();
bool isDirty = mDisplayList.prepareListAndChildren( bool isDirty = mDisplayList.prepareListAndChildren(
observer, info, childFunctorsNeedLayer, observer, info, childFunctorsNeedLayer,
[](RenderNode* child, TreeObserver& observer, TreeInfo& info, [this](RenderNode* child, TreeObserver& observer, TreeInfo& info,
bool functorsNeedLayer) { bool functorsNeedLayer) {
child->prepareTreeImpl(observer, info, functorsNeedLayer); child->prepareTreeImpl(observer, info, functorsNeedLayer);
mHasHolePunches |= child->hasHolePunches();
}); });
if (isDirty) { if (isDirty) {
damageSelf(info); damageSelf(info);
} }
} else {
mHasHolePunches = false;
} }
pushLayerUpdate(info); pushLayerUpdate(info);

View File

@@ -35,6 +35,7 @@
#include "DisplayList.h" #include "DisplayList.h"
#include "Matrix.h" #include "Matrix.h"
#include "RenderProperties.h" #include "RenderProperties.h"
#include "pipeline/skia/HolePunch.h"
#include "pipeline/skia/SkiaDisplayList.h" #include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaLayer.h" #include "pipeline/skia/SkiaLayer.h"
@@ -284,6 +285,8 @@ private:
UsageHint mUsageHint = UsageHint::Unknown; UsageHint mUsageHint = UsageHint::Unknown;
bool mHasHolePunches;
// METHODS & FIELDS ONLY USED BY THE SKIA RENDERER // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
public: public:
/** /**
@@ -294,6 +297,8 @@ public:
return std::move(mAvailableDisplayList); return std::move(mAvailableDisplayList);
} }
bool hasHolePunches() { return mHasHolePunches; }
/** /**
* Attach unused displayList to this node for potential future reuse. * Attach unused displayList to this node for potential future reuse.
*/ */

View File

@@ -23,6 +23,7 @@
#include "hwui/MinikinUtils.h" #include "hwui/MinikinUtils.h"
#include "hwui/PaintFilter.h" #include "hwui/PaintFilter.h"
#include "pipeline/skia/AnimatedDrawables.h" #include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/HolePunch.h"
#include <SkAndroidFrameworkUtils.h> #include <SkAndroidFrameworkUtils.h>
#include <SkAnimatedImage.h> #include <SkAnimatedImage.h>
@@ -244,6 +245,13 @@ const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const {
return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr; 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) // functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -60,6 +60,8 @@ public:
LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ"); LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
} }
virtual void punchHole(const SkRRect& rect) override;
virtual void setBitmap(const SkBitmap& bitmap) override; virtual void setBitmap(const SkBitmap& bitmap) override;
virtual bool isOpaque() override; virtual bool isOpaque() override;

View File

@@ -155,6 +155,8 @@ public:
LOG_ALWAYS_FATAL("Not supported"); LOG_ALWAYS_FATAL("Not supported");
} }
virtual void punchHole(const SkRRect& rect) = 0;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Canvas state operations // Canvas state operations
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -35,6 +35,7 @@
#include "SkGraphics.h" #include "SkGraphics.h"
#include "SkRegion.h" #include "SkRegion.h"
#include "SkVertices.h" #include "SkVertices.h"
#include "SkRRect.h"
namespace minikin { namespace minikin {
class MeasuredText; class MeasuredText;
@@ -667,6 +668,11 @@ static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) {
Canvas::setCompatibilityVersion(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 }; // namespace CanvasJNI
@@ -740,6 +746,7 @@ static const JNINativeMethod gDrawMethods[] = {
{"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString}, {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
{"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars}, {"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
{"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString}, {"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
{"nPunchHole", "(JFFFFFF)V", (void*) CanvasJNI::punchHole}
}; };
int register_android_graphics_Canvas(JNIEnv* env) { int register_android_graphics_Canvas(JNIEnv* env) {

View File

@@ -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";

View File

@@ -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

View File

@@ -18,6 +18,7 @@
#include <SkPaintFilterCanvas.h> #include <SkPaintFilterCanvas.h>
#include "RenderNode.h" #include "RenderNode.h"
#include "SkiaDisplayList.h" #include "SkiaDisplayList.h"
#include "TransformCanvas.h"
#include "utils/TraceUtils.h" #include "utils/TraceUtils.h"
#include <include/effects/SkImageFilters.h> #include <include/effects/SkImageFilters.h>
@@ -256,6 +257,11 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
canvas->drawAnnotation(bounds, String8::format( canvas->drawAnnotation(bounds, String8::format(
"SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr); "SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
} }
if (renderNode->hasHolePunches()) {
TransformCanvas transformCanvas(canvas);
displayList->draw(&transformCanvas);
}
canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint, canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
SkCanvas::kStrict_SrcRectConstraint); SkCanvas::kStrict_SrcRectConstraint);

View File

@@ -163,7 +163,7 @@ public:
private: private:
std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables; std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables;
bool mHasHolePunches;
public: public:
void appendVD(VectorDrawableRoot* r) { appendVD(r, SkMatrix::I()); } void appendVD(VectorDrawableRoot* r) { appendVD(r, SkMatrix::I()); }
@@ -171,6 +171,14 @@ public:
mVectorDrawables.push_back(Pair<VectorDrawableRoot*, SkMatrix>(r, mat)); mVectorDrawables.push_back(Pair<VectorDrawableRoot*, SkMatrix>(r, mat));
} }
void setHasHolePunches(bool hasHolePunches) {
mHasHolePunches = hasHolePunches;
}
bool hasHolePunches() {
return mHasHolePunches;
}
std::vector<AnimatedImageDrawable*> mAnimatedImages; std::vector<AnimatedImageDrawable*> mAnimatedImages;
DisplayListData mDisplayList; DisplayListData mDisplayList;

View File

@@ -53,6 +53,27 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in
mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height)); mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
SkiaCanvas::reset(&mRecorder); 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() { std::unique_ptr<SkiaDisplayList> SkiaRecordingCanvas::finishRecording() {

View File

@@ -15,6 +15,7 @@
*/ */
#pragma once #pragma once
#include "HolePunch.h"
#include "RecordingCanvas.h" #include "RecordingCanvas.h"
#include "ReorderBarrierDrawables.h" #include "ReorderBarrierDrawables.h"
#include "SkiaCanvas.h" #include "SkiaCanvas.h"
@@ -43,6 +44,8 @@ public:
initDisplayList(renderNode, width, height); initDisplayList(renderNode, width, height);
} }
virtual void punchHole(const SkRRect& rect) override;
virtual void finishRecording(uirenderer::RenderNode* destination) override; virtual void finishRecording(uirenderer::RenderNode* destination) override;
std::unique_ptr<SkiaDisplayList> finishRecording(); std::unique_ptr<SkiaDisplayList> finishRecording();

View File

@@ -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;
}

View File

@@ -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;
};