Skip to content

Commit

Permalink
SceneryContext: Fix flickering issue when BVV LUTs update
Browse files Browse the repository at this point in the history
* fixes an issue where the volume rendering would flicker whenever the BVV LUT
  was updated, which is quite annoying
* this fix double-buffers the LUT and waits for it to become available on the GPU
  before replacing the old one, fixing the flickering issue
  • Loading branch information
skalarproduktraum committed May 15, 2024
1 parent 5011bd3 commit 78ad6b8
Showing 1 changed file with 64 additions and 30 deletions.
94 changes: 64 additions & 30 deletions src/main/kotlin/graphics/scenery/volumes/SceneryContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.util.concurrent.ConcurrentHashMap
import kotlin.concurrent.thread
import kotlin.time.ExperimentalTime

/**
Expand Down Expand Up @@ -541,33 +542,81 @@ open class SceneryContext(val node: VolumeManager, val useCompute: Boolean = fal

if(texture != null && name != null) {
val material = node.material()
val gt = material.textures[name] as? UpdatableTexture ?: throw IllegalStateException("Texture for $name is null or not updateable")
var gt = material.textures[name] as? UpdatableTexture ?: throw IllegalStateException("Texture for $name is null or not updateable")

logger.debug("Running ${updates.size} texture updates for $texture")
logger.debug("Running {} texture updates for {}", updates.size, texture)
updates.forEach { update ->
if (texture.reallocate) {
val newDimensions = Vector3i(update.width, update.height, update.depth)
val dimensionsChanged = Vector3i(newDimensions).sub(gt.dimensions).length() > 0.0001f

if(dimensionsChanged) {
logger.debug("Reallocating for size change ${gt.dimensions} -> $newDimensions")
logger.warn("*** SIZE CHANGE FOR $name ***")
logger.debug("Reallocating for size change {} -> {}", gt.dimensions, newDimensions)

gt.clearUpdates()
gt.dimensions = newDimensions
gt.contents = null
val nt = UpdatableTexture(
newDimensions,
gt.channels,
gt.type,
null,
gt.repeatUVW,
gt.borderColor,
gt.normalized,
gt.mipmap,
gt.minFilter,
gt.maxFilter,
gt.usageType
)
nt.clearUpdates()
nt.usageType += Texture.UsageType.AsyncLoad

if (t is LookupTextureARGB) {
gt.normalized = false
nt.normalized = false
}

material.textures[name] = gt
// material.textures["$name"] = gt
val timestampedName = "$name-${System.nanoTime()}"
material.textures[timestampedName] = nt

val textureUpdate = TextureUpdate(
TextureExtents(
update.xoffset,
update.yoffset,
update.zoffset,
update.width,
update.height,
update.depth
),
update.contents, deallocate = update.deallocate
)
nt.addUpdate(textureUpdate)
texture.reallocate = false

thread {
while(!nt.availableOnGPU() && nt.hasConsumableUpdates()) {
Thread.sleep(1)
}

material.textures[name] = nt
material.textures.remove(timestampedName)
}
} else {
val textureUpdate = TextureUpdate(
TextureExtents(
update.xoffset,
update.yoffset,
update.zoffset,
update.width,
update.height,
update.depth
),
update.contents, deallocate = update.deallocate
)
gt.addUpdate(textureUpdate)

texture.reallocate = false
}

val textureUpdate = TextureUpdate(
TextureExtents(update.xoffset, update.yoffset, update.zoffset, update.width, update.height, update.depth),
update.contents, deallocate = update.deallocate)
gt.addUpdate(textureUpdate)

texture.reallocate = false
} else {
val textureUpdate = TextureUpdate(
TextureExtents(update.xoffset, update.yoffset, update.zoffset, update.width, update.height, update.depth),
Expand Down Expand Up @@ -628,30 +677,15 @@ open class SceneryContext(val node: VolumeManager, val useCompute: Boolean = fal
return
}

// val (params, duration) = measureTimedValue {
// UpdateParameters(xoffset, yoffset, zoffset, width, height, depth, XXHash.XXH3_64bits(pixels))
// }

// if (lastUpdates[texture] == params) {
// logger.debug("Updates already seen, skipping")
// return
// }

logger.debug("Updating 3D texture via Texture3D, hash took from {}: dx={} dy={} dz={} w={} h={} d={}",
texture,
xoffset, yoffset, zoffset,
width, height, depth
)

val p = pixels.duplicate().order(ByteOrder.LITTLE_ENDIAN)
// val allocationSize = width * height * depth * texture.texInternalFormat().bytesPerElement
// val tmp = //MemoryUtil.memAlloc(allocationSize)
// p.limit(p.position() + allocationSize)
// MemoryUtil.memCopy(p, tmp)

// lastUpdates[texture] = params
val update = SubImageUpdate(xoffset, yoffset, zoffset, width, height, depth, p)
cachedUpdates.getOrPut(texture, { ArrayList(10) }).add(update)
cachedUpdates.getOrPut(texture) { ArrayList(10) }.add(update)
}

fun clearLUTs() {
Expand Down

0 comments on commit 78ad6b8

Please sign in to comment.