Massively improve memory usage of world tiles

This commit is contained in:
DBotThePony 2023-10-22 10:12:39 +07:00
parent 949ed802ad
commit 064689fc25
Signed by: DBot
GPG Key ID: DCC23B5715498507
7 changed files with 21 additions and 15 deletions

View File

@ -116,7 +116,7 @@ fun main() {
val rand = Random()
for (i in 0 .. 128) {
for (i in 0 until 0) {
val item = ItemEntity(client.world!!, Registries.items.keys.values.random().value)
item.position = Vector2d(225.0 - i, 785.0)

View File

@ -613,7 +613,7 @@ class StarboundClient : Closeable {
}
val tileRenderers = TileRenderers(this)
var world: ClientWorld? = ClientWorld(this, 0L, Vector2i(3000, 2000), true)
var world: ClientWorld? = ClientWorld(this, 0L, Vector2i(16000, 8000), true)
init {
clearColor = RGBAColor.SLATE_GRAY

View File

@ -9,11 +9,13 @@ import java.lang.ref.WeakReference
import java.util.concurrent.locks.LockSupport
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
import kotlin.math.log
import kotlin.math.roundToInt
// hand-rolled interner, which has similar performance to ConcurrentHashMap
// (given there is no strong congestion, otherwise it performs somewhere above Caffeine interner),
// while yielding significantly better memory utilization than both
class HashTableInterner<T : Any>(private val segmentBits: Int) : Interner<T> {
class HashTableInterner<T : Any>(private val segmentBits: Int = log(Runtime.getRuntime().availableProcessors().toDouble(), 2.0).roundToInt().coerceAtLeast(4)) : Interner<T> {
companion object {
private val interners = ArrayList<WeakReference<HashTableInterner<*>>>()

View File

@ -1,5 +1,7 @@
package ru.dbotthepony.kstarbound.world.api
import com.github.benmanes.caffeine.cache.Interner
import ru.dbotthepony.kstarbound.util.HashTableInterner
import java.io.DataInputStream
sealed class AbstractCell {
@ -23,7 +25,10 @@ sealed class AbstractCell {
stream.skipNBytes(1 + 2 + 1 + 1 + 1 + 1)
}
val EMPTY = ImmutableCell(AbstractTileState.EMPTY, AbstractTileState.EMPTY, AbstractLiquidState.EMPTY, 0, 0, 0, false)
val NULL = ImmutableCell(AbstractTileState.NULL, AbstractTileState.NULL, AbstractLiquidState.EMPTY, 0, 0, 0, false)
@JvmStatic
protected val POOL: Interner<ImmutableCell> = HashTableInterner()
val EMPTY: ImmutableCell = POOL.intern(ImmutableCell(AbstractTileState.EMPTY, AbstractTileState.EMPTY, AbstractLiquidState.EMPTY, 0, 0, 0, false))
val NULL: ImmutableCell = POOL.intern(ImmutableCell(AbstractTileState.NULL, AbstractTileState.NULL, AbstractLiquidState.EMPTY, 0, 0, 0, false))
}
}

View File

@ -1,9 +1,11 @@
package ru.dbotthepony.kstarbound.world.api
import com.github.benmanes.caffeine.cache.Interner
import ru.dbotthepony.kstarbound.Registry
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kstarbound.util.HashTableInterner
import java.io.DataInputStream
sealed class AbstractTileState {
@ -21,7 +23,10 @@ sealed class AbstractTileState {
stream.skipNBytes(2 + 1 + 1 + 2 + 1)
}
val EMPTY = ImmutableTileState(BuiltinMetaMaterials.EMPTY)
val NULL = ImmutableTileState(BuiltinMetaMaterials.NULL)
@JvmStatic
protected val POOL: Interner<ImmutableTileState> = HashTableInterner()
val EMPTY: ImmutableTileState = POOL.intern(ImmutableTileState(BuiltinMetaMaterials.EMPTY))
val NULL: ImmutableTileState = POOL.intern(ImmutableTileState(BuiltinMetaMaterials.NULL))
}
}

View File

@ -29,10 +29,7 @@ data class MutableCell(
}
override fun immutable(): ImmutableCell {
val result = ImmutableCell(foreground.immutable(), background.immutable(), liquid.immutable(), dungeonId, biome, envBiome, isIndestructible)
if (result == NULL) return NULL
if (result == EMPTY) return EMPTY
return result
return POOL.intern(ImmutableCell(foreground.immutable(), background.immutable(), liquid.immutable(), dungeonId, biome, envBiome, isIndestructible))
}
override fun mutable(): MutableCell {

View File

@ -15,10 +15,7 @@ data class MutableTileState(
override var modifierHueShift: Float = 0f,
) : AbstractTileState() {
override fun immutable(): ImmutableTileState {
val result = ImmutableTileState(material, modifier, color, hueShift, modifierHueShift)
if (result == NULL) return NULL
if (result == EMPTY) return EMPTY
return result
return POOL.intern(ImmutableTileState(material, modifier, color, hueShift, modifierHueShift))
}
override fun mutable(): MutableTileState {