From dbd4752d098238e24b9bf60887a6f3028d0da2ec Mon Sep 17 00:00:00 2001 From: Moritz Zwerger Date: Sun, 9 Feb 2025 19:05:17 +0100 Subject: [PATCH] section occlusion: set invalid region for full opaque blocks No need to check if the block is full opaque multiple times. Benchmark time goes down from 18s to 15s, so 17% improvement. Not bad. --- .../world/chunk/neighbours/ChunkNeighbours.kt | 4 ++-- .../world/container/block/SectionOcclusion.kt | 17 ++++++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/world/chunk/neighbours/ChunkNeighbours.kt b/src/main/java/de/bixilon/minosoft/data/world/chunk/neighbours/ChunkNeighbours.kt index c5377bf4e..b982b74e8 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/chunk/neighbours/ChunkNeighbours.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/chunk/neighbours/ChunkNeighbours.kt @@ -1,6 +1,6 @@ /* * Minosoft - * Copyright (C) 2020-2024 Moritz Zwerger + * Copyright (C) 2020-2025 Moritz Zwerger * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. * @@ -33,7 +33,7 @@ class ChunkNeighbours(val chunk: Chunk) : Iterable { val complete: Boolean get() = count == COUNT fun get(): Array? { - if (count == COUNT) { + if (count == COUNT) { // TODO: Race condition! return neighbours.unsafeCast() } return null diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/block/SectionOcclusion.kt b/src/main/java/de/bixilon/minosoft/data/world/container/block/SectionOcclusion.kt index fd0787116..ddb951d51 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/container/block/SectionOcclusion.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/container/block/SectionOcclusion.kt @@ -58,13 +58,14 @@ class SectionOcclusion( } } - private inline fun ShortArray.updateRegion(x: Int, y: Int, z: Int, id: Short): Boolean { + private inline fun ShortArray.setIfUnset(x: Int, y: Int, z: Int, id: Short): Boolean { val index = y shl 8 or (z shl 4) or x - if (this[index] > 0) { + if (this[index] != EMPTY_REGION) { return true } val state = provider[index] if (state.isFullyOpaque()) { + this[index] = INVALID_REGION return true } this[index] = id @@ -72,7 +73,7 @@ class SectionOcclusion( } private fun startTrace(regions: ShortArray, x: Int, y: Int, z: Int, nextId: Short) { - if (regions.updateRegion(x, y, z, nextId)) return + if (regions.setIfUnset(x, y, z, nextId)) return // no need to trace negative coordinates initially if (x < ProtocolDefinition.SECTION_MAX_X) trace(regions, x + 1, y, z, nextId) @@ -81,7 +82,7 @@ class SectionOcclusion( } private fun trace(regions: ShortArray, x: Int, y: Int, z: Int, nextId: Short) { - if (regions.updateRegion(x, y, z, nextId)) return + if (regions.setIfUnset(x, y, z, nextId)) return if (x > 0) trace(regions, x - 1, y, z, nextId) if (x < ProtocolDefinition.SECTION_MAX_X) trace(regions, x + 1, y, z, nextId) @@ -93,9 +94,9 @@ class SectionOcclusion( private fun floodFill(array: ShortArray): ShortArray { // mark regions and check direct neighbours - Arrays.fill(array, 0.toShort()) + Arrays.fill(array, EMPTY_REGION) - var next: Short = 0 + var next = EMPTY_REGION for (y in 0 until ProtocolDefinition.SECTION_HEIGHT_Y) { for (z in 0 until ProtocolDefinition.SECTION_WIDTH_Z) { for (x in 0 until ProtocolDefinition.SECTION_WIDTH_X) { @@ -124,7 +125,7 @@ class SectionOcclusion( Axes.Z -> Directions.NORTH } val nRegion = regions[indexPrefix].toInt() - if (nRegion > 0) { + if (nRegion > EMPTY_REGION) { sideRegions[nDirection.ordinal].add(nRegion) // primitive } @@ -203,6 +204,8 @@ class SectionOcclusion( } companion object { + private const val EMPTY_REGION = 0.toShort() + private const val INVALID_REGION = (-1).toShort() private val EMPTY = BooleanArray(CubeDirections.CUBE_DIRECTION_COMBINATIONS) private val ALLOCATOR = ShortAllocator()