package org.jetbrains.skiko

import kotlinx.coroutines.*
import java.util.concurrent.atomic.AtomicInteger

/**
 * This class is intended to mitigate issues coming from the situation that we have
 * pretty large native peers (Skia objects) for rather tiny Java wrappers.
 * It is especially visible for situation with paragraph classes.
 * As a result, memory consumption grows dramatically.
 * To solve this issue, we force periodic GC if certain amount of frames was rendered,
 * making sure that we'll have memory consumption under control.
 */
internal object FrameWatcher {
    var gcDelayMillis = 30_000L
    var minFramesToRenderer = 1_000

    fun start() {
        // We initiate GC on IO threads, so that rendering is not blocked in
        // cases of concurrent collectors.
        @OptIn(DelicateCoroutinesApi::class)
        GlobalScope.launch(Dispatchers.IO) {
            while (true) {
                // Wait some time between collection attempts.
                delay(gcDelayMillis)
                // Ensure that certain number of frames were rendered, as we allocate Skia
                // garbage when rendering.
                if (frameCounter.get() > minFramesToRenderer) {
                    System.gc()
                    frameCounter.set(0)
                }
            }
        }
    }

    fun nextFrame() {
        frameCounter.addAndGet(1)
    }

    private val frameCounter = AtomicInteger(0)
}
