Use Shader instead of RenderEffect for highlight

This commit is contained in:
Kyant0 committed 2025-10-16 00:14:46 +08:00
1 parent e2571c1d67
commit 781ff16df8
3 files changed
+34 -61

No files matched your search

@@ -166,8 +166,6 @@ half4 main(float2 coord) {
@Language("AGSL")
internal const val DefaultHighlightShaderString = """
uniform shader content;
uniform float2 size;
uniform float4 cornerRadii;
uniform float angle;
@@ -184,13 +182,11 @@ half4 main(float2 coord) {
float2 grad = gradSdRoundedRectangle(centeredCoord, halfSize, gradRadius);
float2 normal = float2(-cos(angle), -sin(angle));
float intensity = pow(abs(dot(normal, grad)), falloff);
return content.eval(coord) * intensity;
return half4(intensity);
}"""
@Language("AGSL")
internal const val AmbientHighlightShaderString = """
uniform shader content;
uniform float2 size;
uniform float4 cornerRadii;
uniform float angle;
@@ -207,16 +203,13 @@ half4 main(float2 coord) {
float2 grad = gradSdRoundedRectangle(centeredCoord, halfSize, gradRadius);
float2 normal = float2(-cos(angle), -sin(angle));
float d = dot(normal, grad);
float alpha = content.eval(coord).a;
float intensity = pow(abs(d), falloff);
if (d > 0.0) {
return half4(0.0, 0.0, 0.0, 1.0) * intensity * alpha;
return half4(0.0, 0.0, 0.0, 1.0) * intensity;
} else {
return half4(1.0) * intensity;
}
if (d < 0.0) {
return half4(1.0) * intensity * alpha;
}
return half4(0.0);
}"""
@Language("AGSL")
@@ -11,7 +11,6 @@ import androidx.compose.ui.graphics.drawOutline
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.layer.CompositingStrategy
import androidx.compose.ui.graphics.layer.GraphicsLayer
import androidx.compose.ui.graphics.layer.drawLayer
import androidx.compose.ui.node.DrawModifierNode
@@ -73,7 +72,6 @@ internal class HighlightNode(
override val shouldAutoInvalidate: Boolean = false
private var highlightLayer: GraphicsLayer? = null
private var maskLayer: GraphicsLayer? = null
private val paint =
Paint().apply {
@@ -94,8 +92,7 @@ internal class HighlightNode(
drawContent()
val highlightLayer = highlightLayer
val maskLayer = maskLayer
if (highlightLayer != null && maskLayer != null) {
if (highlightLayer != null) {
val size = size
val density: Density = this
val layoutDirection = layoutDirection
@@ -116,18 +113,8 @@ internal class HighlightNode(
configurePaint(highlight)
val style = highlight.style
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (prevStyle != style) {
highlightLayer.renderEffect = with(style) {
createRenderEffect(
shape = shapeProvider.shape,
runtimeShaderCache = runtimeShaderCache
)
}
prevStyle = style
}
}
highlightLayer.alpha = highlight.alpha
highlightLayer.blendMode = highlight.style.blendMode
highlightLayer.record(safeSize) {
translate(1f, 1f) {
val canvas = drawContext.canvas
@@ -138,14 +125,8 @@ internal class HighlightNode(
}
}
maskLayer.alpha = highlight.alpha
maskLayer.blendMode = style.blendMode
maskLayer.record(safeSize) {
drawLayer(highlightLayer)
}
translate(-1f, -1f) {
drawLayer(maskLayer)
drawLayer(highlightLayer)
}
}
}
@@ -153,10 +134,6 @@ internal class HighlightNode(
override fun onAttach() {
val graphicsContext = requireGraphicsContext()
highlightLayer = graphicsContext.createGraphicsLayer()
maskLayer =
graphicsContext.createGraphicsLayer().apply {
compositingStrategy = CompositingStrategy.Offscreen
}
}
override fun onDetach() {
@@ -165,10 +142,6 @@ internal class HighlightNode(
graphicsContext.releaseGraphicsLayer(layer)
highlightLayer = null
}
maskLayer?.let { layer ->
graphicsContext.releaseGraphicsLayer(layer)
maskLayer = null
}
clipPath = null
runtimeShaderCache.clear()
prevStyle = null
@@ -185,5 +158,13 @@ internal class HighlightNode(
} else {
null
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
paint.shader = with(highlight.style) {
createShader(
shape = shapeProvider.shape,
runtimeShaderCache = runtimeShaderCache
)
}
}
}
}
@@ -8,9 +8,8 @@ import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RenderEffect
import androidx.compose.ui.graphics.Shader
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.asComposeRenderEffect
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.util.fastCoerceAtMost
@@ -27,10 +26,10 @@ interface HighlightStyle {
val blendMode: BlendMode
@RequiresApi(Build.VERSION_CODES.S)
fun DrawScope.createRenderEffect(
fun DrawScope.createShader(
shape: Shape,
runtimeShaderCache: RuntimeShaderCache
): RenderEffect?
): Shader?
@Immutable
data class Plain(
@@ -39,10 +38,10 @@ interface HighlightStyle {
) : HighlightStyle {
@RequiresApi(Build.VERSION_CODES.S)
override fun DrawScope.createRenderEffect(
override fun DrawScope.createShader(
shape: Shape,
runtimeShaderCache: RuntimeShaderCache
): RenderEffect? = null
): Shader? = null
}
@Immutable
@@ -57,20 +56,20 @@ interface HighlightStyle {
override val blendMode: BlendMode = BlendMode.Plus
@RequiresApi(Build.VERSION_CODES.S)
override fun DrawScope.createRenderEffect(
override fun DrawScope.createShader(
shape: Shape,
runtimeShaderCache: RuntimeShaderCache
): RenderEffect? {
): Shader? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val shader = runtimeShaderCache.obtainRuntimeShader("Default", DefaultHighlightShaderString)
shader.apply {
runtimeShaderCache.obtainRuntimeShader(
"Default",
DefaultHighlightShaderString
).apply {
setFloatUniform("size", size.width, size.height)
setFloatUniform("cornerRadii", getCornerRadii(shape))
setFloatUniform("angle", angle * (PI / 180f).toFloat())
setFloatUniform("falloff", falloff)
}
android.graphics.RenderEffect.createRuntimeShaderEffect(shader, "content")
.asComposeRenderEffect()
} else {
null
}
@@ -87,20 +86,20 @@ interface HighlightStyle {
override val blendMode: BlendMode = DrawScope.DefaultBlendMode
@RequiresApi(Build.VERSION_CODES.S)
override fun DrawScope.createRenderEffect(
override fun DrawScope.createShader(
shape: Shape,
runtimeShaderCache: RuntimeShaderCache
): RenderEffect? {
): Shader? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val shader = runtimeShaderCache.obtainRuntimeShader("Ambient", AmbientHighlightShaderString)
shader.apply {
runtimeShaderCache.obtainRuntimeShader(
"Ambient",
AmbientHighlightShaderString
).apply {
setFloatUniform("size", size.width, size.height)
setFloatUniform("cornerRadii", getCornerRadii(shape))
setFloatUniform("angle", 45f * (PI / 180f).toFloat())
setFloatUniform("falloff", 1f)
}
android.graphics.RenderEffect.createRuntimeShaderEffect(shader, "content")
.asComposeRenderEffect()
} else {
null
}
@@ -121,9 +120,9 @@ interface HighlightStyle {
}
private fun DrawScope.getCornerRadii(shape: Shape): FloatArray {
val shape = shape as? CornerBasedShape ?: return FloatArray(4) { size.minDimension / 2f }
val size = size
val maxRadius = size.minDimension / 2f
val shape = shape as? CornerBasedShape ?: return FloatArray(4) { maxRadius }
val isLtr = layoutDirection == LayoutDirection.Ltr
val topLeft =
if (isLtr) shape.topStart.toPx(size, this)