diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt index 65ba5c45..f16fe6b1 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/StarboundClient.kt @@ -254,7 +254,7 @@ class StarboundClient : Closeable { // минимальное время хранения 5 минут и... private val named2DTextures0: Cache = Caffeine.newBuilder() - .expireAfterAccess(Duration.ofMinutes(5)) + .expireAfterAccess(Duration.ofMinutes(1)) .build() // ...бесконечное хранение пока кто-то все ещё использует текстуру diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/gl/shader/UberShader.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/gl/shader/UberShader.kt index 94d6c696..0361f7c3 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/gl/shader/UberShader.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/gl/shader/UberShader.kt @@ -1,9 +1,11 @@ package ru.dbotthepony.kstarbound.client.gl.shader +import com.github.benmanes.caffeine.cache.Cache +import com.github.benmanes.caffeine.cache.Caffeine +import com.github.benmanes.caffeine.cache.Scheduler import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap import it.unimi.dsi.fastutil.objects.ObjectArraySet import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction -import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import org.lwjgl.opengl.GL20.GL_FRAGMENT_SHADER import org.lwjgl.opengl.GL20.GL_VERTEX_SHADER import ru.dbotthepony.kstarbound.client.StarboundClient @@ -15,6 +17,7 @@ import ru.dbotthepony.kstarbound.client.render.RenderConfig import ru.dbotthepony.kvector.api.IStruct4f import ru.dbotthepony.kvector.arrays.Matrix3f import ru.dbotthepony.kvector.vector.RGBAColor +import java.time.Duration import java.util.Collections import java.util.EnumSet import java.util.function.Function @@ -48,18 +51,22 @@ class UberShader private constructor( colorMultiplier = RGBAColor.WHITE } - private val textureConfigs = Reference2ObjectOpenHashMap>() + private val textureConfigs: Cache> = Caffeine.newBuilder() + .weakValues() + .weakKeys() + .expireAfterAccess(Duration.ofMinutes(1)) + .build() fun config(texture: GLTexture2D): RenderConfig { - return textureConfigs.computeIfAbsent(texture, Reference2ObjectFunction { + return textureConfigs.get(texture) { object : RenderConfig(this) { override fun setup() { super.setup() - client.textures2D[0] = texture + client.textures2D[0] = it } } - }) + } } class Builder { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/LayeredRenderer.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/LayeredRenderer.kt index 65bf5919..fa2576e0 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/LayeredRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/LayeredRenderer.kt @@ -39,9 +39,10 @@ object OneShotGeometryLayer : IGeometryLayer { class LayeredRenderer { class Layer(val layer: RenderLayer.Point) : IGeometryLayer { + private data class Tracker(val builder: StreamVertexBuilder, var emptyFrames: Int = 0) private val meshes = ArrayList>() private val callbacks = ArrayList<() -> Unit>() - private val builders = Reference2ObjectLinkedOpenHashMap, StreamVertexBuilder>() + private val builders = Reference2ObjectLinkedOpenHashMap, Tracker>() override fun add(renderer: () -> Unit) { callbacks.add(renderer) @@ -49,17 +50,27 @@ class LayeredRenderer { override fun getBuilder(config: RenderConfig<*>): VertexBuilder { return builders.computeIfAbsent(config, Function { - StreamVertexBuilder(config.program.attributes, initialCapacity = config.initialBuilderCapacity) - }).builder + Tracker(StreamVertexBuilder(config.program.attributes, initialCapacity = config.initialBuilderCapacity)) + }).builder.builder } override fun render() { - builders.entries.forEach { - if (it.value.builder.isNotEmpty()) { - it.key.setup() - it.value.upload() - it.value.draw() - it.key.uninstall() + val iterator = builders.entries.iterator() + + for ((k, v) in iterator) { + if (v.builder.builder.isNotEmpty()) { + v.emptyFrames = 0 + k.setup() + v.builder.upload() + v.builder.draw() + k.uninstall() + } else { + v.emptyFrames++ + + if (v.emptyFrames >= 600) { + // ~10 seconds of inactivity, free resources + iterator.remove() + } } } @@ -73,7 +84,7 @@ class LayeredRenderer { } override fun clear() { - builders.values.forEach { it.builder.begin() } + builders.values.forEach { it.builder.builder.begin() } meshes.clear() callbacks.clear() } @@ -83,8 +94,8 @@ class LayeredRenderer { throw IllegalStateException("This layer (index $layer) contains preconfigured meshes and/or callbacks") return builders.entries.stream() - .filter { it.value.builder.isNotEmpty() } - .map { ConfiguredMesh(it.key, Mesh(it.value.builder)) to layer } + .filter { it.value.builder.builder.isNotEmpty() } + .map { ConfiguredMesh(it.key, Mesh(it.value.builder.builder)) to layer } } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/Image.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/Image.kt index c9e8cb9b..694efd56 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/Image.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/image/Image.kt @@ -275,7 +275,7 @@ class Image private constructor( private val dataCache: Cache = Caffeine.newBuilder() .softValues() - .expireAfterAccess(Duration.ofMinutes(20)) + .expireAfterAccess(Duration.ofMinutes(5)) .weigher { key, value -> value.capacity() } .maximumWeight(1_024L * 1_024L * 256L /* 256 МиБ */) .build()