world renderer: remove locking hell

This commit is contained in:
Bixilon 2022-12-23 14:26:16 +01:00
parent 5672bacb75
commit a4928205f0
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
6 changed files with 84 additions and 106 deletions

View File

@ -31,7 +31,7 @@ class LoadedMeshes(
fun cleanup(lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
val iterator = meshes.iterator()
for ((chunkPosition, sections) in iterator) {
@ -42,21 +42,22 @@ class LoadedMeshes(
renderer.unloadingQueue.forceQueue(sections.values)
}
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun clear(lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
for (sections in meshes.values) {
renderer.unloadingQueue.forceQueue(sections.values, lock)
}
this.meshes.clear()
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun unload(position: ChunkPosition, lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
val meshes = this.meshes.remove(position)
@ -64,11 +65,11 @@ class LoadedMeshes(
renderer.unloadingQueue.forceQueue(meshes.values, lock)
}
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun unload(position: ChunkPosition, sectionHeight: Int, lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
val meshes = this.meshes[position]
@ -82,7 +83,7 @@ class LoadedMeshes(
}
}
if (lock) this.lock.unlock()
if (lock) unlock()
}
@ -113,10 +114,12 @@ class LoadedMeshes(
}
fun lock() {
renderer.lock.acquire()
this.lock.lock()
}
fun unlock() {
this.lock.unlock()
renderer.lock.release()
}
}

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.rendering.world
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kotlinglm.vec3.Vec3
import de.bixilon.kutil.concurrent.lock.simple.SimpleLock
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.kutil.observer.DataObserver.Companion.observe
import de.bixilon.minosoft.config.key.KeyActions
@ -60,6 +61,7 @@ class WorldRenderer(
private val shader = renderSystem.createShader(minosoft("world")) { WorldShader(it, false) }
private val transparentShader = renderSystem.createShader(minosoft("world")) { WorldShader(it, true) }
private val textShader = renderSystem.createShader(minosoft("world/text")) { WorldTextShader(it) }
val lock = SimpleLock()
val world: World = connection.world
val loaded = LoadedMeshes(this)
@ -111,13 +113,10 @@ class WorldRenderer(
}
}
renderWindow.inputHandler.registerKeyCallback(
"minosoft:clear_chunk_cache".toResourceLocation(),
KeyBinding(
renderWindow.inputHandler.registerKeyCallback("minosoft:clear_chunk_cache".toResourceLocation(), KeyBinding(
KeyActions.MODIFIER to setOf(KeyCodes.KEY_F3),
KeyActions.PRESS to setOf(KeyCodes.KEY_A),
)
) { clearChunkCache() }
)) { clearChunkCache() }
profile.rendering::antiMoirePattern.observe(this) { clearChunkCache() }
val rendering = connection.profiles.rendering
@ -127,26 +126,17 @@ class WorldRenderer(
val distance = maxOf(viewDistance, profile.simulationDistance)
if (distance < this.previousViewDistance) {
// Unload all chunks(-sections) that are out of view distance
culledQueue.lock()
meshingQueue.lock()
loadingQueue.lock()
unloadingQueue.lock()
loaded.lock()
lock.lock()
loaded.cleanup(false)
culledQueue.cleanup(false)
meshingQueue.cleanup()
meshingQueue.cleanup(false)
meshingQueue.tasks.cleanup()
loadingQueue.cleanup(false)
loaded.unlock()
meshingQueue.unlock()
culledQueue.unlock()
loadingQueue.unlock()
unloadingQueue.unlock()
lock.unlock()
} else {
master.tryQueue(world)
}
@ -166,16 +156,10 @@ class WorldRenderer(
}
fun unloadWorld() {
culledQueue.lock()
meshingQueue.lock()
loadingQueue.lock()
loaded.lock()
lock.lock()
meshingQueue.tasks.interruptAll()
unloadingQueue.lock()
loaded.clear(false)
culledQueue.clear(false)
@ -184,19 +168,11 @@ class WorldRenderer(
clearVisibleNextFrame = true
loaded.unlock()
meshingQueue.unlock()
culledQueue.unlock()
loadingQueue.unlock()
lock.unlock()
}
fun unloadChunk(chunkPosition: Vec2i) {
culledQueue.lock()
meshingQueue.lock()
loadingQueue.lock()
unloadingQueue.lock()
loaded.lock()
lock.lock()
meshingQueue.tasks.interrupt(chunkPosition)
@ -209,20 +185,13 @@ class WorldRenderer(
loaded.unload(chunkPosition, false)
loaded.unlock()
culledQueue.unlock()
loadingQueue.unlock()
unloadingQueue.unlock()
meshingQueue.unlock()
lock.unlock()
}
fun queueItemUnload(item: WorldQueueItem) {
culledQueue.lock()
meshingQueue.lock()
loadingQueue.lock()
unloadingQueue.lock()
loaded.lock()
lock.lock()
loaded.unload(item.chunkPosition, item.sectionHeight, false)
culledQueue.remove(item.chunkPosition, item.sectionHeight, false)
@ -233,11 +202,7 @@ class WorldRenderer(
meshingQueue.tasks.interrupt(item.chunkPosition, item.sectionHeight)
loaded.unlock()
meshingQueue.unlock()
culledQueue.unlock()
loadingQueue.unlock()
unloadingQueue.unlock()
lock.unlock()
}

View File

@ -31,7 +31,7 @@ class CulledQueue(
fun cleanup(lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
val iterator = queue.iterator()
for ((chunkPosition, _) in iterator) {
if (renderer.visibilityGraph.isChunkVisible(chunkPosition)) {
@ -39,34 +39,36 @@ class CulledQueue(
}
iterator.remove()
}
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun lock() {
renderer.lock.acquire()
this.lock.lock()
}
fun unlock() {
this.lock.unlock()
renderer.lock.release()
}
fun clear(lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
this.queue.clear()
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun remove(position: ChunkPosition, lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
queue -= position
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun remove(position: ChunkPosition, height: SectionHeight, lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
queue[position]?.let {
if (it.remove(height) && it.isEmpty()) {
@ -74,7 +76,7 @@ class CulledQueue(
}
}
if (lock) this.lock.unlock()
if (lock) unlock()
}

View File

@ -34,9 +34,9 @@ class MeshLoadingQueue(
fun work() {
lock.lock()
lock()
if (meshes.isEmpty()) {
lock.unlock()
unlock()
return
}
@ -73,7 +73,7 @@ class MeshLoadingQueue(
}
renderer.loaded.unlock()
lock.unlock()
unlock()
if (count > 0) {
renderer.visible.sort()
@ -82,7 +82,7 @@ class MeshLoadingQueue(
fun queue(mesh: WorldMesh) {
lock.lock()
lock()
if (!this.positions.add(QueuePosition(mesh))) {
// already inside, remove
meshes.remove(mesh)
@ -93,11 +93,11 @@ class MeshLoadingQueue(
} else {
meshes += mesh
}
lock.unlock()
unlock()
}
fun abort(position: ChunkPosition, lock: Boolean = true) {
if (lock) this.lock.lock()
if (lock) lock()
val positions: MutableSet<QueuePosition> = mutableSetOf()
this.positions.removeAll {
if (it.position != position) {
@ -107,14 +107,14 @@ class MeshLoadingQueue(
return@removeAll true
}
this.meshes.removeAll { QueuePosition(it.chunkPosition, it.sectionHeight) in positions }
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun cleanup(lock: Boolean) {
val remove: MutableSet<QueuePosition> = mutableSetOf()
if (lock) this.lock.lock()
if (lock) lock()
this.positions.removeAll {
if (renderer.visibilityGraph.isChunkVisible(it.position)) {
return@removeAll false
@ -124,22 +124,24 @@ class MeshLoadingQueue(
}
this.meshes.removeAll { QueuePosition(it) in remove }
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun clear(lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
this.positions.clear()
this.meshes.clear()
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun lock() {
renderer.lock.acquire()
this.lock.lock()
}
fun unlock() {
this.lock.unlock()
renderer.lock.release()
}
}

View File

@ -45,16 +45,16 @@ class MeshUnloadingQueue(
}
fun work() {
lock.lock()
lock()
try {
forceWork()
} finally {
lock.unlock()
unlock()
}
}
fun forceQueue(mesh: WorldMesh, lock: Boolean = true) {
if (lock) this.lock.lock()
if (lock) lock()
if (mesh.chunkPosition == renderer.connection.player.positionInfo.chunkPosition) { // TODO: camera
this.meshes.add(0, mesh)
@ -63,42 +63,44 @@ class MeshUnloadingQueue(
}
this.positions += QueuePosition(mesh)
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun queue(mesh: WorldMesh, lock: Boolean = true) {
if (lock) this.lock.lock()
if (lock) lock()
if (QueuePosition(mesh) in this.positions) {
// already queued
// TODO: maybe camera chunk position changed?
this.lock.unlock()
unlock()
return
}
forceQueue(mesh, false)
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun forceQueue(meshes: Collection<WorldMesh>, lock: Boolean = true) {
if (lock) this.lock.lock()
if (lock) lock()
for (mesh in meshes) {
forceQueue(mesh, false)
}
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun queue(meshes: Collection<WorldMesh>) {
this.lock.lock()
lock()
for (mesh in meshes) {
queue(mesh, false)
}
this.lock.unlock()
unlock()
}
fun lock() {
lock.lock()
renderer.lock.acquire()
this.lock.lock()
}
fun unlock() {
lock.unlock()
this.lock.unlock()
renderer.lock.release()
}
}

View File

@ -33,17 +33,17 @@ class ChunkMeshingQueue(
@Volatile
private var working = false
private val queue: MutableList<WorldQueueItem> = mutableListOf() // queue, that is visible, and should be rendered
private val set: MutableSet<WorldQueueItem> = HashSet() // queue, that is visible, and should be rendered
private val queue: MutableList<WorldQueueItem> = mutableListOf()
private val set: MutableSet<WorldQueueItem> = HashSet()
val lock = SimpleLock()
private val lock = SimpleLock()
val size: Int get() = queue.size
fun sort() {
lock.lock()
lock()
val position = renderer.cameraChunkPosition
val height = renderer.cameraSectionHeight
val cameraSectionPosition = Vec3i(position.x, height, position.y)
@ -54,7 +54,7 @@ class ChunkMeshingQueue(
}
(it.sectionPosition - cameraSectionPosition).length2()
}
lock.unlock()
unlock()
}
@ -68,7 +68,7 @@ class ChunkMeshingQueue(
val items: MutableList<WorldQueueItem> = mutableListOf()
lock.lock()
lock()
for (i in 0 until tasks.max - size) {
if (queue.isEmpty()) {
break
@ -77,9 +77,9 @@ class ChunkMeshingQueue(
set -= item
items += item
}
lock.unlock()
unlock()
for (item in items) {
val runnable = ThreadPoolRunnable(if (item.chunkPosition == renderer.cameraChunkPosition) ThreadPool.HIGH else ThreadPool.LOW, interruptable = true) // Our own chunk is the most important one ToDo: Also make neighbour chunks important
val runnable = ThreadPoolRunnable(if (item.chunkPosition == renderer.cameraChunkPosition) ThreadPool.HIGH else ThreadPool.LOW, interruptable = true) // ToDo: Also make neighbour chunks important
val task = MeshPrepareTask(item.chunkPosition, item.sectionHeight, runnable)
task.runnable.runnable = Runnable { renderer.mesher.tryMesh(item, task, task.runnable) }
tasks += task
@ -100,7 +100,8 @@ class ChunkMeshingQueue(
set -= remove
}
fun cleanup() {
fun cleanup(lock: Boolean) {
if (lock) lock()
val remove: MutableSet<WorldQueueItem> = mutableSetOf()
queue.removeAll {
if (renderer.visibilityGraph.isChunkVisible(it.chunkPosition)) {
@ -110,36 +111,39 @@ class ChunkMeshingQueue(
return@removeAll true
}
set -= remove
if (lock) unlock()
}
fun lock() {
renderer.lock.acquire()
this.lock.lock()
}
fun unlock() {
this.lock.unlock()
renderer.lock.release()
}
fun clear(lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
this.queue.clear()
this.set.clear()
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun remove(item: WorldQueueItem, lock: Boolean) {
if (lock) this.lock.lock()
if (lock) lock()
if (this.set.remove(item)) {
this.queue -= item
}
if (lock) this.lock.unlock()
if (lock) unlock()
}
fun queue(item: WorldQueueItem) {
lock.lock()
lock()
if (set.remove(item)) {
queue -= item
}
@ -149,6 +153,6 @@ class ChunkMeshingQueue(
queue += item
}
set += item
lock.unlock()
unlock()
}
}