From 779b9342575bd3a7430d4cd9ff1fd7482b98b464 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Sun, 1 Dec 2024 21:14:21 +0000 Subject: [PATCH] Add automatic HazeInputScale --- docs/usage.md | 14 +++++--- haze/api/api.txt | 4 +++ .../kotlin/dev/chrisbanes/haze/HazeChild.kt | 8 ++++- .../dev/chrisbanes/haze/HazeChildNode.kt | 34 +++++++++++-------- .../dev/chrisbanes/haze/sample/Samples.kt | 7 ++-- 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 1db198f..7c44c73 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -133,13 +133,19 @@ You can provide an input scale value which determines how much the content is sc LargeTopAppBar( // ... modifier = Modifier.hazeChild(hazeState) { - inputScale = HazeInputScale.Fixed(0.5f) + inputScale = HazeInputScale.Auto } ) ``` -Using a value less than 1.0 **may** improve performance, at the sacrifice of quality and crispness. As always, run your own benchmarks as to whether this compromise is worth it. +`HazeInputScale` has a number of different options: -If you're looking for a good value to experiment with, `0.8` results in a reduction in total resolution of ~35%, while being visually imperceptible to most people (probably). +- `HazeInputScale.None`: Turns off input scaling (default) +- `HazeInputScale.Auto`: Turns on input scaling, with automatic values derived underneath. +- `HazeInputScale.Fixed(...)`: Turns on input scaling, using the value you pass in. -The minimum value I would realistically use is somewhere in the region of `0.5`, which results in the total pixel count of only 25% of the original content. This is likely to be visually different to no scaling, but depending on the styling parameters, it will be visually pleasing to the user. +When using a `Fixed` value, less than 1.0 **may** improve performance, at the sacrifice of quality and crispness. As always, run your own benchmarks as to whether this compromise is worth it. + +If you're looking for a good value to experiment with, `0.66` results in a reduction in total resolution of ~55%, while being visually imperceptible to most people (probably). + +The minimum value I would realistically use is somewhere in the region of `0.33`, which results in the total pixel count of only 11% of the original content. This is likely to be visually different to no scaling, but depending on the styling parameters, it will be visually pleasing to the user. diff --git a/haze/api/api.txt b/haze/api/api.txt index 062a4cd..e36e30f 100644 --- a/haze/api/api.txt +++ b/haze/api/api.txt @@ -109,6 +109,10 @@ package dev.chrisbanes.haze { field public static final dev.chrisbanes.haze.HazeInputScale.Companion Companion; } + public static final class HazeInputScale.Auto implements dev.chrisbanes.haze.HazeInputScale { + field public static final dev.chrisbanes.haze.HazeInputScale.Auto INSTANCE; + } + public static final class HazeInputScale.Companion { method public dev.chrisbanes.haze.HazeInputScale getDefault(); property @dev.chrisbanes.haze.ExperimentalHazeApi public final dev.chrisbanes.haze.HazeInputScale Default; diff --git a/haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChild.kt b/haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChild.kt index 5600a8d..d917ec6 100644 --- a/haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChild.kt +++ b/haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChild.kt @@ -158,6 +158,12 @@ sealed interface HazeInputScale { */ data object None : HazeInputScale + /** + * Automatic input scaling. Haze will attempt to use an appropriate input scale depending on + * the other settings which have been set. The values used underneath may change in the future. + */ + data object Auto : HazeInputScale + /** * An input scale which uses a fixed scale factor. * @@ -175,7 +181,7 @@ sealed interface HazeInputScale { companion object { /** * The default [HazeInputScale] value. Currently this resolves to [HazeInputScale.None] but - * this may change in the future. + * this may change in the future, probably to [HazeInputScale.Auto]. */ @ExperimentalHazeApi val Default: HazeInputScale get() = None diff --git a/haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChildNode.kt b/haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChildNode.kt index c5b5edf..97ca016 100644 --- a/haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChildNode.kt +++ b/haze/src/commonMain/kotlin/dev/chrisbanes/haze/HazeChildNode.kt @@ -259,24 +259,19 @@ class HazeChildNode( } override fun ContentDrawScope.draw() { - log(TAG) { "-> HazeChild. start draw()" } - require(!state.contentDrawing) { "Layout nodes using Modifier.haze and Modifier.hazeChild can not be descendants of each other" } - if (!isValid) { - // If we don't have any effects, just call drawContent and return early - drawContent() - log(TAG) { "-> HazeChild. end draw()" } - return - } + log(TAG) { "-> HazeChild. start draw()" } - val contentLayer = state.contentLayer - if (contentLayer != null && blurEnabled && canUseGraphicLayers()) { - drawEffectWithGraphicsLayer(contentLayer) - } else { - drawEffectWithScrim() + if (isValid) { + val contentLayer = state.contentLayer + if (contentLayer != null && blurEnabled && canUseGraphicLayers()) { + drawEffectWithGraphicsLayer(contentLayer) + } else { + drawEffectWithScrim() + } } // Finally we draw the content @@ -535,9 +530,20 @@ internal data class RenderEffectParams( ) @ExperimentalHazeApi -internal fun HazeChildNode.calculateInputScaleFactor(): Float = when (val s = inputScale) { +internal fun HazeChildNode.calculateInputScaleFactor( + blurRadius: Dp = resolveBlurRadius(), +): Float = when (val s = inputScale) { HazeInputScale.None -> 1f is HazeInputScale.Fixed -> s.scale + HazeInputScale.Auto -> { + when { + // For small blurRadius values, input scaling is very noticeable therefore we turn it off + blurRadius < 7.dp -> 1f + progressive != null -> 0.5f + mask != null -> 0.5f + else -> 0.3334f + } + } } @OptIn(ExperimentalHazeApi::class) diff --git a/sample/shared/src/commonMain/kotlin/dev/chrisbanes/haze/sample/Samples.kt b/sample/shared/src/commonMain/kotlin/dev/chrisbanes/haze/sample/Samples.kt index 9b84603..e038621 100644 --- a/sample/shared/src/commonMain/kotlin/dev/chrisbanes/haze/sample/Samples.kt +++ b/sample/shared/src/commonMain/kotlin/dev/chrisbanes/haze/sample/Samples.kt @@ -41,12 +41,11 @@ import dev.chrisbanes.haze.HazeInputScale val Samples = listOf( Sample("Scaffold") { ScaffoldSample(it) }, - Sample("Scaffold (input scaled)") { ScaffoldSample(it, inputScale = HazeInputScale.Fixed(0.5f)) }, + Sample("Scaffold (input scaled)") { ScaffoldSample(it, inputScale = HazeInputScale.Auto) }, Sample("Scaffold (progressive blur)") { ScaffoldSample(it, ScaffoldSampleMode.Progressive) }, - Sample("Scaffold (progressive blur, input scaled)") { - ScaffoldSample(it, ScaffoldSampleMode.Progressive, HazeInputScale.Fixed(0.5f)) - }, + Sample("Scaffold (progressive blur, input scaled)") { ScaffoldSample(it, ScaffoldSampleMode.Progressive, HazeInputScale.Auto) }, Sample("Scaffold (masked)") { ScaffoldSample(it, ScaffoldSampleMode.Mask) }, + Sample("Scaffold (masked, input scaled)") { ScaffoldSample(it, ScaffoldSampleMode.Mask, HazeInputScale.Auto) }, Sample("Credit Card") { CreditCardSample(it) }, Sample("Images List") { ImagesList(it) }, Sample("List over Image") { ListOverImage(it) },