mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
feat: Add option to lower the threshold for hardware bitmaps
This commit is contained in:
parent
27002a20ef
commit
fd73958923
7 changed files with 85 additions and 48 deletions
|
@ -51,6 +51,8 @@ import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||||
import eu.kanade.tachiyomi.ui.source.SourcePresenter
|
import eu.kanade.tachiyomi.ui.source.SourcePresenter
|
||||||
import eu.kanade.tachiyomi.util.manga.MangaCoverMetadata
|
import eu.kanade.tachiyomi.util.manga.MangaCoverMetadata
|
||||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil
|
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil
|
||||||
|
import eu.kanade.tachiyomi.util.system.GLUtil
|
||||||
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
import eu.kanade.tachiyomi.util.system.launchIO
|
import eu.kanade.tachiyomi.util.system.launchIO
|
||||||
import eu.kanade.tachiyomi.util.system.localeContext
|
import eu.kanade.tachiyomi.util.system.localeContext
|
||||||
import eu.kanade.tachiyomi.util.system.notification
|
import eu.kanade.tachiyomi.util.system.notification
|
||||||
|
@ -102,6 +104,10 @@ open class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.F
|
||||||
modules(preferenceModule(this@App), appModule(this@App), domainModule())
|
modules(preferenceModule(this@App), appModule(this@App), domainModule())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||||
|
|
||||||
|
val scope = ProcessLifecycleOwner.get().lifecycleScope
|
||||||
|
|
||||||
basePreferences.crashReport().changes()
|
basePreferences.crashReport().changes()
|
||||||
.onEach {
|
.onEach {
|
||||||
try {
|
try {
|
||||||
|
@ -110,18 +116,23 @@ open class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.F
|
||||||
// Probably already enabled/disabled
|
// Probably already enabled/disabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
.launchIn(scope)
|
||||||
|
|
||||||
setupNotificationChannels()
|
setupNotificationChannels()
|
||||||
|
|
||||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
|
||||||
|
|
||||||
MangaCoverMetadata.load()
|
MangaCoverMetadata.load()
|
||||||
preferences.nightMode().changes()
|
preferences.nightMode().changes()
|
||||||
.onEach { AppCompatDelegate.setDefaultNightMode(it) }
|
.onEach { AppCompatDelegate.setDefaultNightMode(it) }
|
||||||
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
.launchIn(scope)
|
||||||
|
|
||||||
ProcessLifecycleOwner.get().lifecycleScope.launchIO {
|
basePreferences.hardwareBitmapThreshold().let { preference ->
|
||||||
|
if (!preference.isSet()) preference.set(GLUtil.DEVICE_TEXTURE_LIMIT)
|
||||||
|
}
|
||||||
|
basePreferences.hardwareBitmapThreshold().changes()
|
||||||
|
.onEach { ImageUtil.hardwareBitmapThreshold = it }
|
||||||
|
.launchIn(scope)
|
||||||
|
|
||||||
|
scope.launchIO {
|
||||||
with(TachiyomiWidgetManager()) { this@App.init() }
|
with(TachiyomiWidgetManager()) { this@App.init() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +171,7 @@ open class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.F
|
||||||
notificationManager.cancel(Notifications.ID_INCOGNITO_MODE)
|
notificationManager.cancel(Notifications.ID_INCOGNITO_MODE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(ProcessLifecycleOwner.get().lifecycleScope)
|
.launchIn(scope)
|
||||||
|
|
||||||
initializeMigrator()
|
initializeMigrator()
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ import eu.kanade.tachiyomi.data.coil.customDecoder
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonSubsamplingImageView
|
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonSubsamplingImageView
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.GLUtil
|
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||||
import okio.BufferedSource
|
import okio.BufferedSource
|
||||||
|
@ -127,7 +126,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
} else {
|
} else {
|
||||||
SubsamplingScaleImageView(context)
|
SubsamplingScaleImageView(context)
|
||||||
}.apply {
|
}.apply {
|
||||||
setMaxTileSize(GLUtil.maxTextureSize)
|
setMaxTileSize(ImageUtil.hardwareBitmapThreshold)
|
||||||
setDoubleTapZoomStyle(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER)
|
setDoubleTapZoomStyle(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER)
|
||||||
setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE)
|
setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE)
|
||||||
setMinimumTileDpi(180)
|
setMinimumTileDpi(180)
|
||||||
|
@ -232,8 +231,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
isVisible = true
|
isVisible = true
|
||||||
}
|
}
|
||||||
is BufferedSource -> {
|
is BufferedSource -> {
|
||||||
// FIXME: Remove `ImageUtil.isMaxTextureSizeExceeded` after porting https://github.com/mihonapp/mihon/commit/dcddac5daaff3ec89c8507c35dc13d345ffdb6d7#diff-cbb19957efc1d319c0cdc62d5cf4b32bad5b51da21d3c67c3d4256200eb9c5d1
|
if (!isWebtoon) {
|
||||||
if (!isWebtoon || ImageUtil.isMaxTextureSizeExceeded(data)) {
|
|
||||||
setHardwareConfig(!ImageUtil.isMaxTextureSizeExceeded(data))
|
setHardwareConfig(!ImageUtil.isMaxTextureSizeExceeded(data))
|
||||||
setImage(ImageSource.inputStream(data.inputStream()))
|
setImage(ImageSource.inputStream(data.inputStream()))
|
||||||
isVisible = true
|
isVisible = true
|
||||||
|
|
|
@ -57,6 +57,7 @@ import eu.kanade.tachiyomi.ui.setting.preference
|
||||||
import eu.kanade.tachiyomi.ui.setting.preferenceCategory
|
import eu.kanade.tachiyomi.ui.setting.preferenceCategory
|
||||||
import eu.kanade.tachiyomi.ui.setting.switchPreference
|
import eu.kanade.tachiyomi.ui.setting.switchPreference
|
||||||
import eu.kanade.tachiyomi.util.CrashLogUtil
|
import eu.kanade.tachiyomi.util.CrashLogUtil
|
||||||
|
import eu.kanade.tachiyomi.util.system.GLUtil
|
||||||
import eu.kanade.tachiyomi.util.system.disableItems
|
import eu.kanade.tachiyomi.util.system.disableItems
|
||||||
import eu.kanade.tachiyomi.util.system.e
|
import eu.kanade.tachiyomi.util.system.e
|
||||||
import eu.kanade.tachiyomi.util.system.isPackageInstalled
|
import eu.kanade.tachiyomi.util.system.isPackageInstalled
|
||||||
|
@ -73,6 +74,7 @@ import eu.kanade.tachiyomi.util.view.setPositiveButton
|
||||||
import eu.kanade.tachiyomi.util.view.setTitle
|
import eu.kanade.tachiyomi.util.view.setTitle
|
||||||
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlinx.collections.immutable.toImmutableMap
|
||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -393,8 +395,25 @@ class SettingsAdvancedController : SettingsLegacyController() {
|
||||||
preferenceCategory {
|
preferenceCategory {
|
||||||
titleRes = MR.strings.reader
|
titleRes = MR.strings.reader
|
||||||
|
|
||||||
|
listPreference(activity) {
|
||||||
|
bindTo(basePreferences.hardwareBitmapThreshold())
|
||||||
|
titleRes = MR.strings.pref_hardware_bitmap_threshold
|
||||||
|
|
||||||
|
val entryMap = GLUtil.CUSTOM_TEXTURE_LIMIT_OPTIONS
|
||||||
|
.associateWith { it.toString() }
|
||||||
|
.toImmutableMap()
|
||||||
|
entries = entryMap.values.toList()
|
||||||
|
entryValues = entryMap.keys.map { it.toString() }.toList()
|
||||||
|
|
||||||
|
isVisible = GLUtil.DEVICE_TEXTURE_LIMIT > GLUtil.SAFE_TEXTURE_LIMIT
|
||||||
|
|
||||||
|
basePreferences.hardwareBitmapThreshold().changesIn(viewScope) { threshold ->
|
||||||
|
summary = context.getString(MR.strings.pref_hardware_bitmap_threshold_summary, threshold)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
preference {
|
preference {
|
||||||
key = "pref_display_profile"
|
bindTo(basePreferences.displayProfile())
|
||||||
titleRes = MR.strings.pref_display_profile
|
titleRes = MR.strings.pref_display_profile
|
||||||
onClick {
|
onClick {
|
||||||
(activity as? MainActivity)?.showColourProfilePicker()
|
(activity as? MainActivity)?.showColourProfilePicker()
|
||||||
|
|
|
@ -3,52 +3,54 @@ package eu.kanade.tachiyomi.util.system
|
||||||
import javax.microedition.khronos.egl.EGL10
|
import javax.microedition.khronos.egl.EGL10
|
||||||
import javax.microedition.khronos.egl.EGLConfig
|
import javax.microedition.khronos.egl.EGLConfig
|
||||||
import javax.microedition.khronos.egl.EGLContext
|
import javax.microedition.khronos.egl.EGLContext
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
class GLUtil private constructor() {
|
object GLUtil {
|
||||||
companion object {
|
val DEVICE_TEXTURE_LIMIT: Int by lazy {
|
||||||
// Safe minimum default size
|
// Get EGL Display
|
||||||
private const val IMAGE_MAX_BITMAP_DIMENSION = 2048
|
val egl = EGLContext.getEGL() as EGL10
|
||||||
|
val display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
|
||||||
|
|
||||||
val maxTextureSize: Int
|
// Initialise
|
||||||
get() {
|
val version = IntArray(2)
|
||||||
// Get EGL Display
|
egl.eglInitialize(display, version)
|
||||||
val egl = EGLContext.getEGL() as EGL10
|
|
||||||
val display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
|
|
||||||
|
|
||||||
// Initialise
|
// Query total number of configurations
|
||||||
val version = IntArray(2)
|
val totalConfigurations = IntArray(1)
|
||||||
egl.eglInitialize(display, version)
|
egl.eglGetConfigs(display, null, 0, totalConfigurations)
|
||||||
|
|
||||||
// Query total number of configurations
|
// Query actual list configurations
|
||||||
val totalConfigurations = IntArray(1)
|
val configurationsList = arrayOfNulls<EGLConfig>(totalConfigurations[0])
|
||||||
egl.eglGetConfigs(display, null, 0, totalConfigurations)
|
egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations)
|
||||||
|
|
||||||
// Query actual list configurations
|
val textureSize = IntArray(1)
|
||||||
val configurationsList = arrayOfNulls<EGLConfig>(totalConfigurations[0])
|
var maximumTextureSize = 0
|
||||||
egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations)
|
|
||||||
|
|
||||||
val textureSize = IntArray(1)
|
// Iterate through all the configurations to located the maximum texture size
|
||||||
var maximumTextureSize = 0
|
for (i in 0 until totalConfigurations[0]) {
|
||||||
|
// Only need to check for width since opengl textures are always squared
|
||||||
|
egl.eglGetConfigAttrib(display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize)
|
||||||
|
|
||||||
// Iterate through all the configurations to located the maximum texture size
|
// Keep track of the maximum texture size
|
||||||
for (i in 0 until totalConfigurations[0]) {
|
if (maximumTextureSize < textureSize[0]) maximumTextureSize = textureSize[0]
|
||||||
// Only need to check for width since opengl textures are always squared
|
}
|
||||||
egl.eglGetConfigAttrib(display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize)
|
|
||||||
|
|
||||||
// Keep track of the maximum texture size
|
// Release
|
||||||
if (maximumTextureSize < textureSize[0]) maximumTextureSize = textureSize[0]
|
egl.eglTerminate(display)
|
||||||
}
|
|
||||||
|
|
||||||
// Release
|
// Return largest texture size found (after making it a multiplier of [Multiplier]), or default
|
||||||
egl.eglTerminate(display)
|
if (maximumTextureSize > SAFE_TEXTURE_LIMIT) {
|
||||||
|
(maximumTextureSize / MULTIPLIER) * MULTIPLIER
|
||||||
// Return largest texture size found, or default
|
} else {
|
||||||
return max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION)
|
SAFE_TEXTURE_LIMIT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
const val SAFE_TEXTURE_LIMIT: Int = 2048
|
||||||
throw InstantiationException("This class is not for instantiation")
|
|
||||||
|
val CUSTOM_TEXTURE_LIMIT_OPTIONS: List<Int> by lazy {
|
||||||
|
val steps = ((DEVICE_TEXTURE_LIMIT / MULTIPLIER) - 1)
|
||||||
|
List(steps) { (it + 2) * MULTIPLIER }.asReversed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val MULTIPLIER: Int = 1024
|
||||||
|
|
|
@ -785,9 +785,11 @@ object ImageUtil {
|
||||||
fun isMaxTextureSizeExceeded(bitmap: Bitmap): Boolean =
|
fun isMaxTextureSizeExceeded(bitmap: Bitmap): Boolean =
|
||||||
isMaxTextureSizeExceeded(bitmap.width, bitmap.height)
|
isMaxTextureSizeExceeded(bitmap.width, bitmap.height)
|
||||||
|
|
||||||
|
var hardwareBitmapThreshold: Int = GLUtil.SAFE_TEXTURE_LIMIT
|
||||||
|
|
||||||
private fun isMaxTextureSizeExceeded(width: Int, height: Int): Boolean {
|
private fun isMaxTextureSizeExceeded(width: Int, height: Int): Boolean {
|
||||||
if (minOf(width, height) <= 0) return false
|
if (minOf(width, height) <= 0) return false
|
||||||
|
|
||||||
return maxOf(width, height) > GLUtil.maxTextureSize
|
return maxOf(width, height) > hardwareBitmapThreshold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.core.preference.Preference
|
||||||
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
import eu.kanade.tachiyomi.core.preference.PreferenceStore
|
||||||
import eu.kanade.tachiyomi.core.preference.getEnum
|
import eu.kanade.tachiyomi.core.preference.getEnum
|
||||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
|
||||||
|
import eu.kanade.tachiyomi.util.system.GLUtil
|
||||||
import yokai.i18n.MR
|
import yokai.i18n.MR
|
||||||
|
|
||||||
class BasePreferences(private val preferenceStore: PreferenceStore) {
|
class BasePreferences(private val preferenceStore: PreferenceStore) {
|
||||||
|
@ -46,4 +47,6 @@ class BasePreferences(private val preferenceStore: PreferenceStore) {
|
||||||
DEFAULT(MR.strings.recents_long_tap_default),
|
DEFAULT(MR.strings.recents_long_tap_default),
|
||||||
LAST_READ(MR.strings.recents_long_tap_last_read)
|
LAST_READ(MR.strings.recents_long_tap_last_read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hardwareBitmapThreshold() = preferenceStore.getInt("pref_hardware_bitmap_threshold", GLUtil.SAFE_TEXTURE_LIMIT)
|
||||||
}
|
}
|
||||||
|
|
|
@ -513,6 +513,8 @@
|
||||||
<string name="pref_low">Low</string>
|
<string name="pref_low">Low</string>
|
||||||
<string name="pref_lowest">Lowest</string>
|
<string name="pref_lowest">Lowest</string>
|
||||||
<string name="pref_display_profile">Custom display profile</string>
|
<string name="pref_display_profile">Custom display profile</string>
|
||||||
|
<string name="pref_hardware_bitmap_threshold">Custom hardware bitmap threshold</string>
|
||||||
|
<string name="pref_hardware_bitmap_threshold_summary">If reader loads a blank image incrementally reduce the threshold.\nSelected: %s</string>
|
||||||
<string name="pref_double_tap_zoom">Double tap to zoom</string>
|
<string name="pref_double_tap_zoom">Double tap to zoom</string>
|
||||||
|
|
||||||
<!-- Manga details -->
|
<!-- Manga details -->
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue