Двухуровневый кеш текстур

This commit is contained in:
DBotThePony 2023-03-28 22:38:27 +07:00
parent 0910b093f8
commit 952f245e8f
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -6,7 +6,6 @@ import org.apache.logging.log4j.LogManager
import org.lwjgl.opengl.GL
import org.lwjgl.opengl.GL46.*
import org.lwjgl.opengl.GLCapabilities
import ru.dbotthepony.kstarbound.api.ISBFileLocator
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.freetype.FreeType
import ru.dbotthepony.kstarbound.client.freetype.InvalidArgumentException
@ -28,10 +27,8 @@ import java.lang.ref.Cleaner
import java.lang.ref.WeakReference
import java.time.Duration
import java.util.*
import java.util.concurrent.ThreadFactory
import java.util.concurrent.locks.LockSupport
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.roundToInt
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@ -435,22 +432,27 @@ class GLStateTracker(val client: StarboundClient) {
fun newVAO() = VertexArrayObject(this)
fun newTexture(name: String = "<unknown>") = GLTexture2D(this, name)
/**
* Так как текстуры не занимают память в куче JVM, а только видеопамять, то
* такой кеш довольно хрупкий
*/
private val named2DTextures: Cache<String, GLTexture2D> = Caffeine.newBuilder()
// минимальное время хранения 5 минут и...
private val named2DTextures0: Cache<String, GLTexture2D> = Caffeine.newBuilder()
.softValues()
.expireAfterAccess(Duration.ofMinutes(5))
.build()
// ...бесконечное хранение пока кто-то все ещё использует текстуру
private val named2DTextures1: Cache<String, GLTexture2D> = Caffeine.newBuilder()
.weakValues()
.build()
init {
val ref = WeakReference(named2DTextures)
val ref0 = WeakReference(named2DTextures0)
val ref1 = WeakReference(named2DTextures1)
val worker = Runnable {
while (true) {
val get = ref.get() ?: break
get.cleanUp()
val get0 = ref0.get() ?: break
get0.cleanUp()
val get1 = ref1.get() ?: break
get1.cleanUp()
LockSupport.parkNanos(1_000_000_000L)
}
}
@ -473,14 +475,16 @@ class GLStateTracker(val client: StarboundClient) {
fun loadTexture(path: String): GLTexture2D {
ensureSameThread()
return named2DTextures.get(path) {
if (!client.starbound.exists(path)) {
LOGGER.error("Texture {} is missing! Falling back to {}", path, missingTexturePath)
missingTexture
} else {
newTexture(path).upload(client.starbound.imageData(path)).generateMips().also {
it.textureMinFilter = GL_NEAREST
it.textureMagFilter = GL_NEAREST
return named2DTextures0.get(path) {
named2DTextures1.get(it) {
if (!client.starbound.exists(it)) {
LOGGER.error("Texture {} is missing! Falling back to {}", it, missingTexturePath)
missingTexture
} else {
newTexture(it).upload(client.starbound.imageData(it)).generateMips().also {
it.textureMinFilter = GL_NEAREST
it.textureMagFilter = GL_NEAREST
}
}
}
}