diff --git a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt index 1700f0a02f..e2651a5f3e 100644 --- a/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/base/BasePreferences.kt @@ -2,6 +2,7 @@ package eu.kanade.domain.base import android.content.Context import dev.icerock.moko.resources.StringResource +import eu.kanade.tachiyomi.util.system.GLUtil import tachiyomi.core.common.preference.Preference import tachiyomi.core.common.preference.PreferenceStore import tachiyomi.i18n.MR @@ -30,4 +31,6 @@ class BasePreferences( } fun displayProfile() = preferenceStore.getString("pref_display_profile_key", "") + + fun hardwareBitmapThreshold() = preferenceStore.getInt("pref_hardware_bitmap_threshold", GLUtil.SAFE_TEXTURE_LIMIT) } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt index 8cf062ee90..94bc845d8e 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt @@ -47,6 +47,7 @@ import eu.kanade.tachiyomi.network.PREF_DOH_QUAD9 import eu.kanade.tachiyomi.network.PREF_DOH_SHECAN import eu.kanade.tachiyomi.ui.more.OnboardingScreen import eu.kanade.tachiyomi.util.CrashLogUtil +import eu.kanade.tachiyomi.util.system.GLUtil import eu.kanade.tachiyomi.util.system.isDevFlavor import eu.kanade.tachiyomi.util.system.isPreviewBuildType import eu.kanade.tachiyomi.util.system.isShizukuInstalled @@ -331,9 +332,23 @@ object SettingsAdvancedScreen : SearchableSettings { basePreferences.displayProfile().set(uri.toString()) } } + val hardwareBitmapThresholdPref = basePreferences.hardwareBitmapThreshold() + val hardwareBitmapThreshold by hardwareBitmapThresholdPref.collectAsState() return Preference.PreferenceGroup( title = stringResource(MR.strings.pref_category_reader), preferenceItems = persistentListOf( + Preference.PreferenceItem.ListPreference( + pref = hardwareBitmapThresholdPref, + title = stringResource(MR.strings.pref_hardware_bitmap_threshold), + subtitle = stringResource( + MR.strings.pref_hardware_bitmap_threshold_summary, + hardwareBitmapThreshold, + ), + enabled = GLUtil.DEVICE_TEXTURE_LIMIT > GLUtil.SAFE_TEXTURE_LIMIT, + entries = GLUtil.CUSTOM_TEXTURE_LIMIT_OPTIONS + .associateWith { it.toString() } + .toImmutableMap(), + ), Preference.PreferenceItem.TextPreference( title = stringResource(MR.strings.pref_display_profile), subtitle = basePreferences.displayProfile().get(), diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 0f15cf0952..5eb94ecf8d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -41,6 +41,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate import eu.kanade.tachiyomi.util.system.DeviceUtil +import eu.kanade.tachiyomi.util.system.GLUtil import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.animatorDurationScale import eu.kanade.tachiyomi.util.system.cancelNotification @@ -58,6 +59,7 @@ import org.conscrypt.Conscrypt import tachiyomi.core.common.i18n.stringResource import tachiyomi.core.common.preference.Preference import tachiyomi.core.common.preference.PreferenceStore +import tachiyomi.core.common.util.system.ImageUtil import tachiyomi.core.common.util.system.logcat import tachiyomi.i18n.MR import tachiyomi.presentation.widget.WidgetManager @@ -142,6 +144,14 @@ class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factor .onEach(FirebaseConfig::setCrashlyticsEnabled) .launchIn(scope) + basePreferences.hardwareBitmapThreshold().let { preference -> + if (!preference.isSet()) preference.set(GLUtil.DEVICE_TEXTURE_LIMIT) + } + + basePreferences.hardwareBitmapThreshold().changes() + .onEach { ImageUtil.hardwareBitmapThreshold = it } + .launchIn(scope) + setAppCompatDelegateThemeMode(Injekt.get().themeMode().get()) // Updates widget update diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt index 5d66fc8084..c1f4a2328a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ReaderPageImageView.kt @@ -36,7 +36,6 @@ import com.github.chrisbanes.photoview.PhotoView import eu.kanade.tachiyomi.data.coil.cropBorders import eu.kanade.tachiyomi.data.coil.customDecoder import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonSubsamplingImageView -import eu.kanade.tachiyomi.util.system.GLUtil import eu.kanade.tachiyomi.util.system.animatorDurationScale import eu.kanade.tachiyomi.util.view.isVisibleOnScreen import okio.BufferedSource @@ -234,7 +233,7 @@ open class ReaderPageImageView @JvmOverloads constructor( } else { SubsamplingScaleImageView(context) }.apply { - setMaxTileSize(GLUtil.maxTextureSize) + setMaxTileSize(ImageUtil.hardwareBitmapThreshold) setDoubleTapZoomStyle(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER) setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE) setMinimumTileDpi(180) diff --git a/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/system/GLUtil.kt b/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/system/GLUtil.kt index 98bccf126b..16f3203fb5 100644 --- a/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/system/GLUtil.kt +++ b/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/system/GLUtil.kt @@ -3,10 +3,9 @@ package eu.kanade.tachiyomi.util.system import javax.microedition.khronos.egl.EGL10 import javax.microedition.khronos.egl.EGLConfig import javax.microedition.khronos.egl.EGLContext -import kotlin.math.max object GLUtil { - val maxTextureSize: Int by lazy { + val DEVICE_TEXTURE_LIMIT: Int by lazy { // Get EGL Display val egl = EGLContext.getEGL() as EGL10 val display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY) @@ -38,10 +37,20 @@ object GLUtil { // Release egl.eglTerminate(display) - // Return largest texture size found, or default - max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION) + // Return largest texture size found (after making it a multiplier of [Multiplier]), or default + if (maximumTextureSize > SAFE_TEXTURE_LIMIT) { + (maximumTextureSize / MULTIPLIER) * MULTIPLIER + } else { + SAFE_TEXTURE_LIMIT + } + } + + const val SAFE_TEXTURE_LIMIT: Int = 2048 + + val CUSTOM_TEXTURE_LIMIT_OPTIONS: List by lazy { + val steps = ((DEVICE_TEXTURE_LIMIT / MULTIPLIER) - 1) + List(steps) { (it + 2) * MULTIPLIER }.asReversed() } } -// Safe minimum default size -private const val IMAGE_MAX_BITMAP_DIMENSION = 2048 +private const val MULTIPLIER: Int = 1024 diff --git a/core/common/src/main/kotlin/tachiyomi/core/common/util/system/ImageUtil.kt b/core/common/src/main/kotlin/tachiyomi/core/common/util/system/ImageUtil.kt index 68b49f75b9..dc3aec2cf2 100644 --- a/core/common/src/main/kotlin/tachiyomi/core/common/util/system/ImageUtil.kt +++ b/core/common/src/main/kotlin/tachiyomi/core/common/util/system/ImageUtil.kt @@ -320,8 +320,10 @@ object ImageUtil { } } + var hardwareBitmapThreshold: Int = GLUtil.SAFE_TEXTURE_LIMIT + private fun canUseHardwareBitmap(width: Int, height: Int): Boolean { - return maxOf(width, height) <= GLUtil.maxTextureSize + return maxOf(width, height) <= hardwareBitmapThreshold } /** diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index 6d7e7adba1..78cc63fdd5 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -392,6 +392,8 @@ Show reading mode Briefly show current mode when reader is opened Custom display profile + Custom hardware bitmap threshold + If reader loads a blank image incrementally reduce the threshold.\nSelected: %s Crop borders Custom brightness Grayscale