summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--graphics/java/android/graphics/RenderEffect.java145
-rw-r--r--graphics/java/android/graphics/RenderNode.java20
-rw-r--r--libs/hwui/Android.bp1
-rw-r--r--libs/hwui/RenderProperties.cpp7
-rw-r--r--libs/hwui/RenderProperties.h7
-rw-r--r--libs/hwui/apex/LayoutlibLoader.cpp2
-rw-r--r--libs/hwui/apex/jni_runtime.cpp2
-rw-r--r--libs/hwui/hwui/Paint.h1
-rw-r--r--libs/hwui/jni/RenderEffect.cpp69
-rw-r--r--libs/hwui/jni/android_graphics_RenderNode.cpp7
-rw-r--r--libs/hwui/pipeline/skia/RenderNodeDrawable.cpp4
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml2
-rw-r--r--tests/HwAccelerationTest/res/layout/image_filter_activity.xml28
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java86
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt60
15 files changed, 402 insertions, 39 deletions
diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java
new file mode 100644
index 000000000000..9fc0c8eb9d90
--- /dev/null
+++ b/graphics/java/android/graphics/RenderEffect.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.graphics;
+
+import android.annotation.NonNull;
+import android.graphics.Shader.TileMode;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Intermediate rendering step used to render drawing commands with a corresponding
+ * visual effect
+ *
+ * @hide
+ */
+public final class RenderEffect {
+
+ private static class RenderEffectHolder {
+ public static final NativeAllocationRegistry RENDER_EFFECT_REGISTRY =
+ NativeAllocationRegistry.createMalloced(
+ RenderEffect.class.getClassLoader(), nativeGetFinalizer());
+ }
+
+ /**
+ * Create a {@link RenderEffect} instance that will offset the drawing content
+ * by the provided x and y offset.
+ * @param offsetX offset along the x axis in pixels
+ * @param offsetY offset along the y axis in pixels
+ */
+ @NonNull
+ public static RenderEffect createOffsetEffect(float offsetX, float offsetY) {
+ return new RenderEffect(nativeCreateOffsetEffect(offsetX, offsetY, 0));
+ }
+
+ /**
+ * Create a {@link RenderEffect} instance with the provided x and y offset
+ * @param offsetX offset along the x axis in pixels
+ * @param offsetY offset along the y axis in pixels
+ * @param input target RenderEffect used to render in the offset coordinates.
+ */
+ @NonNull
+ public static RenderEffect createOffsetEffect(
+ float offsetX,
+ float offsetY,
+ @NonNull RenderEffect input
+ ) {
+ return new RenderEffect(nativeCreateOffsetEffect(
+ offsetX,
+ offsetY,
+ input.getNativeInstance()
+ )
+ );
+ }
+
+ /**
+ * Create a {@link RenderEffect} that blurs the contents of the optional input RenderEffect
+ * with the specified radius along the x and y axis. If no input RenderEffect is provided
+ * then all drawing commands issued with a {@link android.graphics.RenderNode} that this
+ * RenderEffect is installed in will be blurred
+ * @param radiusX Radius of blur along the X axis
+ * @param radiusY Radius of blur along the Y axis
+ * @param inputEffect Input RenderEffect that provides the content to be blurred, can be null
+ * to indicate that the drawing commands on the RenderNode are to be
+ * blurred instead of the input RenderEffect
+ * @param edgeTreatment Policy for how to blur content near edges of the blur kernel
+ */
+ @NonNull
+ public static RenderEffect createBlurEffect(
+ float radiusX,
+ float radiusY,
+ @NonNull RenderEffect inputEffect,
+ @NonNull TileMode edgeTreatment
+ ) {
+ long nativeInputEffect = inputEffect != null ? inputEffect.mNativeRenderEffect : 0;
+ return new RenderEffect(
+ nativeCreateBlurEffect(
+ radiusX,
+ radiusY,
+ nativeInputEffect,
+ edgeTreatment.nativeInt
+ )
+ );
+ }
+
+ /**
+ * Create a {@link RenderEffect} that blurs the contents of the
+ * {@link android.graphics.RenderNode} that this RenderEffect is installed on with the
+ * specified radius along hte x and y axis.
+ * @param radiusX Radius of blur along the X axis
+ * @param radiusY Radius of blur along the Y axis
+ * @param edgeTreatment Policy for how to blur content near edges of the blur kernel
+ */
+ @NonNull
+ public static RenderEffect createBlurEffect(
+ float radiusX,
+ float radiusY,
+ @NonNull TileMode edgeTreatment
+ ) {
+ return new RenderEffect(
+ nativeCreateBlurEffect(
+ radiusX,
+ radiusY,
+ 0,
+ edgeTreatment.nativeInt
+ )
+ );
+ }
+
+ private final long mNativeRenderEffect;
+
+ /* only constructed from static factory methods */
+ private RenderEffect(long nativeRenderEffect) {
+ mNativeRenderEffect = nativeRenderEffect;
+ RenderEffectHolder.RENDER_EFFECT_REGISTRY.registerNativeAllocation(
+ this, mNativeRenderEffect);
+ }
+
+ /**
+ * Obtain the pointer to the underlying RenderEffect to be configured
+ * on a RenderNode object via {@link RenderNode#setRenderEffect(RenderEffect)}
+ */
+ /* package */ long getNativeInstance() {
+ return mNativeRenderEffect;
+ }
+
+ private static native long nativeCreateOffsetEffect(
+ float offsetX, float offsetY, long nativeInput);
+ private static native long nativeCreateBlurEffect(
+ float radiusX, float radiusY, long nativeInput, int edgeTreatment);
+ private static native long nativeGetFinalizer();
+}
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 8aacbc7bc109..d812c1a5595d 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -850,6 +850,23 @@ public final class RenderNode {
}
/**
+ * Configure the {@link android.graphics.RenderEffect} to apply to this RenderNode. This
+ * will apply a visual effect to the end result of the contents of this RenderNode before
+ * it is drawn into the destination. For example if
+ * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)}
+ * is provided, the contents will be drawn in a separate layer, then this layer will
+ * be blurred when this RenderNode is drawn into the destination.
+ * @param renderEffect to be applied to the RenderNode. Passing null clears all previously
+ * configured RenderEffects
+ *
+ * @hide
+ */
+ public void setRenderEffect(@Nullable RenderEffect renderEffect) {
+ nSetRenderEffect(mNativeRenderNode,
+ renderEffect != null ? renderEffect.getNativeInstance() : 0);
+ }
+
+ /**
* Returns the translucency level of this display list.
*
* @return A value between 0.0f and 1.0f
@@ -1655,6 +1672,9 @@ public final class RenderNode {
private static native boolean nSetAlpha(long renderNode, float alpha);
@CriticalNative
+ private static native void nSetRenderEffect(long renderNode, long renderEffect);
+
+ @CriticalNative
private static native boolean nSetHasOverlappingRendering(long renderNode,
boolean hasOverlappingRendering);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 90d2537d97a8..9f4c9a1eddfa 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -327,6 +327,7 @@ cc_defaults {
"jni/PathMeasure.cpp",
"jni/Picture.cpp",
"jni/Shader.cpp",
+ "jni/RenderEffect.cpp",
"jni/Typeface.cpp",
"jni/Utils.cpp",
"jni/YuvToJpegEncoder.cpp",
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index ff9cf45cdc73..8fba9cf21df1 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -49,6 +49,12 @@ bool LayerProperties::setColorFilter(SkColorFilter* filter) {
return true;
}
+bool LayerProperties::setImageFilter(SkImageFilter* imageFilter) {
+ if(mImageFilter.get() == imageFilter) return false;
+ mImageFilter = sk_ref_sp(imageFilter);
+ return true;
+}
+
bool LayerProperties::setFromPaint(const SkPaint* paint) {
bool changed = false;
changed |= setAlpha(static_cast<uint8_t>(PaintUtils::getAlphaDirect(paint)));
@@ -63,6 +69,7 @@ LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
setAlpha(other.alpha());
setXferMode(other.xferMode());
setColorFilter(other.getColorFilter());
+ setImageFilter(other.getImageFilter());
return *this;
}
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index ef4cd1f1eb62..aeb60e6ce355 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -27,6 +27,7 @@
#include "utils/PaintUtils.h"
#include <SkBlendMode.h>
+#include <SkImageFilter.h>
#include <SkCamera.h>
#include <SkColor.h>
#include <SkMatrix.h>
@@ -93,6 +94,10 @@ public:
SkColorFilter* getColorFilter() const { return mColorFilter.get(); }
+ bool setImageFilter(SkImageFilter* imageFilter);
+
+ SkImageFilter* getImageFilter() const { return mImageFilter.get(); }
+
// Sets alpha, xfermode, and colorfilter from an SkPaint
// paint may be NULL, in which case defaults will be set
bool setFromPaint(const SkPaint* paint);
@@ -118,6 +123,7 @@ private:
uint8_t mAlpha;
SkBlendMode mMode;
sk_sp<SkColorFilter> mColorFilter;
+ sk_sp<SkImageFilter> mImageFilter;
};
/*
@@ -541,6 +547,7 @@ public:
bool promotedToLayer() const {
return mLayerProperties.mType == LayerType::None && fitsOnLayer() &&
(mComputedFields.mNeedLayerForFunctors ||
+ mLayerProperties.mImageFilter != nullptr ||
(!MathUtils::isZero(mPrimitiveFields.mAlpha) && mPrimitiveFields.mAlpha < 1 &&
mPrimitiveFields.mHasOverlappingRendering));
}
diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp
index 4bbf1214bdcf..dca10e29cbb8 100644
--- a/libs/hwui/apex/LayoutlibLoader.cpp
+++ b/libs/hwui/apex/LayoutlibLoader.cpp
@@ -47,6 +47,7 @@ extern int register_android_graphics_MaskFilter(JNIEnv* env);
extern int register_android_graphics_NinePatch(JNIEnv*);
extern int register_android_graphics_PathEffect(JNIEnv* env);
extern int register_android_graphics_Shader(JNIEnv* env);
+extern int register_android_graphics_RenderEffect(JNIEnv* env);
extern int register_android_graphics_Typeface(JNIEnv* env);
namespace android {
@@ -108,6 +109,7 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.graphics.RecordingCanvas", REG_JNI(register_android_view_DisplayListCanvas)},
// {"android.graphics.Region", REG_JNI(register_android_graphics_Region)},
{"android.graphics.Shader", REG_JNI(register_android_graphics_Shader)},
+ {"android.graphics.RenderEffect", REG_JNI(register_android_graphics_RenderEffect)},
{"android.graphics.Typeface", REG_JNI(register_android_graphics_Typeface)},
{"android.graphics.animation.NativeInterpolatorFactory",
REG_JNI(register_android_graphics_animation_NativeInterpolatorFactory)},
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 12e2e8135278..deccc802dbb2 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -43,6 +43,7 @@ extern int register_android_graphics_Movie(JNIEnv* env);
extern int register_android_graphics_NinePatch(JNIEnv*);
extern int register_android_graphics_PathEffect(JNIEnv* env);
extern int register_android_graphics_Shader(JNIEnv* env);
+extern int register_android_graphics_RenderEffect(JNIEnv* env);
extern int register_android_graphics_Typeface(JNIEnv* env);
extern int register_android_graphics_YuvImage(JNIEnv* env);
@@ -123,6 +124,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Picture),
REG_JNI(register_android_graphics_Region),
REG_JNI(register_android_graphics_Shader),
+ REG_JNI(register_android_graphics_RenderEffect),
REG_JNI(register_android_graphics_TextureLayer),
REG_JNI(register_android_graphics_Typeface),
REG_JNI(register_android_graphics_YuvImage),
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 0bb689c19079..4e2016a41f5e 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -157,7 +157,6 @@ public:
private:
using SkPaint::setShader;
- using SkPaint::setImageFilter;
SkFont mFont;
sk_sp<SkDrawLooper> mLooper;
diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp
new file mode 100644
index 000000000000..0ebd0ca720d8
--- /dev/null
+++ b/libs/hwui/jni/RenderEffect.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 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 "Bitmap.h"
+#include "GraphicsJNI.h"
+#include "SkImageFilter.h"
+#include "SkImageFilters.h"
+#include "graphics_jni_helpers.h"
+#include "utils/Blur.h"
+#include <utils/Log.h>
+
+using namespace android::uirenderer;
+
+static jlong createOffsetEffect(
+ JNIEnv* env,
+ jobject,
+ jfloat offsetX,
+ jfloat offsetY,
+ jlong inputFilterHandle
+) {
+ auto* inputFilter = reinterpret_cast<const SkImageFilter*>(inputFilterHandle);
+ sk_sp<SkImageFilter> offset = SkImageFilters::Offset(offsetX, offsetY, sk_ref_sp(inputFilter));
+ return reinterpret_cast<jlong>(offset.release());
+}
+
+static jlong createBlurEffect(JNIEnv* env , jobject, jfloat radiusX,
+ jfloat radiusY, jlong inputFilterHandle, jint edgeTreatment) {
+ auto* inputImageFilter = reinterpret_cast<SkImageFilter*>(inputFilterHandle);
+ sk_sp<SkImageFilter> blurFilter =
+ SkImageFilters::Blur(
+ Blur::convertRadiusToSigma(radiusX),
+ Blur::convertRadiusToSigma(radiusY),
+ static_cast<SkTileMode>(edgeTreatment),
+ sk_ref_sp(inputImageFilter),
+ nullptr);
+ return reinterpret_cast<jlong>(blurFilter.release());
+}
+
+static void RenderEffect_safeUnref(SkImageFilter* filter) {
+ SkSafeUnref(filter);
+}
+
+static jlong getRenderEffectFinalizer(JNIEnv*, jobject) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&RenderEffect_safeUnref));
+}
+
+static const JNINativeMethod gRenderEffectMethods[] = {
+ {"nativeGetFinalizer", "()J", (void*)getRenderEffectFinalizer},
+ {"nativeCreateOffsetEffect", "(FFJ)J", (void*)createOffsetEffect},
+ {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect}
+};
+
+int register_android_graphics_RenderEffect(JNIEnv* env) {
+ android::RegisterMethodsOrDie(env, "android/graphics/RenderEffect",
+ gRenderEffectMethods, NELEM(gRenderEffectMethods));
+ return 0;
+} \ No newline at end of file
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 85c802b40459..4b4aa92b97b7 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -215,6 +215,12 @@ static jboolean android_view_RenderNode_setAlpha(CRITICAL_JNI_PARAMS_COMMA jlong
return SET_AND_DIRTY(setAlpha, alpha, RenderNode::ALPHA);
}
+static jboolean android_view_RenderNode_setRenderEffect(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
+ jlong renderEffectPtr) {
+ SkImageFilter* imageFilter = reinterpret_cast<SkImageFilter*>(renderEffectPtr);
+ return SET_AND_DIRTY(mutateLayerProperties().setImageFilter, imageFilter, RenderNode::GENERIC);
+}
+
static jboolean android_view_RenderNode_setHasOverlappingRendering(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
bool hasOverlappingRendering) {
return SET_AND_DIRTY(setHasOverlappingRendering, hasOverlappingRendering,
@@ -690,6 +696,7 @@ static const JNINativeMethod gMethods[] = {
{ "nSetRevealClip", "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
{ "nSetAlpha", "(JF)Z", (void*) android_view_RenderNode_setAlpha },
+ { "nSetRenderEffect", "(JJ)V", (void*) android_view_RenderNode_setRenderEffect },
{ "nSetHasOverlappingRendering", "(JZ)Z",
(void*) android_view_RenderNode_setHasOverlappingRendering },
{ "nSetUsageHint", "(JI)V", (void*) android_view_RenderNode_setUsageHint },
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 00ceb2d84f9e..1473b3e5abb7 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -172,10 +172,12 @@ static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultip
SkPaint* paint) {
paint->setFilterQuality(kLow_SkFilterQuality);
if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
- properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr) {
+ properties.xferMode() != SkBlendMode::kSrcOver || properties.getColorFilter() != nullptr ||
+ properties.getImageFilter() != nullptr) {
paint->setAlpha(properties.alpha() * alphaMultiplier);
paint->setBlendMode(properties.xferMode());
paint->setColorFilter(sk_ref_sp(properties.getColorFilter()));
+ paint->setImageFilter(sk_ref_sp(properties.getImageFilter()));
return true;
}
return false;
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 05a59ef7fc72..9a2def935f5d 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -745,7 +745,7 @@
</activity>
<activity android:name="BlurActivity"
- android:label="Shaders/Blur"
+ android:label="RenderEffect/Blur"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/tests/HwAccelerationTest/res/layout/image_filter_activity.xml b/tests/HwAccelerationTest/res/layout/image_filter_activity.xml
new file mode 100644
index 000000000000..a0ee67ae0bef
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/image_filter_activity.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center">
+
+ <ImageView
+ android:id="@+id/image_filter_test_view"
+ android:background="#FF0000"
+ android:layout_width="200dp"
+ android:layout_height="200dp" />
+</FrameLayout> \ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
index 033fb0ec35d2..e4ca7881f796 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BlurActivity.java
@@ -18,11 +18,12 @@ package com.android.test.hwui;
import android.app.Activity;
import android.content.Context;
-import android.graphics.BlurShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
+import android.graphics.RenderEffect;
+import android.graphics.RenderNode;
import android.graphics.Shader;
import android.os.Bundle;
import android.view.Gravity;
@@ -51,16 +52,27 @@ public class BlurActivity extends Activity {
}
public static class BlurGradientView extends View {
- private BlurShader mBlurShader = null;
- private Paint mPaint;
+ private final float mBlurRadius = 25f;
+ private final Paint mPaint;
+ private final RenderNode mRenderNode;
public BlurGradientView(Context c) {
super(c);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mRenderNode = new RenderNode("BlurGradientView");
+ mRenderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(
+ mBlurRadius,
+ mBlurRadius,
+ null,
+ Shader.TileMode.DECAL
+ )
+ );
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- if (changed || mBlurShader == null) {
+ if (changed) {
LinearGradient gradient = new LinearGradient(
0f,
0f,
@@ -70,41 +82,81 @@ public class BlurActivity extends Activity {
Color.YELLOW,
Shader.TileMode.CLAMP
);
- mBlurShader = new BlurShader(30f, 40f, gradient);
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPaint.setShader(mBlurShader);
+
+ mPaint.setShader(gradient);
+
+ final int width = right - left;
+ final int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+
+ Canvas canvas = mRenderNode.beginRecording();
+ canvas.drawRect(
+ mBlurRadius * 2,
+ mBlurRadius * 2,
+ width - mBlurRadius * 2,
+ height - mBlurRadius * 2,
+ mPaint
+ );
+ mRenderNode.endRecording();
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
- canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+ canvas.drawRenderNode(mRenderNode);
}
}
public static class BlurView extends View {
- private final BlurShader mBlurShader;
private final Paint mPaint;
+ private final RenderNode mRenderNode;
+ private final float mBlurRadius = 20f;
public BlurView(Context c) {
super(c);
- mBlurShader = new BlurShader(20f, 20f, null);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPaint.setShader(mBlurShader);
+ mRenderNode = new RenderNode("blurNode");
+ mRenderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(
+ mBlurRadius,
+ mBlurRadius,
+ null,
+ Shader.TileMode.DECAL
+ )
+ );
}
@Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (changed) {
+ int width = right - left;
+ int height = bottom - top;
+ mRenderNode.setPosition(0, 0, width, height);
+ Canvas canvas = mRenderNode.beginRecording(width, height);
+ mPaint.setColor(Color.BLUE);
+
+ canvas.drawRect(
+ mBlurRadius * 2,
+ mBlurRadius * 2,
+ width - mBlurRadius * 2,
+ height - mBlurRadius * 2,
+ mPaint
+ );
- mPaint.setColor(Color.BLUE);
- canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
+ mPaint.setColor(Color.RED);
+ canvas.drawCircle((right - left) / 2f, (bottom - top) / 2f, 50f, mPaint);
+
+ mRenderNode.endRecording();
+ }
+ }
- mPaint.setColor(Color.RED);
- canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, 50f, mPaint);
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRenderNode(mRenderNode);
}
}
}
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
index 711758476a62..2f2578b87f35 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
@@ -20,13 +20,13 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.BitmapShader
import android.graphics.BlendMode
-import android.graphics.BlurShader
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Outline
import android.graphics.Paint
-import android.graphics.RadialGradient
import android.graphics.Rect
+import android.graphics.RenderEffect
+import android.graphics.RenderNode
import android.graphics.Shader
import android.hardware.Sensor
import android.hardware.SensorEvent
@@ -36,7 +36,6 @@ import android.util.AttributeSet
import android.view.View
import android.view.ViewOutlineProvider
import android.widget.FrameLayout
-import com.android.internal.graphics.ColorUtils
import com.android.test.silkfx.R
import kotlin.math.sin
import kotlin.math.sqrt
@@ -152,10 +151,19 @@ class GlassView(context: Context, attributeSet: AttributeSet) : FrameLayout(cont
var blurRadius = 150f
set(value) {
field = value
- blurPaint.shader = BlurShader(value, value, null)
+ renderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(value, value, Shader.TileMode.CLAMP))
invalidate()
}
+ private var renderNodeIsDirty = true
+ private val renderNode = RenderNode("GlassRenderNode")
+
+ override fun invalidate() {
+ renderNodeIsDirty = true
+ super.invalidate()
+ }
+
init {
setWillNotDraw(false)
materialPaint.blendMode = BlendMode.SOFT_LIGHT
@@ -164,7 +172,6 @@ class GlassView(context: Context, attributeSet: AttributeSet) : FrameLayout(cont
scrimPaint.alpha = (scrimOpacity * 255).toInt()
noisePaint.alpha = (noiseOpacity * 255).toInt()
materialPaint.alpha = (materialOpacity * 255).toInt()
- blurPaint.shader = BlurShader(blurRadius, blurRadius, null)
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View?, outline: Outline?) {
outline?.setRoundRect(Rect(0, 0, width, height), 100f)
@@ -184,20 +191,8 @@ class GlassView(context: Context, attributeSet: AttributeSet) : FrameLayout(cont
}
override fun onDraw(canvas: Canvas?) {
- src.set(-width / 2, -height / 2, width / 2, height / 2)
- src.scale(1.0f + zoom)
- val centerX = left + width / 2
- val centerY = top + height / 2
- val textureXOffset = (textureTranslationMultiplier * gyroYRotation).toInt()
- val textureYOffset = (textureTranslationMultiplier * gyroXRotation).toInt()
- src.set(src.left + centerX + textureXOffset, src.top + centerY + textureYOffset,
- src.right + centerX + textureXOffset, src.bottom + centerY + textureYOffset)
-
- dst.set(0, 0, width, height)
- canvas?.drawBitmap(backgroundBitmap, src, dst, blurPaint)
- canvas?.drawRect(dst, materialPaint)
- canvas?.drawRect(dst, noisePaint)
- canvas?.drawRect(dst, scrimPaint)
+ updateGlassRenderNode()
+ canvas?.drawRenderNode(renderNode)
}
fun resetGyroOffsets() {
@@ -205,4 +200,31 @@ class GlassView(context: Context, attributeSet: AttributeSet) : FrameLayout(cont
gyroYRotation = 0f
invalidate()
}
+
+ private fun updateGlassRenderNode() {
+ if (renderNodeIsDirty) {
+ renderNode.setPosition(0, 0, getWidth(), getHeight())
+
+ val canvas = renderNode.beginRecording()
+
+ src.set(-width / 2, -height / 2, width / 2, height / 2)
+ src.scale(1.0f + zoom)
+ val centerX = left + width / 2
+ val centerY = top + height / 2
+ val textureXOffset = (textureTranslationMultiplier * gyroYRotation).toInt()
+ val textureYOffset = (textureTranslationMultiplier * gyroXRotation).toInt()
+ src.set(src.left + centerX + textureXOffset, src.top + centerY + textureYOffset,
+ src.right + centerX + textureXOffset, src.bottom + centerY + textureYOffset)
+
+ dst.set(0, 0, width, height)
+ canvas.drawBitmap(backgroundBitmap, src, dst, blurPaint)
+ canvas.drawRect(dst, materialPaint)
+ canvas.drawRect(dst, noisePaint)
+ canvas.drawRect(dst, scrimPaint)
+
+ renderNode.endRecording()
+
+ renderNodeIsDirty = false
+ }
+ }
} \ No newline at end of file