Use Shader instead of RenderEffect for highlight
This commit is contained in:
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)
|
||||
|
||||
Reference in new issue
Block a user