Unverified Commit 76bc8837 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

FPS counter in clocks (#495)

* FPS counter in clocks

* Restore vsync
parent 176415a1
...@@ -11,6 +11,8 @@ import kotlin.math.sin ...@@ -11,6 +11,8 @@ import kotlin.math.sin
import kotlin.math.PI import kotlin.math.PI
class Clocks(private val layer: SkiaLayer): SkikoView { class Clocks(private val layer: SkiaLayer): SkikoView {
private val withFps = true
private val fpsCounter = FPSCounter()
private val platformYOffset = if (hostOs == OS.Ios) 50f else 5f private val platformYOffset = if (hostOs == OS.Ios) 50f else 5f
private var frame = 0 private var frame = 0
private var xpos = 0.0 private var xpos = 0.0
...@@ -26,6 +28,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -26,6 +28,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
private var inputText = "" private var inputText = ""
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
if (withFps) fpsCounter.tick()
canvas.translate(xOffset.toFloat(), yOffset.toFloat()) canvas.translate(xOffset.toFloat(), yOffset.toFloat())
canvas.scale(scale.toFloat(), scale.toFloat()) canvas.scale(scale.toFloat(), scale.toFloat())
canvas.rotate(rotate.toFloat(), (width / 2).toFloat(), (height / 2).toFloat()) canvas.rotate(rotate.toFloat(), (width / 2).toFloat(), (height / 2).toFloat())
...@@ -85,9 +88,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -85,9 +88,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
} }
} }
val maybeFps = if (withFps) " ${fpsCounter.average}FPS " else ""
val renderInfo = ParagraphBuilder(style, fontCollection) val renderInfo = ParagraphBuilder(style, fontCollection)
.pushStyle(TextStyle().setColor(0xFF000000.toInt())) .pushStyle(TextStyle().setColor(0xFF000000.toInt()))
.addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}") .addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}${maybeFps}")
.popStyle() .popStyle()
.build() .build()
renderInfo.layout(Float.POSITIVE_INFINITY) renderInfo.layout(Float.POSITIVE_INFINITY)
......
...@@ -9,9 +9,10 @@ import org.jetbrains.skiko.* ...@@ -9,9 +9,10 @@ import org.jetbrains.skiko.*
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.pow
class Clocks(private val layer: SkiaLayer): SkikoView { class Clocks(private val layer: SkiaLayer): SkikoView {
private val withFps = true
private val fpsCounter = FPSCounter()
private val platformYOffset = if (hostOs == OS.Ios) 50f else 5f private val platformYOffset = if (hostOs == OS.Ios) 50f else 5f
private var frame = 0 private var frame = 0
private var xpos = 0.0 private var xpos = 0.0
...@@ -27,6 +28,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -27,6 +28,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
private var inputText = "" private var inputText = ""
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
if (withFps) fpsCounter.tick()
canvas.translate(xOffset.toFloat(), yOffset.toFloat()) canvas.translate(xOffset.toFloat(), yOffset.toFloat())
canvas.scale(scale.toFloat(), scale.toFloat()) canvas.scale(scale.toFloat(), scale.toFloat())
canvas.rotate(rotate.toFloat(), (width / 2).toFloat(), (height / 2).toFloat()) canvas.rotate(rotate.toFloat(), (width / 2).toFloat(), (height / 2).toFloat())
...@@ -86,9 +88,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -86,9 +88,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
} }
} }
val maybeFps = if (withFps) " ${fpsCounter.average}FPS " else ""
val renderInfo = ParagraphBuilder(style, fontCollection) val renderInfo = ParagraphBuilder(style, fontCollection)
.pushStyle(TextStyle().setColor(0xFF000000.toInt())) .pushStyle(TextStyle().setColor(0xFF000000.toInt()))
.addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}") .addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}${maybeFps}")
.popStyle() .popStyle()
.build() .build()
renderInfo.layout(Float.POSITIVE_INFINITY) renderInfo.layout(Float.POSITIVE_INFINITY)
......
...@@ -3,8 +3,8 @@ package org.jetbrains.skiko ...@@ -3,8 +3,8 @@ package org.jetbrains.skiko
import kotlin.math.roundToInt import kotlin.math.roundToInt
class FPSCounter( class FPSCounter(
private val periodSeconds: Double, private val periodSeconds: Double = 2.0,
private val showLongFrames: Boolean, private val showLongFrames: Boolean = false,
private val getLongFrameMillis: () -> Double = { private val getLongFrameMillis: () -> Double = {
1.5 * 1000 / 60 1.5 * 1000 / 60
} }
...@@ -12,6 +12,9 @@ class FPSCounter( ...@@ -12,6 +12,9 @@ class FPSCounter(
private val times = mutableListOf<Long>() private val times = mutableListOf<Long>()
private var lastLogTime = currentNanoTime() private var lastLogTime = currentNanoTime()
private var lastTime = currentNanoTime() private var lastTime = currentNanoTime()
private var _average = 0
private var _min = 0
private var _max = 0
fun tick() { fun tick() {
val time = currentNanoTime() val time = currentNanoTime()
...@@ -25,16 +28,25 @@ class FPSCounter( ...@@ -25,16 +28,25 @@ class FPSCounter(
println("$timestamp Long frame ${frameTime.nanosToMillis()} ms") println("$timestamp Long frame ${frameTime.nanosToMillis()} ms")
} }
if ((time - lastLogTime) > periodSeconds.secondsToNanos()) { if ((time - lastLogTime) > periodSeconds.secondsToNanos() && times.isNotEmpty()) {
val average = (nanosPerSecond / times.average()).roundToInt() _average = (nanosPerSecond / times.average()).roundToInt()
val min = (nanosPerSecond / times.maxOrNull()!!).roundToInt() _min = (nanosPerSecond / times.maxOrNull()!!).roundToInt()
val max = (nanosPerSecond / times.minOrNull()!!).roundToInt() _max = (nanosPerSecond / times.minOrNull()!!).roundToInt()
println("[$timestamp] FPS $average ($min-$max)")
times.clear() times.clear()
lastLogTime = time lastLogTime = time
} }
} }
val average: Int
get() = _average
val min: Int
get() = _min
val max: Int
get() = _max
private val nanosPerMillis = 1_000_000.0 private val nanosPerMillis = 1_000_000.0
private val nanosPerSecond = 1_000_000_000.0 private val nanosPerSecond = 1_000_000_000.0
private fun Long.nanosToMillis(): Double = this / nanosPerMillis private fun Long.nanosToMillis(): Double = this / nanosPerMillis
......
...@@ -145,7 +145,6 @@ internal class MetalLayer : CAMetalLayer { ...@@ -145,7 +145,6 @@ internal class MetalLayer : CAMetalLayer {
this.backgroundColor = this.backgroundColor =
CGColorCreate(CGColorSpaceCreateDeviceRGB(), it.addressOf(0)) CGColorCreate(CGColorSpaceCreateDeviceRGB(), it.addressOf(0))
} }
this.displaySyncEnabled = false
skiaLayer.nsView.layer = this skiaLayer.nsView.layer = this
skiaLayer.nsView.wantsLayer = true skiaLayer.nsView.wantsLayer = true
this.contentsGravity = kCAGravityTopLeft; this.contentsGravity = kCAGravityTopLeft;
...@@ -158,6 +157,5 @@ internal class MetalLayer : CAMetalLayer { ...@@ -158,6 +157,5 @@ internal class MetalLayer : CAMetalLayer {
override fun drawInContext(ctx: CGContextRef?) { override fun drawInContext(ctx: CGContextRef?) {
skiaLayer.update(getTimeNanos()) skiaLayer.update(getTimeNanos())
contextHandler.draw() contextHandler.draw()
super.drawInContext(ctx)
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment