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
import kotlin.math.PI
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 var frame = 0
private var xpos = 0.0
......@@ -26,28 +28,29 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
private var inputText = ""
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
if (withFps) fpsCounter.tick()
canvas.translate(xOffset.toFloat(), yOffset.toFloat())
canvas.scale(scale.toFloat(), scale.toFloat())
canvas.rotate(rotate.toFloat(), (width / 2).toFloat(), (height / 2).toFloat())
val watchFill = Paint().apply { color = 0xFFFFFFFF.toInt() }
val watchStroke = Paint().apply {
color = 0xFF000000.toInt()
mode = PaintMode.STROKE
strokeWidth = 1f
color = 0xFF000000.toInt()
mode = PaintMode.STROKE
strokeWidth = 1f
}
val watchStrokeAA = Paint().apply {
color = 0xFF000000.toInt()
mode = PaintMode.STROKE
strokeWidth = 1f
color = 0xFF000000.toInt()
mode = PaintMode.STROKE
strokeWidth = 1f
}
val watchFillHover = Paint().apply { color = 0xFFE4FF01.toInt() }
for (x in 0 .. width - 50 step 50) {
for (y in 30 + platformYOffset.toInt() .. height - 50 step 50) {
val hover =
val hover =
(xpos - xOffset) / scale > x &&
(xpos - xOffset) / scale < x + 50 &&
(ypos - yOffset) / scale > y &&
(ypos - yOffset) / scale < y + 50
(xpos - xOffset) / scale < x + 50 &&
(ypos - yOffset) / scale > y &&
(ypos - yOffset) / scale < y + 50
val fill = if (hover) watchFillHover else watchFill
val stroke = if (x > width / 2) watchStrokeAA else watchStroke
canvas.drawOval(Rect.makeXYWH(x + 5f, y + 5f, 40f, 40f), fill)
......@@ -55,11 +58,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
var angle = 0f
while (angle < 2f * PI) {
canvas.drawLine(
(x + 25 - 17 * sin(angle)),
(y + 25 + 17 * cos(angle)),
(x + 25 - 20 * sin(angle)),
(y + 25 + 20 * cos(angle)),
stroke
(x + 25 - 17 * sin(angle)),
(y + 25 + 17 * cos(angle)),
(x + 25 - 20 * sin(angle)),
(y + 25 + 20 * cos(angle)),
stroke
)
angle += (2.0 * PI / 12.0).toFloat()
}
......@@ -69,25 +72,27 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
val angle1 = (time.toFloat() / 5000 * 2f * PI).toFloat()
canvas.drawLine(
x + 25f,
y + 25f,
x + 25f - 15f * sin(angle1),
y + 25f + 15 * cos(angle1),
stroke)
x + 25f,
y + 25f,
x + 25f - 15f * sin(angle1),
y + 25f + 15 * cos(angle1),
stroke)
val angle2 = (time / 60000 * 2f * PI).toFloat()
canvas.drawLine(
x + 25f,
y + 25f,
x + 25f - 10f * sin(angle2),
y + 25f + 10f * cos(angle2),
stroke)
x + 25f,
y + 25f,
x + 25f - 10f * sin(angle2),
y + 25f + 10f * cos(angle2),
stroke)
}
}
val maybeFps = if (withFps) " ${fpsCounter.average}FPS " else ""
val renderInfo = ParagraphBuilder(style, fontCollection)
.pushStyle(TextStyle().setColor(0xFF000000.toInt()))
.addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}")
.addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}${maybeFps}")
.popStyle()
.build()
renderInfo.layout(Float.POSITIVE_INFINITY)
......@@ -100,7 +105,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
.build()
input.layout(Float.POSITIVE_INFINITY)
input.paint(canvas, 5f, platformYOffset + 20f)
val frames = ParagraphBuilder(style, fontCollection)
.pushStyle(TextStyle().setColor(0xff9BC730L.toInt()).setFontSize(20f))
.addText("Frames: ${frame++}\nAngle: $rotate")
......
......@@ -9,9 +9,10 @@ import org.jetbrains.skiko.*
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.PI
import kotlin.math.pow
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 var frame = 0
private var xpos = 0.0
......@@ -27,6 +28,7 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
private var inputText = ""
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
if (withFps) fpsCounter.tick()
canvas.translate(xOffset.toFloat(), yOffset.toFloat())
canvas.scale(scale.toFloat(), scale.toFloat())
canvas.rotate(rotate.toFloat(), (width / 2).toFloat(), (height / 2).toFloat())
......@@ -86,9 +88,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
}
}
val maybeFps = if (withFps) " ${fpsCounter.average}FPS " else ""
val renderInfo = ParagraphBuilder(style, fontCollection)
.pushStyle(TextStyle().setColor(0xFF000000.toInt()))
.addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}")
.addText("Graphics API: ${layer.renderApi} ✿゚ ${currentSystemTheme}${maybeFps}")
.popStyle()
.build()
renderInfo.layout(Float.POSITIVE_INFINITY)
......
......@@ -3,8 +3,8 @@ package org.jetbrains.skiko
import kotlin.math.roundToInt
class FPSCounter(
private val periodSeconds: Double,
private val showLongFrames: Boolean,
private val periodSeconds: Double = 2.0,
private val showLongFrames: Boolean = false,
private val getLongFrameMillis: () -> Double = {
1.5 * 1000 / 60
}
......@@ -12,6 +12,9 @@ class FPSCounter(
private val times = mutableListOf<Long>()
private var lastLogTime = currentNanoTime()
private var lastTime = currentNanoTime()
private var _average = 0
private var _min = 0
private var _max = 0
fun tick() {
val time = currentNanoTime()
......@@ -25,16 +28,25 @@ class FPSCounter(
println("$timestamp Long frame ${frameTime.nanosToMillis()} ms")
}
if ((time - lastLogTime) > periodSeconds.secondsToNanos()) {
val average = (nanosPerSecond / times.average()).roundToInt()
val min = (nanosPerSecond / times.maxOrNull()!!).roundToInt()
val max = (nanosPerSecond / times.minOrNull()!!).roundToInt()
println("[$timestamp] FPS $average ($min-$max)")
if ((time - lastLogTime) > periodSeconds.secondsToNanos() && times.isNotEmpty()) {
_average = (nanosPerSecond / times.average()).roundToInt()
_min = (nanosPerSecond / times.maxOrNull()!!).roundToInt()
_max = (nanosPerSecond / times.minOrNull()!!).roundToInt()
times.clear()
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 nanosPerSecond = 1_000_000_000.0
private fun Long.nanosToMillis(): Double = this / nanosPerMillis
......
......@@ -145,7 +145,6 @@ internal class MetalLayer : CAMetalLayer {
this.backgroundColor =
CGColorCreate(CGColorSpaceCreateDeviceRGB(), it.addressOf(0))
}
this.displaySyncEnabled = false
skiaLayer.nsView.layer = this
skiaLayer.nsView.wantsLayer = true
this.contentsGravity = kCAGravityTopLeft;
......@@ -158,6 +157,5 @@ internal class MetalLayer : CAMetalLayer {
override fun drawInContext(ctx: CGContextRef?) {
skiaLayer.update(getTimeNanos())
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