Async image data loading

This commit is contained in:
DBotThePony 2023-10-11 23:54:27 +07:00
parent 7cb9a7951f
commit c8488c3565
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 42 additions and 36 deletions

View File

@ -520,15 +520,19 @@ class StarboundClient : Closeable {
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
})
tex.upload(when (data.amountOfChannels) {
1 -> GL_RED
3 -> GL_RGB
4 -> GL_RGBA
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
}, GL_UNSIGNED_BYTE, data.data)
val fileFormat = when (data.amountOfChannels) {
1 -> GL_RED
3 -> GL_RGB
4 -> GL_RGBA
else -> throw IllegalArgumentException("Unknown amount of channels in $it: ${data.amountOfChannels}")
}
tex.textureMinFilter = GL_NEAREST
tex.textureMagFilter = GL_NEAREST
data.data.thenApplyAsync({
tex.upload(fileFormat, GL_UNSIGNED_BYTE, it)
tex.textureMinFilter = GL_NEAREST
tex.textureMagFilter = GL_NEAREST
}, foregroundExecutor)
tex
}

View File

@ -1,7 +1,10 @@
package ru.dbotthepony.kstarbound.defs.image
import com.github.benmanes.caffeine.cache.AsyncLoadingCache
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.CacheLoader
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.LoadingCache
import com.github.benmanes.caffeine.cache.Scheduler
import com.google.common.collect.ImmutableList
import com.google.gson.JsonArray
@ -32,6 +35,7 @@ import java.nio.ByteBuffer
import java.time.Duration
import java.util.Collections
import java.util.Optional
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.locks.ReentrantLock
@ -68,11 +72,11 @@ class Image private constructor(
}
}
val data: ByteBuffer get() {
val data: CompletableFuture<ByteBuffer> get() {
var get = dataRef?.get()
if (get != null)
return get
return CompletableFuture.completedFuture(get)
lock.lock()
@ -80,31 +84,14 @@ class Image private constructor(
get = dataRef?.get()
if (get != null)
return get
return CompletableFuture.completedFuture(get)
get = dataCache.get(path) {
val getWidth = intArrayOf(0)
val getHeight = intArrayOf(0)
val components = intArrayOf(0)
val f = dataCache.get(source)
val data = STBImage.stbi_load_from_memory(
source.readDirect(),
getWidth, getHeight,
components, 0
) ?: throw IllegalArgumentException("File $source is not an image or it is corrupted")
if (f.isDone)
dataRef = WeakReference(f.get())
val address = MemoryUtil.memAddress(data)
Starbound.CLEANER.register(data) { STBImage.nstbi_image_free(address) }
check(getWidth[0] == width && getHeight[0] == height && components[0] == amountOfChannels) {
"Actual loaded image differs from constructed (this $width x $height with $amountOfChannels channels; loaded ${getWidth[0]} x ${getHeight[0]} with ${components[0]} channels)"
}
data
}
dataRef = WeakReference(get)
return get
return f.copy()
} finally {
lock.unlock()
}
@ -149,7 +136,7 @@ class Image private constructor(
require(x in 0 until width && y in 0 until height) { "Position out of bounds: $x $y" }
val offset = (this.y + y) * this@Image.width * amountOfChannels + (this.x + x) * amountOfChannels
val data = data
val data = data.join()
when (amountOfChannels) {
4 -> return data[offset].toInt() or
@ -273,12 +260,27 @@ class Image private constructor(
private val imageCache = ConcurrentHashMap<String, Optional<Image>>()
private val logger = LogManager.getLogger()
private val dataCache: Cache<String, ByteBuffer> = Caffeine.newBuilder()
private val dataCache: AsyncLoadingCache<IStarboundFile, ByteBuffer> = Caffeine.newBuilder()
.expireAfterAccess(Duration.ofMinutes(1))
.weigher<String, ByteBuffer> { key, value -> value.capacity() }
.weigher<IStarboundFile, ByteBuffer> { key, value -> value.capacity() }
.maximumWeight(1_024L * 1_024L * 256L /* 256 МиБ */)
.scheduler(Scheduler.systemScheduler())
.build()
.buildAsync(CacheLoader {
val getWidth = intArrayOf(0)
val getHeight = intArrayOf(0)
val components = intArrayOf(0)
val data = STBImage.stbi_load_from_memory(
it.readDirect(),
getWidth, getHeight,
components, 0
) ?: throw IllegalArgumentException("File $it is not an image or it is corrupted")
val address = MemoryUtil.memAddress(data)
Starbound.CLEANER.register(data) { STBImage.nstbi_image_free(address) }
data
})
@JvmStatic
fun get(path: String): Image? {