From 373540e8e169dc385fc4cd2fde15e61c72c3f2d9 Mon Sep 17 00:00:00 2001 From: Yein Jo Date: Wed, 26 Jul 2023 23:29:18 +0000 Subject: [PATCH] Add SparkleShader in the ShaderLib As part of Shared shader library, SparkleShader is added to support modularity. Test: SparkleShaderTest, SolidColorShaderTest Test: Manual in debug app (locally. will upload apk in experimental package.) Change-Id: I13677567814e8e3aab46704106dcea9a739a0631 --- .../shaders/SolidColorShader.kt | 36 ++++++ .../surfaceeffects/shaders/SparkleShader.kt | 115 ++++++++++++++++++ .../shaders/SolidColorShaderTest.kt | 33 +++++ .../shaders/SparkleShaderTest.kt | 44 +++++++ 4 files changed, 228 insertions(+) create mode 100644 packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt create mode 100644 packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt new file mode 100644 index 0000000000000..c94fad7246fae --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 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 com.android.systemui.surfaceeffects.shaders + +import android.graphics.RuntimeShader + +/** Simply renders a solid color. */ +class SolidColorShader(color: Int) : RuntimeShader(SHADER) { + // language=AGSL + private companion object { + private const val SHADER = + """ + layout(color) uniform vec4 in_color; + vec4 main(vec2 p) { + return in_color; + } + """ + } + + init { + setColorUniform("in_color", color) + } +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt new file mode 100644 index 0000000000000..df07856e325e3 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 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 com.android.systemui.surfaceeffects.shaders + +import android.graphics.Color +import android.graphics.RuntimeShader +import android.graphics.Shader +import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary + +/** + * Renders sparkles based on the luma matte. + * + * For example, you can pass in simplex noise as the luma matte and have a cloud looking sparkles. + * + * You may want to utilize this shader by: (Preferred) 1. Create a RuntimeShaderEffect and set the + * [RenderEffect] to the target [View]. + * 2. Create a custom [View], set the shader to the [Paint] and use [Canvas.drawPaint] in [onDraw]. + */ +class SparkleShader : RuntimeShader(SPARKLE_SHADER) { + // language=AGSL + companion object { + private const val UNIFORMS = + """ + // Used it for RenderEffect. For example: + // myView.setRenderEffect( + // RenderEffect.createRuntimeShaderEffect(SparkleShader(), "in_src") + // ) + uniform shader in_src; + uniform half in_time; + uniform half in_pixelate; + uniform shader in_lumaMatte; + layout(color) uniform vec4 in_color; + """ + private const val MAIN_SHADER = + """vec4 main(vec2 p) { + half3 src = in_src.eval(p).rgb; + half luma = getLuminosity(in_lumaMatte.eval(p).rgb); + half sparkle = sparkles(p - mod(p, in_pixelate), in_time); + half3 mask = maskLuminosity(in_color.rgb * sparkle, luma); + + return vec4(src * mask * in_color.a, in_color.a); + } + """ + private const val SPARKLE_SHADER = UNIFORMS + ShaderUtilLibrary.SHADER_LIB + MAIN_SHADER + + /** Highly recommended to use this value unless specified by design spec. */ + const val DEFAULT_SPARKLE_PIXELATE_AMOUNT = 0.8f + } + + init { + // Initializes the src and luma matte to be white. + setInputShader("in_src", SolidColorShader(Color.WHITE)) + setLumaMatteColor(Color.WHITE) + } + + /** + * Sets the time of the sparkle animation. + * + * This is used for animating sparkles. Note that this only makes the sparkles sparkle in place. + * In order to move the sparkles in x, y directions, move the luma matte input instead. + */ + fun setTime(time: Float) { + setFloatUniform("in_time", time) + } + + /** + * Sets pixelated amount of the sparkle. + * + * This value *must* be based on [resources.displayMetrics.density]. Otherwise, this will result + * in having different sparkle sizes on different screens. + * + * Expected to be used as follows: + *
+     *     {@code
+     *     val pixelDensity = context.resources.displayMetrics.density
+     *     // Sparkles will be 0.8 of the pixel size.
+     *     val sparkleShader = SparkleShader().apply { setPixelateAmount(pixelDensity * 0.8f) }
+     *     }
+     * 
+ */ + fun setPixelateAmount(pixelateAmount: Float) { + setFloatUniform("in_pixelate", pixelateAmount) + } + + /** + * Sets the luma matte for the sparkles. The luminosity determines the sparkle's visibility. + * Useful for setting a complex mask (e.g. simplex noise, texture, etc.) + */ + fun setLumaMatte(lumaMatte: Shader) { + setInputShader("in_lumaMatte", lumaMatte) + } + + /** Sets the luma matte for the sparkles. Useful for setting a solid color. */ + fun setLumaMatteColor(color: Int) { + setInputShader("in_lumaMatte", SolidColorShader(color)) + } + + /** Sets the color of the sparkles. Expect to have the alpha value encoded. */ + fun setColor(color: Int) { + setColorUniform("in_color", color) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt new file mode 100644 index 0000000000000..f1fadf6f1a4af --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 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 com.android.systemui.surfaceeffects.shaders + +import android.graphics.Color +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class SolidColorShaderTest : SysuiTestCase() { + + @Test + fun compilesShader() { + SolidColorShader(Color.RED) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt new file mode 100644 index 0000000000000..64ea6a68a5185 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 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 com.android.systemui.surfaceeffects.shaders + +import android.graphics.Color +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class SparkleShaderTest : SysuiTestCase() { + + private lateinit var sparkleShader: SparkleShader + + @Test + fun compilesSparkleShader() { + sparkleShader = + SparkleShader().apply { + setPixelateAmount( + context.resources.displayMetrics.density * + SparkleShader.DEFAULT_SPARKLE_PIXELATE_AMOUNT + ) + setColor(Color.RED) + setTime(0.01f) + setLumaMatteColor(Color.WHITE) + } + } +}