parallel light always does this random noise

This commit is contained in:
minjaesong
2019-01-18 04:24:14 +09:00
parent 784a6a13e3
commit 68df2a223e
3 changed files with 77 additions and 85 deletions

View File

@@ -1,11 +1,6 @@
package net.torvald.terrarum.concurrent
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.lock
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.collections.ArrayList
typealias RunnableFun = () -> Unit
/** Int: index of the processing core */
@@ -174,9 +169,9 @@ object ParallelUtils {
return al
}
fun Iterable<*>.sliceEvenly(slices: Int): List<List<*>> = this.toList().sliceEvenly(slices)
fun <T> Iterable<T>.sliceEvenly(slices: Int): List<List<T>> = this.toList().sliceEvenly(slices)
fun List<*>.sliceEvenly(slices: Int): List<List<*>> {
fun <T> List<T>.sliceEvenly(slices: Int): List<List<T>> {
return (0 until slices).map {
this.subList(
this.size.toFloat().div(slices).times(it).roundInt(),
@@ -185,7 +180,7 @@ object ParallelUtils {
}
}
fun Array<*>.sliceEvenly(slices: Int): List<Array<*>> {
fun <T> Array<T>.sliceEvenly(slices: Int): List<Array<T>> {
return (0 until slices).map {
this.sliceArray(
this.size.toFloat().div(slices).times(it).roundInt() until

View File

@@ -492,7 +492,7 @@ open class Ingame(batch: SpriteBatch) : IngameInstance(batch) {
//renderGame(batch)
AppLoader.debugTimers["Ingame.render"] = measureNanoTime { renderGame() }
AppLoader.debugTimers["Ingame.render-Light"] =
(AppLoader.debugTimers["Ingame.render"] as Long) - ((AppLoader.debugTimers["Renderer.LightSequential"] as? Long) ?: 0)
(AppLoader.debugTimers["Ingame.render"] as Long) - ((AppLoader.debugTimers["Renderer.LightTotal"] as? Long) ?: 0)
}
protected fun updateGame(delta: Float) {

View File

@@ -17,6 +17,7 @@ import net.torvald.terrarum.gameactors.ActorWBMovable
import net.torvald.terrarum.gameactors.Luminous
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.IngameRenderer
import java.util.concurrent.atomic.AtomicReferenceArray
import kotlin.system.measureNanoTime
/**
@@ -51,6 +52,8 @@ object LightmapRenderer {
for (i in 0 until lightmap.size) {
lightmap[i] = colourNull
}
makeUpdateTaskList()
}
}
catch (e: UninitializedPropertyAccessException) {
@@ -278,102 +281,96 @@ object LightmapRenderer {
}
}
AppLoader.debugTimers["Renderer.LightSequential"] =
AppLoader.debugTimers["Renderer.LightTotal"] =
(AppLoader.debugTimers["Renderer.Light1"]!! as Long) +
(AppLoader.debugTimers["Renderer.Light2"]!! as Long) +
(AppLoader.debugTimers["Renderer.Light3"]!! as Long) +
(AppLoader.debugTimers["Renderer.Light4"]!! as Long) +
(AppLoader.debugTimers["Renderer.Light0"]!! as Long)
}
else {
AppLoader.debugTimers["Renderer.LightPre"] = measureNanoTime {
else if (world.worldIndex != -1) { // to avoid updating on the null world
val buf = AtomicReferenceArray<Color>(lightmap.size)
val bufferForPasses = arrayOf(
lightmap.copyOf(), lightmap.copyOf(), lightmap.copyOf(), lightmap.copyOf()
)
//val combiningBuffer = Array(lightmap.size) { colourNull }
AppLoader.debugTimers["Renderer.LightPrlPre"] = measureNanoTime {
// update the content of buf using maxBlend -- it's not meant for overwrite
// this is kind of inefficient...
val calcTask = ArrayList<ThreadedLightmapUpdateMessage>()
updateMessages.forEachIndexed { index, msg ->
ThreadParallel.map(index, "Light") {
// for the message slices...
msg.forEach { m ->
// update the content of buf using maxBlend -- it's not meant for overwrite
buf.getAndUpdate(m.y * LIGHTMAP_WIDTH + m.x) { oldCol ->
val ux = m.x + for_x_start - overscan_open
val uy = m.y + for_y_start - overscan_open
// Round 1 preload
for (y in for_y_start - overscan_open..for_y_end) {
for (x in for_x_start - overscan_open..for_x_end) {
calcTask.add(ThreadedLightmapUpdateMessage(x, y, 1))
}
}
// Round 2 preload
for (y in for_y_end + overscan_open downTo for_y_start) {
for (x in for_x_start - overscan_open..for_x_end) {
calcTask.add(ThreadedLightmapUpdateMessage(x, y, 2))
}
}
// Round 3 preload
for (y in for_y_end + overscan_open downTo for_y_start) {
for (x in for_x_end + overscan_open downTo for_x_start) {
calcTask.add(ThreadedLightmapUpdateMessage(x, y, 3))
}
}
// Round 4 preload
for (y in for_y_start - overscan_open..for_y_end) {
for (x in for_x_end + overscan_open downTo for_x_start) {
calcTask.add(ThreadedLightmapUpdateMessage(x, y, 4))
}
}
val calcTasks = calcTask.sliceEvenly(Terrarum.THREADS)
val combineTasks = (0 until lightmap.size).sliceEvenly(Terrarum.THREADS)
// couldn't help but do this nested timer
AppLoader.debugTimers["Renderer.LightParallel${Terrarum.THREADS}x"] = measureNanoTime {
calcTasks.forEachIndexed { index, list ->
ThreadParallel.map(index, "LightCalculate") { index -> // this index is that index
list.forEach {
val it = it as ThreadedLightmapUpdateMessage
setLightOf(bufferForPasses[it.pass - 1], it.x, it.y, calculate(it.x, it.y))
(oldCol ?: colourNull) maxBlend calculate(ux, uy)
}
}
}
ThreadParallel.startAllWaitForDie()
}
AppLoader.debugTimers["Runderer.LightPost"] = measureNanoTime {
combineTasks.forEachIndexed { index, intRange ->
ThreadParallel.map(index, "LightCombine") { index -> // this index is that index
for (i in intRange) {
val max1 = bufferForPasses[0][i] maxBlend bufferForPasses[1][i]
val max2 = bufferForPasses[2][i] maxBlend bufferForPasses[3][i]
val max = max1 maxBlend max2
lightmap[i] = max
}
}
}
ThreadParallel.startAllWaitForDie()
}
}
AppLoader.debugTimers["Renderer.LightPrlRun"] = measureNanoTime {
ThreadParallel.startAllWaitForDie()
}
// get correct Renderer.LightPre by subtracting some shits
AppLoader.debugTimers["Renderer.LightParaTotal"] = AppLoader.debugTimers["Renderer.LightPre"]!!
AppLoader.debugTimers["Renderer.LightPre"] =
(AppLoader.debugTimers["Renderer.LightPre"]!! as Long) -
(AppLoader.debugTimers["Renderer.LightParallel${Terrarum.THREADS}x"]!! as Long) -
(AppLoader.debugTimers["Runderer.LightPost"]!! as Long)
AppLoader.debugTimers["Renderer.LightPrlPost"] = measureNanoTime {
// copy to lightmap
for (k in 0 until lightmap.size) {
lightmap[k] = buf.getPlain(k) ?: colourNull
}
}
// accuracy may suffer (overheads maybe?) but it doesn't matter (i think...)
AppLoader.debugTimers["Renderer.LightTotal"] =
(AppLoader.debugTimers["Renderer.LightPrlPre"]!! as Long) +
(AppLoader.debugTimers["Renderer.LightPrlRun"]!! as Long) +
(AppLoader.debugTimers["Renderer.LightPrlPost"]!! as Long)
}
}
internal data class ThreadedLightmapUpdateMessage(val x: Int, val y: Int, val pass: Int)
// TODO re-init at every resize
private lateinit var updateMessages: List<Array<ThreadedLightmapUpdateMessage>>
private fun makeUpdateTaskList() {
val lightTaskArr = ArrayList<ThreadedLightmapUpdateMessage>()
val for_x_start = overscan_open
val for_y_start = overscan_open
val for_x_end = for_x_start + WorldCamera.width / TILE_SIZE + 3
val for_y_end = for_y_start + WorldCamera.height / TILE_SIZE + 3 // same fix as above
// Round 2
for (y in for_y_end + overscan_open downTo for_y_start) {
for (x in for_x_start - overscan_open..for_x_end) {
lightTaskArr.add(ThreadedLightmapUpdateMessage(x, y))
}
}
// Round 3
for (y in for_y_end + overscan_open downTo for_y_start) {
for (x in for_x_end + overscan_open downTo for_x_start) {
lightTaskArr.add(ThreadedLightmapUpdateMessage(x, y))
}
}
// Round 4
for (y in for_y_start - overscan_open..for_y_end) {
for (x in for_x_end + overscan_open downTo for_x_start) {
lightTaskArr.add(ThreadedLightmapUpdateMessage(x, y))
}
}
// Round 1
for (y in for_y_start - overscan_open..for_y_end) {
for (x in for_x_start - overscan_open..for_x_end) {
lightTaskArr.add(ThreadedLightmapUpdateMessage(x, y))
}
}
updateMessages = lightTaskArr.toTypedArray().sliceEvenly(Terrarum.THREADS)
}
internal data class ThreadedLightmapUpdateMessage(val x: Int, val y: Int)
private fun buildLanternmap() {