From 93ac1011e9fb9875859451f6418b4e7dfb08664b Mon Sep 17 00:00:00 2001 From: minjaesong Date: Thu, 6 Oct 2022 21:07:16 +0900 Subject: [PATCH] optimisation attempt --- .../torvald/gdx/graphics/UnsafeCvecArray.kt | 80 +++++----- src/net/torvald/terrarum/DefaultConfig.kt | 2 +- .../terrarum/worlddrawer/LightmapRenderer.kt | 141 ++++++++---------- 3 files changed, 111 insertions(+), 112 deletions(-) diff --git a/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt b/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt index 4664bc137..b61b3a6ed 100644 --- a/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt +++ b/src/net/torvald/gdx/graphics/UnsafeCvecArray.kt @@ -29,34 +29,43 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { fun getG(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 1) fun getB(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 2) fun getA(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 3) - inline fun getVec(x: Int, y: Int) = Cvec( - array.getFloat(toAddr(x, y)), - array.getFloat(toAddr(x, y) + 1), - array.getFloat(toAddr(x, y) + 2), - array.getFloat(toAddr(x, y) + 3) - ) + /** + * Returns a copy of the vector. Use [setVec] to modify the value in the CvecArray + */ + fun getVec(x: Int, y: Int): Cvec { + val a = toAddr(x, y) + return Cvec( + array.getFloat(a + 0), + array.getFloat(a + 1), + array.getFloat(a + 2), + array.getFloat(a + 3) + ) + } /** * @param channel 0 for R, 1 for G, 2 for B, 3 for A */ - fun channelGet(x: Int, y: Int, channel: Int) = array.getFloat(toAddr(x, y) + channel) +// fun channelGet(x: Int, y: Int, channel: Int) = array.getFloat(toAddr(x, y) + channel) // setters fun zerofill() = array.fillWith(0) - fun setR(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y), value) } - fun setG(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 1, value) } - fun setB(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 2, value) } - fun setA(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 3, value) } - inline fun setVec(x: Int, y: Int, value: Cvec) { - array.setFloat(toAddr(x, y), value.r) - array.setFloat(toAddr(x, y) + 1, value.g) - array.setFloat(toAddr(x, y) + 2, value.b) - array.setFloat(toAddr(x, y) + 3, value.a) + // fun setR(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y), value) } +// fun setG(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 1, value) } +// fun setB(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 2, value) } +// fun setA(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 3, value) } + fun setVec(x: Int, y: Int, value: Cvec) { + val a = toAddr(x, y) + array.setFloat(a + 0, value.r) + array.setFloat(a + 1, value.g) + array.setFloat(a + 2, value.b) + array.setFloat(a + 3, value.a) } - inline fun setScalar(x: Int, y: Int, value: Float) { - array.setFloat(toAddr(x, y), value) - array.setFloat(toAddr(x, y) + 1, value) - array.setFloat(toAddr(x, y) + 2, value) - array.setFloat(toAddr(x, y) + 3, value) + fun setScalar(x: Int, y: Int, value: Float) { + val a = toAddr(x, y) + + array.setFloat(a + 0, value) + array.setFloat(a + 1, value) + array.setFloat(a + 2, value) + array.setFloat(a + 3, value) } /** * @param channel 0 for R, 1 for G, 2 for B, 3 for A @@ -66,24 +75,27 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) { } // operators - inline fun max(x: Int, y: Int, other: Cvec) { - setR(x, y, maxOf(getR(x, y), other.r)) - setG(x, y, maxOf(getG(x, y), other.g)) - setB(x, y, maxOf(getB(x, y), other.b)) - setA(x, y, maxOf(getA(x, y), other.a)) + fun max(x: Int, y: Int, other: Cvec) { + val a = toAddr(x, y) + array.setFloat(a + 0, maxOf(array.getFloat(a + 0), other.r)) + array.setFloat(a + 1, maxOf(array.getFloat(a + 1), other.g)) + array.setFloat(a + 2, maxOf(array.getFloat(a + 2), other.b)) + array.setFloat(a + 3, maxOf(array.getFloat(a + 3), other.a)) } - inline fun mul(x: Int, y: Int, scalar: Float) { - setR(x, y, getR(x, y) * scalar) - setG(x, y, getG(x, y) * scalar) - setB(x, y, getB(x, y) * scalar) - setA(x, y, getA(x, y) * scalar) + fun mul(x: Int, y: Int, scalar: Float) { + val a = toAddr(x, y) + array.setFloat(a + 0, (array.getFloat(a + 0) * scalar)) + array.setFloat(a + 1, (array.getFloat(a + 1) * scalar)) + array.setFloat(a + 2, (array.getFloat(a + 2) * scalar)) + array.setFloat(a + 3, (array.getFloat(a + 3) * scalar)) } fun mulAndAssign(x: Int, y: Int, scalar: Float) { val addr = toAddr(x, y) - for (k in 0..3) { - array.setFloat(addr + k, (array.getFloat(addr + k) * scalar)) - } + array.setFloat(addr + 0, (array.getFloat(addr + 0) * scalar)) + array.setFloat(addr + 1, (array.getFloat(addr + 1) * scalar)) + array.setFloat(addr + 2, (array.getFloat(addr + 2) * scalar)) + array.setFloat(addr + 3, (array.getFloat(addr + 3) * scalar)) } fun forAllMulAssign(scalar: Float) { diff --git a/src/net/torvald/terrarum/DefaultConfig.kt b/src/net/torvald/terrarum/DefaultConfig.kt index f8f28a5fa..00b2ad739 100644 --- a/src/net/torvald/terrarum/DefaultConfig.kt +++ b/src/net/torvald/terrarum/DefaultConfig.kt @@ -110,7 +110,7 @@ object DefaultConfig { "screenmagnifying" to 1.0, - "fx_newlight" to true, + "fx_newlight" to false, diff --git a/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt b/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt index 25471b61d..faa236685 100644 --- a/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt +++ b/src/net/torvald/terrarum/worlddrawer/LightmapRenderer.kt @@ -73,7 +73,7 @@ object LightmapRenderer { private val lanternMap = HashMap((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4) private val shadowMap = HashMap((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4) - private val giMap = HashMap((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4) +// private val giMap = HashMap((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4) /** * Float value, 1.0 for 1023 * @@ -119,8 +119,7 @@ object LightmapRenderer { * @param y world tile coord */ internal fun getLight(x: Int, y: Int): Cvec? { - var y = y - var x = if (for_x_start - overscan_open + LIGHTMAP_WIDTH >= world.width && x - for_x_start + overscan_open < 0) + val x = if (for_x_start - overscan_open + LIGHTMAP_WIDTH >= world.width && x - for_x_start + overscan_open < 0) x + world.width else if (for_x_start - overscan_open + LIGHTMAP_WIDTH < 0 && x - for_x_start + overscan_open >= world.width) x - world.width else x @@ -129,15 +128,7 @@ object LightmapRenderer { null } else { - x = x.convX() - y = y.convY() - - Cvec( - lightmap.getR(x, y), - lightmap.getG(x, y), - lightmap.getB(x, y), - lightmap.getA(x, y) - ) + lightmap.getVec(x.convX(), y.convY()) } } @@ -201,9 +192,8 @@ object LightmapRenderer { // when disabled, light will "decay out" instead of "instantly out", which can have a cool effect // but the performance boost is measly 0.1 ms on 6700K - giMap.clear() - - _mapLightLevelThis.zerofill() +// giMap.clear() +// _mapLightLevelThis.zerofill() for (y in for_y_start - overscan_open..for_y_end + overscan_open) { for (x in for_x_start - overscan_open..for_x_end + overscan_open) { @@ -328,9 +318,9 @@ object LightmapRenderer { // - If you naively slice the screen (job area) to multithread, the seam will appear. r1(lightmap);r2(lightmap); - if (!App.getConfigBoolean("fx_newlight")) { +// if (!App.getConfigBoolean("fx_newlight")) { r3(lightmap);r4(lightmap) - } +// } } App.measureDebugTime("Renderer.Precalculate2") { @@ -344,9 +334,9 @@ object LightmapRenderer { App.measureDebugTime("Renderer.LightRuns2") { r1(lightmap);r2(lightmap); - if (!App.getConfigBoolean("fx_newlight")) { +// if (!App.getConfigBoolean("fx_newlight")) { r3(lightmap);r4(lightmap) // two looks better than one - } +// } // no rendering trickery will eliminate the need of 2nd pass, even the "decay out" } } @@ -462,6 +452,7 @@ object LightmapRenderer { // } + _thisTerrain = world.getTileFromTerrainRaw(worldX, worldY) _thisTerrainProp = BlockCodex[world.tileNumberToNameMap[_thisTerrain.toLong()]] _thisWall = world.getTileFromWallRaw(worldX, worldY) @@ -508,11 +499,7 @@ object LightmapRenderer { // blend shade _mapThisTileOpacity.max(lx, ly, shadowMap[LandUtil.getBlockAddr(world, worldX, worldY)] ?: colourNull) - - _mapThisTileOpacity2.setR(lx, ly, _mapThisTileOpacity.getR(lx, ly) * 1.41421356f) - _mapThisTileOpacity2.setG(lx, ly, _mapThisTileOpacity.getG(lx, ly) * 1.41421356f) - _mapThisTileOpacity2.setB(lx, ly, _mapThisTileOpacity.getB(lx, ly) * 1.41421356f) - _mapThisTileOpacity2.setA(lx, ly, _mapThisTileOpacity.getA(lx, ly) * 1.41421356f) + _mapThisTileOpacity2.setVec(lx, ly, _mapThisTileOpacity.getVec(lx, ly).mul(1.41421356f)) // open air || luminous tile backed by sunlight @@ -520,6 +507,9 @@ object LightmapRenderer { (_thisTileLuminosity.nonZero() && !_thisWallProp.isSolid)) { _mapLightLevelThis.setVec(lx, ly, sunLight) } + else { + _mapLightLevelThis.setScalar(lx, ly, 0f) + } // blend lantern _mapLightLevelThis.max(lx, ly, _thisTileLuminosity.maxAndAssign( @@ -562,23 +552,15 @@ object LightmapRenderer { private fun _swipeTask(x: Int, y: Int, x2: Int, y2: Int, lightmap: UnsafeCvecArray, distFromLightSrc: Ivec4) { if (x2 < 0 || y2 < 0 || x2 >= LIGHTMAP_WIDTH || y2 >= LIGHTMAP_HEIGHT) return - _ambientAccumulator.r = _mapLightLevelThis.getR(x, y) - _ambientAccumulator.g = _mapLightLevelThis.getG(x, y) - _ambientAccumulator.b = _mapLightLevelThis.getB(x, y) - _ambientAccumulator.a = _mapLightLevelThis.getA(x, y) + _ambientAccumulator.set(_mapLightLevelThis.getVec(x, y)) + if (!swipeDiag) { - _thisTileOpacity.r = _mapThisTileOpacity.getR(x, y) - _thisTileOpacity.g = _mapThisTileOpacity.getG(x, y) - _thisTileOpacity.b = _mapThisTileOpacity.getB(x, y) - _thisTileOpacity.a = _mapThisTileOpacity.getA(x, y) + _thisTileOpacity.set(_mapThisTileOpacity.getVec(x, y)) _ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity, lightmap, distFromLightSrc)) } else { - _thisTileOpacity2.r = _mapThisTileOpacity2.getR(x, y) - _thisTileOpacity2.g = _mapThisTileOpacity2.getG(x, y) - _thisTileOpacity2.b = _mapThisTileOpacity2.getB(x, y) - _thisTileOpacity2.a = _mapThisTileOpacity2.getA(x, y) + _thisTileOpacity2.set(_mapThisTileOpacity2.getVec(x, y)) _ambientAccumulator.maxAndAssign(darkenColoured(x2, y2, _thisTileOpacity2, lightmap, distFromLightSrc)) } @@ -587,7 +569,7 @@ object LightmapRenderer { } private fun swipeLight(sx: Int, sy: Int, ex: Int, ey: Int, dx: Int, dy: Int, lightmap: UnsafeCvecArray) { swipeX = sx; swipeY = sy - if (App.getConfigBoolean("fx_newlight")) distFromLightSrc.broadcast(0) +// if (App.getConfigBoolean("fx_newlight")) distFromLightSrc.broadcast(0) while (swipeX*dx <= ex*dx && swipeY*dy <= ey*dy) { // conduct the task #1 // spread towards the end @@ -597,18 +579,18 @@ object LightmapRenderer { swipeX += dx swipeY += dy - if (App.getConfigBoolean("fx_newlight")) { - distFromLightSrc.add(1) - - if (_mapLightLevelThis.getR(swipeX - dx, swipeY - dy) <= _mapLightLevelThis.getR(swipeX, swipeY)) distFromLightSrc.r = 0 - if (_mapLightLevelThis.getG(swipeX - dx, swipeY - dy) <= _mapLightLevelThis.getG(swipeX, swipeY)) distFromLightSrc.g = 0 - if (_mapLightLevelThis.getB(swipeX - dx, swipeY - dy) <= _mapLightLevelThis.getB(swipeX, swipeY)) distFromLightSrc.b = 0 - if (_mapLightLevelThis.getA(swipeX - dx, swipeY - dy) <= _mapLightLevelThis.getA(swipeX, swipeY)) distFromLightSrc.a = 0 - } +// if (App.getConfigBoolean("fx_newlight")) { +// distFromLightSrc.add(1) +// +// if (_mapLightLevelThis.getR(swipeX - dx, swipeY - dy) <= _mapLightLevelThis.getR(swipeX, swipeY)) distFromLightSrc.r = 0 +// if (_mapLightLevelThis.getG(swipeX - dx, swipeY - dy) <= _mapLightLevelThis.getG(swipeX, swipeY)) distFromLightSrc.g = 0 +// if (_mapLightLevelThis.getB(swipeX - dx, swipeY - dy) <= _mapLightLevelThis.getB(swipeX, swipeY)) distFromLightSrc.b = 0 +// if (_mapLightLevelThis.getA(swipeX - dx, swipeY - dy) <= _mapLightLevelThis.getA(swipeX, swipeY)) distFromLightSrc.a = 0 +// } } swipeX = ex; swipeY = ey - if (App.getConfigBoolean("fx_newlight")) distFromLightSrc.broadcast(0) +// if (App.getConfigBoolean("fx_newlight")) distFromLightSrc.broadcast(0) while (swipeX*dx >= sx*dx && swipeY*dy >= sy*dy) { // conduct the task #2 // spread towards the start @@ -617,14 +599,14 @@ object LightmapRenderer { swipeX -= dx swipeY -= dy - if (App.getConfigBoolean("fx_newlight")) { - distFromLightSrc.add(1) - - if (_mapLightLevelThis.getR(swipeX + dx, swipeY + dy) <= _mapLightLevelThis.getR(swipeX, swipeY)) distFromLightSrc.r = 0 - if (_mapLightLevelThis.getG(swipeX + dx, swipeY + dy) <= _mapLightLevelThis.getG(swipeX, swipeY)) distFromLightSrc.g = 0 - if (_mapLightLevelThis.getB(swipeX + dx, swipeY + dy) <= _mapLightLevelThis.getB(swipeX, swipeY)) distFromLightSrc.b = 0 - if (_mapLightLevelThis.getA(swipeX + dx, swipeY + dy) <= _mapLightLevelThis.getA(swipeX, swipeY)) distFromLightSrc.a = 0 - } +// if (App.getConfigBoolean("fx_newlight")) { +// distFromLightSrc.add(1) +// +// if (_mapLightLevelThis.getR(swipeX + dx, swipeY + dy) <= _mapLightLevelThis.getR(swipeX, swipeY)) distFromLightSrc.r = 0 +// if (_mapLightLevelThis.getG(swipeX + dx, swipeY + dy) <= _mapLightLevelThis.getG(swipeX, swipeY)) distFromLightSrc.g = 0 +// if (_mapLightLevelThis.getB(swipeX + dx, swipeY + dy) <= _mapLightLevelThis.getB(swipeX, swipeY)) distFromLightSrc.b = 0 +// if (_mapLightLevelThis.getA(swipeX + dx, swipeY + dy) <= _mapLightLevelThis.getA(swipeX, swipeY)) distFromLightSrc.a = 0 +// } } } @@ -703,17 +685,14 @@ object LightmapRenderer { val arrayX = x.convX() val arrayY = y.convY() - val red = lightmap.getR(arrayX, arrayY) - val grn = lightmap.getG(arrayX, arrayY) - val blu = lightmap.getB(arrayX, arrayY) - val uvl = lightmap.getA(arrayX, arrayY) - val redw = (red.sqrt() - 1f) * (7f / 24f) - val grnw = (grn.sqrt() - 1f) - val bluw = (blu.sqrt() - 1f) * (7f / 72f) - val bluwv = (blu.sqrt() - 1f) * (1f / 50f) - val uvlwr = (uvl.sqrt() - 1f) * (1f / 13f) - val uvlwg = (uvl.sqrt() - 1f) * (1f / 10f) - val uvlwb = (uvl.sqrt() - 1f) * (1f / 8f) + val (red, grn, blu, uvl) = lightmap.getVec(arrayX, arrayY) +// val redw = (red.sqrt() - 1f) * (7f / 24f) +// val grnw = (grn.sqrt() - 1f) +// val bluw = (blu.sqrt() - 1f) * (7f / 72f) +// val bluwv = (blu.sqrt() - 1f) * (1f / 50f) +// val uvlwr = (uvl.sqrt() - 1f) * (1f / 13f) +// val uvlwg = (uvl.sqrt() - 1f) * (1f / 10f) +// val uvlwb = (uvl.sqrt() - 1f) * (1f / 8f) if (solidMultMagic == null) lightBuffer.drawPixel( @@ -722,13 +701,21 @@ object LightmapRenderer { 0 ) else - lightBuffer.drawPixel( + /*lightBuffer.drawPixel( x - this_x_start, lightBuffer.height - 1 - y + this_y_start, // flip Y (maxOf(red,grnw,bluw,uvlwr) * solidMultMagic).hdnorm().times(255f).roundToInt().shl(24) or (maxOf(redw,grn,bluw,uvlwg) * solidMultMagic).hdnorm().times(255f).roundToInt().shl(16) or (maxOf(redw,grnw,blu,uvlwb) * solidMultMagic).hdnorm().times(255f).roundToInt().shl(8) or (maxOf(bluwv,uvl) * solidMultMagic).hdnorm().times(255f).roundToInt() + )*/ + lightBuffer.drawPixel( + x - this_x_start, + lightBuffer.height - 1 - y + this_y_start, // flip Y + (red * solidMultMagic).hdnorm().times(255f).roundToInt().shl(24) or + (grn * solidMultMagic).hdnorm().times(255f).roundToInt().shl(16) or + (blu * solidMultMagic).hdnorm().times(255f).roundToInt().shl(8) or + (uvl * solidMultMagic).hdnorm().times(255f).roundToInt() ) } } @@ -800,20 +787,20 @@ object LightmapRenderer { if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return colourNull - if (App.getConfigBoolean("fx_newlight")) { - val newDarken: Cvec = darken.lanewise { it, ch -> - darkenConv(1f - it * lightScalingMagic) - } - - return lightmap.getVec(x, y).lanewise { it, ch -> - (it * ((newDarken.lane(ch) - distFromLightSrc.lane(ch)) / newDarken.lane(ch))).coerceAtLeast(0f) - } - } - else { +// if (App.getConfigBoolean("fx_newlight")) { +// val newDarken: Cvec = darken.lanewise { it, ch -> +// darkenConv(1f - it * lightScalingMagic) +// } +// +// return lightmap.getVec(x, y).lanewise { it, ch -> +// (it * ((newDarken.lane(ch) - distFromLightSrc.lane(ch)) / newDarken.lane(ch))).coerceAtLeast(0f) +// } +// } +// else { return lightmap.getVec(x, y).lanewise { it, ch -> it * (1f - darken.lane(ch) * lightScalingMagic) } - } +// } } /** infix is removed to clarify the association direction */