Fix possible memory leaks regarding unused resources, and tighten cache store times
This commit is contained in:
parent
178953bce7
commit
40782fd18f
@ -254,7 +254,7 @@ class StarboundClient : Closeable {
|
||||
|
||||
// минимальное время хранения 5 минут и...
|
||||
private val named2DTextures0: Cache<String, GLTexture2D> = Caffeine.newBuilder()
|
||||
.expireAfterAccess(Duration.ofMinutes(5))
|
||||
.expireAfterAccess(Duration.ofMinutes(1))
|
||||
.build()
|
||||
|
||||
// ...бесконечное хранение пока кто-то все ещё использует текстуру
|
||||
|
@ -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<GLTexture2D, RenderConfig<UberShader>>()
|
||||
private val textureConfigs: Cache<GLTexture2D, RenderConfig<UberShader>> = Caffeine.newBuilder()
|
||||
.weakValues()
|
||||
.weakKeys()
|
||||
.expireAfterAccess(Duration.ofMinutes(1))
|
||||
.build()
|
||||
|
||||
fun config(texture: GLTexture2D): RenderConfig<UberShader> {
|
||||
return textureConfigs.computeIfAbsent(texture, Reference2ObjectFunction {
|
||||
return textureConfigs.get(texture) {
|
||||
object : RenderConfig<UberShader>(this) {
|
||||
override fun setup() {
|
||||
super.setup()
|
||||
|
||||
client.textures2D[0] = texture
|
||||
client.textures2D[0] = it
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class Builder {
|
||||
|
@ -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<ConfiguredMesh<*>>()
|
||||
private val callbacks = ArrayList<() -> Unit>()
|
||||
private val builders = Reference2ObjectLinkedOpenHashMap<RenderConfig<*>, StreamVertexBuilder>()
|
||||
private val builders = Reference2ObjectLinkedOpenHashMap<RenderConfig<*>, 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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ class Image private constructor(
|
||||
|
||||
private val dataCache: Cache<String, ByteBuffer> = Caffeine.newBuilder()
|
||||
.softValues()
|
||||
.expireAfterAccess(Duration.ofMinutes(20))
|
||||
.expireAfterAccess(Duration.ofMinutes(5))
|
||||
.weigher<String, ByteBuffer> { key, value -> value.capacity() }
|
||||
.maximumWeight(1_024L * 1_024L * 256L /* 256 МиБ */)
|
||||
.build()
|
||||
|
Loading…
Reference in New Issue
Block a user