Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Research performance issues on Desktop #3543

Open
mazunin-v-jb opened this issue Aug 21, 2023 · 14 comments
Open

Research performance issues on Desktop #3543

mazunin-v-jb opened this issue Aug 21, 2023 · 14 comments
Assignees
Labels
desktop enhancement New feature or request p:high High priority performance

Comments

@mazunin-v-jb
Copy link
Contributor

According to this article and performed tests with different versions of Compose, performance regression has been noticed after Compose 1.0 and Compose 1.2 (tested on Windows).
This is a potential point for further optimization.

@igordmn
Copy link
Collaborator

igordmn commented Aug 21, 2023

Windows 11, Corretto 18, 10000 squares

Compose, Kotlin FPS
1.5.0, 1.9.0 69
1.5.0, 1.7.10 69
1.4.3, 1.7.10 68
1.3.1, 1.7.10 78
1.2.1, 1.7.10 78
1.1.1, 1.6.10 122
1.0.0, 1.5.31 122
0.4.0, 1.5.10 149

A reduced benchmark:

import androidx.compose.ui.awt.ComposeWindow     // for >= 1.0.0
// import androidx.compose.desktop.ComposeWindow // for 0.4.0
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import java.awt.Dimension
import javax.swing.SwingUtilities
import kotlin.math.roundToInt

fun main() = SwingUtilities.invokeLater {
    System.setProperty("skiko.renderApi", "OPENGL")
    System.setProperty("skiko.vsync.enabled", "false")

    ComposeWindow().apply {
        size = Dimension(1280, 720)
        setContent {
            App()
        }
        isVisible = true
    }
}

val particlesCount = 10_000
val fpsCounter = FPSCounter()
var time by mutableStateOf(0L)

@Composable
fun App() = Canvas(Modifier.fillMaxSize()) {
    drawIntoCanvas {
        time++

        fpsCounter.tick()
        drawRect(Color.Red)
        repeat(particlesCount) {
            val x = Math.random().toFloat()
            val y = Math.random().toFloat()
            drawRect(
                color = Color.White,
                Offset(size.width * x, size.height * y),
                Size(10f, 10f)
            )
        }
    }
}

// a reduced copy from skiko
class FPSCounter(
    private val periodSeconds: Double = 2.0,
) {
    private val times = mutableListOf<Long>()
    private var lastLogTime = System.nanoTime()
    private var lastTime = System.nanoTime()

    fun tick() {
        val time = System.nanoTime()
        val frameTime = time - lastTime
        lastTime = time

        times.add(frameTime)

        if ((time - lastLogTime) > periodSeconds.secondsToNanos() && times.isNotEmpty()) {
            val average = (nanosPerSecond / times.average()).roundToInt()
            times.clear()
            lastLogTime = time
            println("FPS $average")
        }
    }

    private val nanosPerSecond = 1_000_000_000.0
    private fun Double.secondsToNanos(): Long = (this * nanosPerSecond).toLong()
}

@igordmn
Copy link
Collaborator

igordmn commented Aug 21, 2023

The regression is in Skiko or in Skia, not in Compose itself. A pure Skiko benchmark shows similar regressions:

// for 0.4.0
//import org.jetbrains.skija.Canvas
//import org.jetbrains.skija.Color
//import org.jetbrains.skija.Paint
//import org.jetbrains.skija.Rect

import org.jetbrains.skia.Canvas
import org.jetbrains.skia.Color
import org.jetbrains.skia.Paint
import org.jetbrains.skia.Rect
import org.jetbrains.skiko.SkikoView
import org.jetbrains.skiko.SkiaLayer
import java.awt.Dimension
import javax.swing.JFrame
import javax.swing.SwingUtilities
import kotlin.math.roundToInt

val redPaint = Paint().apply {
    color = Color.makeRGB(255, 0, 0)
}

val whitePaint = Paint().apply {
    color = Color.makeRGB(255, 255, 255)
}

fun main() = SwingUtilities.invokeLater {
    System.setProperty("skiko.renderApi", "OPENGL")
    System.setProperty("skiko.vsync.enabled", "false")

    JFrame().apply {
        size = Dimension(1280, 720)
        add(SkiaLayer().apply {
            size = Dimension(1280, 720)
// for 0.4.0
//            renderer = object : org.jetbrains.skiko.SkiaRenderer {
            skikoView = object : SkikoView {
                override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
                    fpsCounter.tick()
                    canvas.drawRect(Rect(0f, 0f, width.toFloat(), height.toFloat()), redPaint)
                    repeat(particlesCount) {
                        val x = Math.random().toFloat()
                        val y = Math.random().toFloat()
                        canvas.drawRect(
                            Rect.makeXYWH(width * x, height * y, 10f, 10f),
                            whitePaint
                        )
                    }
                    needRedraw()
                }
            }
        })
        isVisible = true
    }
}

val particlesCount = 10_000
val fpsCounter = FPSCounter()

// a reduced copy from skiko
class FPSCounter(
    private val periodSeconds: Double = 2.0,
) {
    private val times = mutableListOf<Long>()
    private var lastLogTime = System.nanoTime()
    private var lastTime = System.nanoTime()

    fun tick() {
        val time = System.nanoTime()
        val frameTime = time - lastTime
        lastTime = time

        times.add(frameTime)

        if ((time - lastLogTime) > periodSeconds.secondsToNanos() && times.isNotEmpty()) {
            val average = (nanosPerSecond / times.average()).roundToInt()
            times.clear()
            lastLogTime = time
            println("FPS $average")
        }
    }

    private val nanosPerSecond = 1_000_000_000.0
    private fun Double.secondsToNanos(): Long = (this * nanosPerSecond).toLong()
}

@MohamedRejeb
Copy link

MohamedRejeb commented Aug 24, 2023

Does this mean that it could have some effects on other targets as well? iOS? If so, fixing this problem is going to boost performance for all targets.
Also, I think that the title and labels should be changed.

@igordmn
Copy link
Collaborator

igordmn commented Aug 24, 2023

If it is not a Java/JNI overhead issue, then, yes, it should also affect iOS/web platforms.

@elijah-semyonov elijah-semyonov self-assigned this Sep 1, 2023
@elijah-semyonov
Copy link
Contributor

elijah-semyonov commented Sep 1, 2023

JetBrains/skiko@master...es/regression-rollback
Regression was introduced by commit from which this branch starts, this commit shows FPS similar to Compose 1.1.1.

Regression is not present on macOS targets. We will try to update to latest Skia and see if they fixed the issue.

@MohamedRejeb
Copy link

Hey, Any news about this issue?

@igordmn
Copy link
Collaborator

igordmn commented Sep 25, 2023

We plan to update Skia, and if this won't resolve the issue, we'll look further. It either a Skia regression, or a build configuration change.

@MohamedRejeb
Copy link

Awesome, thanks for the great work! I'm working on a drawing app and users are encountering some latency issues, I hope that this will fix it.

@igordmn
Copy link
Collaborator

igordmn commented Oct 5, 2023

Upgrading Skia from m110 to m116 doesn't help.

I checked the new Skiko with this PR - FPS is the same

@RyuuyaS
Copy link

RyuuyaS commented Oct 20, 2023

Hello, is there any news regarding this problem?

@RafaelAthosPrime
Copy link

RafaelAthosPrime commented Jan 29, 2024

Any news about this problem? I'm very worried because my customers of my desktop project have low-end specs and the FPS is about 10~15 that doesn't support OPENGL
I spend the last 2 years working on this project since the compose multiplatform was in 1.0 alpha

@MohamedRejeb
Copy link

Any news about this problem?

@igordmn igordmn added the p:high High priority label Feb 8, 2024
@RafaelAthosPrime
Copy link

Any news? Same problem with the version 1.6.0

@okushnikov
Copy link

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
desktop enhancement New feature or request p:high High priority performance
Projects
None yet
Development

No branches or pull requests

7 participants