diff --git a/src/main/java/de/bixilon/minosoft/config/config/game/OtherGameConfig.kt b/src/main/java/de/bixilon/minosoft/config/config/game/OtherGameConfig.kt index 5795da28c..e220df42c 100644 --- a/src/main/java/de/bixilon/minosoft/config/config/game/OtherGameConfig.kt +++ b/src/main/java/de/bixilon/minosoft/config/config/game/OtherGameConfig.kt @@ -19,6 +19,6 @@ data class OtherGameConfig( @Json(name = "anti_moire_pattern") var antiMoirePattern: Boolean = true, @Json(name = "flower_random_offset") var flowerRandomOffset: Boolean = true, @Json(name = "block_outline") var blockOutline: BlockOutline = BlockOutline(), - @Json(name = "magic_fps") var magicFPS: Boolean = false, + @Json(name = "experimental_fps") var experimentalFPS: Boolean = false, @Json(name = "super_dumb_advanced_setting_leave_at_1") var swapInterval: Int = 1, ) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderStats.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderStats.kt deleted file mode 100644 index f0d56418c..000000000 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderStats.kt +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Minosoft - * Copyright (C) 2020 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. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If not, see . - * - * This software is not affiliated with Mojang AB, the original developer of Minecraft. - */ - -package de.bixilon.minosoft.gui.rendering - -import de.bixilon.minosoft.Minosoft -import de.bixilon.minosoft.util.SystemInformation -import java.util.concurrent.ThreadLocalRandom - -class RenderStats { - var fpsLastSecond = -1 - private set - var minFrameTime = Long.MAX_VALUE - private set - var maxFrameTime = 0L - private set - var avgFrameTime = 0L - private set - var frames = 0L - private set - - private var lastFPSCalcTime = 0L - private var framesLastSecond = 0 - private var frameTime = 0L - - private var frameStartTime = 0L - - fun startFrame() { - frameStartTime = System.nanoTime() - } - - fun endDraw() { - } - - fun endFrame() { - val frameEndTime = System.nanoTime() - val frameTime = frameEndTime - frameStartTime - if (frameTime < minFrameTime) { - minFrameTime = frameTime - } - if (frameTime > maxFrameTime) { - maxFrameTime = frameTime - } - - if (frameEndTime - lastFPSCalcTime > 1E9) { - // 1 second - fpsLastSecond = if (Minosoft.config.config.game.other.magicFPS) { - ThreadLocalRandom.current().nextInt(MAGIC_FPS - 10, MAGIC_FPS) - } else { - framesLastSecond - } - - framesLastSecond = 0 - lastFPSCalcTime = frameEndTime - this.frameTime = 0 - } - frames++ - framesLastSecond++ - - this.frameTime += frameTime - this.avgFrameTime = this.frameTime / framesLastSecond - } - - - companion object { - private var MAGIC_FPS = ThreadLocalRandom.current().nextLong(SystemInformation.PROCESSOR_SPEED / 10000000 - 100, SystemInformation.PROCESSOR_SPEED / 10000000 + 100).toInt() - } -} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt index 4aaa13d8f..314022b7a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderWindow.kt @@ -22,6 +22,7 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.TextureLike import de.bixilon.minosoft.gui.rendering.gui.hud.atlas.TextureLikeTexture import de.bixilon.minosoft.gui.rendering.input.key.RenderWindowInputHandler import de.bixilon.minosoft.gui.rendering.modding.events.* +import de.bixilon.minosoft.gui.rendering.stats.AbstractRenderStats import de.bixilon.minosoft.gui.rendering.system.base.IntegratedBufferTypes import de.bixilon.minosoft.gui.rendering.system.base.PolygonModes import de.bixilon.minosoft.gui.rendering.system.base.RenderSystem @@ -37,6 +38,7 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.CountUpAndDownLatch import de.bixilon.minosoft.util.KUtil.decide import de.bixilon.minosoft.util.KUtil.synchronizedMapOf +import de.bixilon.minosoft.util.MMath.round10 import de.bixilon.minosoft.util.Queue import de.bixilon.minosoft.util.Stopwatch import de.bixilon.minosoft.util.logging.Log @@ -53,7 +55,7 @@ class RenderWindow( var initialized = false private set private lateinit var renderThread: Thread - val renderStats = RenderStats() + val renderStats: AbstractRenderStats = AbstractRenderStats.createInstance() val inputHandler = RenderWindowInputHandler(this) @@ -293,7 +295,7 @@ class RenderWindow( renderStats.endFrame() if (RenderConstants.SHOW_FPS_IN_WINDOW_TITLE) { - window.title = "Minosoft | FPS: ${renderStats.fpsLastSecond}" + window.title = "Minosoft | FPS: ${renderStats.smoothAvgFPS.round10}" } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/stats/AbstractRenderStats.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/stats/AbstractRenderStats.kt new file mode 100644 index 000000000..de75210e8 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/stats/AbstractRenderStats.kt @@ -0,0 +1,42 @@ +/* + * Minosoft + * Copyright (C) 2021 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.stats + +import de.bixilon.minosoft.Minosoft +import de.bixilon.minosoft.util.avg.Average + +interface AbstractRenderStats { + val avgFrameTime: Average + val smoothAvgFPS: Double + + val avgFPS: Double + val totalFrames: Long + + + fun startFrame() {} + fun endDraw() {} + fun endFrame() {} + + + companion object { + + fun createInstance(): AbstractRenderStats { + if (Minosoft.config.config.game.other.experimentalFPS) { + return ExperimentalRenderStats() + } + + return RenderStats() + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/stats/ExperimentalRenderStats.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/stats/ExperimentalRenderStats.kt new file mode 100644 index 000000000..0d7eab620 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/stats/ExperimentalRenderStats.kt @@ -0,0 +1,76 @@ +/* + * Minosoft + * Copyright (C) 2021 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.stats + +import de.bixilon.minosoft.util.KUtil.nextFloat +import de.bixilon.minosoft.util.avg.Average +import de.bixilon.minosoft.util.avg.LongAverage +import glm_.func.common.clamp +import kotlin.random.Random + +class ExperimentalRenderStats : AbstractRenderStats { + private val renderStats = RenderStats() + + private val baseMultiplier = Random.nextFloat(1.0f, 1.5f) + private val baseJitter = Random.nextInt(0, 20) + + override val avgFrameTime: Average = LongAverage(Long.MAX_VALUE) + + private var lastSmoothFPSCalculationTime = 0L + override var smoothAvgFPS: Double = 0.0 + get() { + val time = System.currentTimeMillis() + if (time - lastSmoothFPSCalculationTime > 100) { + field = avgFPS + lastSmoothFPSCalculationTime = time + } + return field + } + private set + + override val avgFPS: Double + get() { + val avgFPS = renderStats.avgFPS + + val multiplier = 3.0f * baseMultiplier * Random.nextFloat(0.9f, 1.1f) + + var fps = avgFPS * multiplier + + fps += baseJitter + + fps += Random.nextInt(-10, 10) + + return fps.clamp(0.0, 10000.0) + } + + + init { + avgFrameTime.add(5000000L) // ToDo: Add real stats + } + + override val totalFrames: Long + get() = renderStats.totalFrames + + override fun startFrame() { + renderStats.startFrame() + } + + override fun endDraw() { + renderStats.endDraw() + } + + override fun endFrame() { + renderStats.endFrame() + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/stats/RenderStats.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/stats/RenderStats.kt new file mode 100644 index 000000000..6ea672e69 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/stats/RenderStats.kt @@ -0,0 +1,60 @@ +/* + * Minosoft + * Copyright (C) 2021 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.stats + +import de.bixilon.minosoft.util.avg.LongAverage + +class RenderStats : AbstractRenderStats { + override val avgFrameTime: LongAverage = LongAverage(1L * 1000000000L) // 1 second * SECOND_SCALE + override var totalFrames: Long = 0L + private set + + private var lastFrameStartTime = -1L + + private var lastSmoothFPSCalculationTime = 0L + + override var smoothAvgFPS: Double = 0.0 + get() { + val time = System.currentTimeMillis() + if (time - lastSmoothFPSCalculationTime > 100) { + field = avgFPS + lastSmoothFPSCalculationTime = time + } + return field + } + private set + + override val avgFPS: Double + get() { + val avgFrameTime = avgFrameTime.avg + + return 1000000000L / avgFrameTime.toDouble() // SECOND_SCALE + } + + + override fun startFrame() { + lastFrameStartTime = System.nanoTime() + } + + override fun endFrame() { + val time = System.nanoTime() + + val delta = time - lastFrameStartTime + + avgFrameTime += delta + + + totalFrames++ + } +} diff --git a/src/main/java/de/bixilon/minosoft/util/MMath.kt b/src/main/java/de/bixilon/minosoft/util/MMath.kt index 2fdc53e0a..9953af041 100644 --- a/src/main/java/de/bixilon/minosoft/util/MMath.kt +++ b/src/main/java/de/bixilon/minosoft/util/MMath.kt @@ -76,6 +76,8 @@ object MMath { val Float.round10: Float get() = (this * 10).toInt().toFloat() / 10f + val Double.round10: Double get() = (this * 10).toInt().toDouble() / 10.0 + fun round10Up(value: Float): Int { val intValue = value.toInt() val rest = value / intValue diff --git a/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt b/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt index c7762d42d..edf3d1d45 100644 --- a/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt +++ b/src/main/java/de/bixilon/minosoft/util/SystemInformation.kt @@ -16,6 +16,7 @@ package de.bixilon.minosoft.util import de.bixilon.minosoft.util.UnitFormatter.formatBytes import oshi.SystemInfo +@Deprecated(message = "Will be refactored") object SystemInformation { val RUNTIME = Runtime.getRuntime() val SYSTEM_INFO = SystemInfo() diff --git a/src/main/java/de/bixilon/minosoft/util/avg/Average.kt b/src/main/java/de/bixilon/minosoft/util/avg/Average.kt new file mode 100644 index 000000000..1dd7c02f7 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/avg/Average.kt @@ -0,0 +1,28 @@ +/* + * Minosoft + * Copyright (C) 2021 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.util.avg + +interface Average { + val nanos: Long + + val avg: T + + fun cleanup() + + fun add(value: T) + + operator fun plusAssign(value: T) { + add(value) + } +} diff --git a/src/main/java/de/bixilon/minosoft/util/avg/LongAverage.kt b/src/main/java/de/bixilon/minosoft/util/avg/LongAverage.kt new file mode 100644 index 000000000..bf082a348 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/avg/LongAverage.kt @@ -0,0 +1,69 @@ +/* + * Minosoft + * Copyright (C) 2021 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.util.avg + +import de.bixilon.minosoft.util.KUtil.synchronizedListOf +import de.bixilon.minosoft.util.KUtil.toSynchronizedList + +class LongAverage(override val nanos: Long) : Average { + /** + * List of + */ + private val data: MutableList> = synchronizedListOf() + private var updated = false + private var lastAVG = 0L + + override val avg: Long + @Synchronized get() { + if (!updated) { + return lastAVG + } + cleanup() + val data = data.toSynchronizedList() + + var total = 0L + for ((_, value) in data) { + total += value + } + + lastAVG = total / data.size + updated = false + return lastAVG + } + + override fun cleanup() { + val time = System.nanoTime() + + var indexOffset = 0 + for ((index, pair) in data.toSynchronizedList().withIndex()) { + val (addTime, _) = pair + val addDelta = time - addTime + if (addDelta - nanos >= 0L) { + // remove + data.removeAt(index - indexOffset) + indexOffset++ + updated = true + } else { + break + } + } + } + + override fun add(value: Long) { + cleanup() + val time = System.nanoTime() + data += Pair(time, value) + updated = true + } +}