Unverified Commit 4561adb5 authored by Igor Demin's avatar Igor Demin Committed by GitHub

Refactor Skiko properties (#563)

- Make SkikoProperties public, and don't cache the values, so users can change properties in runtime

- Deprecate skiko.directx.gpu.priority and skiko.directx.gpu.priority, introduce skiko.gpu.priority. There is no need in separate priority for macOs/DirectX

- Fix skiko.fps.enabled property
parent edb89083
......@@ -624,7 +624,8 @@ internal fun defaultFPSCounter(
FPSCounter(
periodSeconds = fpsPeriodSeconds,
showLongFrames = fpsLongFramesShow,
getLongFrameMillis = { fpsLongFramesMillis ?: 1.5 * 1000 / refreshRate }
getLongFrameMillis = { fpsLongFramesMillis ?: (1.5 * 1000 / refreshRate) },
logOnTick = true
)
}
......
......@@ -17,7 +17,9 @@ internal class Direct3DRedrawer(
private var isDisposed = false
private var drawLock = Any()
private val device = createDirectXDevice(getAdapterPriority(), layer.contentHandle, layer.transparency).also {
private val device = createDirectXDevice(
properties.adapterPriority.ordinal, layer.contentHandle, layer.transparency
).also {
if (it == 0L || !isVideoCardSupported(layer.renderApi)) {
throw RenderException("Failed to create DirectX12 device.")
}
......@@ -77,16 +79,6 @@ internal class Direct3DRedrawer(
makeDirectXSurface(device, context, width, height, index)
)
private fun getAdapterPriority(): Int {
val adapterPriority = GpuPriority.parse(System.getProperty("skiko.directx.gpu.priority"))
return when (adapterPriority) {
GpuPriority.Auto -> 0
GpuPriority.Integrated -> 1
GpuPriority.Discrete -> 2
else -> 0
}
}
fun resizeBuffers(width: Int, height: Int) = resizeBuffers(device, width, height)
fun getBufferIndex() = getBufferIndex(device)
......
......@@ -25,7 +25,7 @@ internal class MetalRedrawer(
private var isDisposed = false
private var drawLock = Any()
private val device = layer.backedLayer.useDrawingSurfacePlatformInfo {
createMetalDevice(layer.windowHandle, layer.transparency, getAdapterPriority(), it)
createMetalDevice(layer.windowHandle, layer.transparency, properties.adapterPriority.ordinal, it)
}
private val windowHandle = layer.windowHandle
......@@ -127,16 +127,6 @@ internal class MetalRedrawer(
fun finishFrame() = finishFrame(device)
fun getAdapterPriority(): Int {
val adapterPriority = GpuPriority.parse(System.getProperty("skiko.metal.gpu.priority"))
return when (adapterPriority) {
GpuPriority.Auto -> 0
GpuPriority.Integrated -> 1
GpuPriority.Discrete -> 2
else -> 0
}
}
fun getAdapterName(): String = getAdapterName(device)
fun getAdapterMemorySize(): Long = getAdapterMemorySize(device)
......
......@@ -7,14 +7,18 @@ class FPSCounter(
private val showLongFrames: Boolean = false,
private val getLongFrameMillis: () -> Double = {
1.5 * 1000 / 60
}
},
private val logOnTick: Boolean = false
) {
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
var average = 0
private set
var min = 0
private set
var max = 0
private set
fun tick() {
val time = currentNanoTime()
......@@ -24,28 +28,21 @@ class FPSCounter(
times.add(frameTime)
if (showLongFrames && frameTime > getLongFrameMillis().millisToNanos()) {
if (logOnTick && showLongFrames && frameTime > getLongFrameMillis().millisToNanos()) {
println("$timestamp Long frame ${frameTime.nanosToMillis()} ms")
}
if ((time - lastLogTime) > periodSeconds.secondsToNanos() && times.isNotEmpty()) {
_average = (nanosPerSecond / times.average()).roundToInt()
_min = (nanosPerSecond / times.maxOrNull()!!).roundToInt()
_max = (nanosPerSecond / times.minOrNull()!!).roundToInt()
average = (nanosPerSecond / times.average()).roundToInt()
min = (nanosPerSecond / times.maxOrNull()!!).roundToInt()
max = (nanosPerSecond / times.minOrNull()!!).roundToInt()
times.clear()
lastLogTime = time
if (logOnTick) {
println("[$timestamp] FPS $average ($min-$max)")
}
}
}
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
......
......@@ -26,6 +26,6 @@ enum class GpuPriority(val value: String) {
Auto("auto"), Integrated("integrated"), Discrete("discrete");
companion object {
fun parse(value: String?): GpuPriority? = GpuPriority.values().find { it.value == value }
fun parseOrNull(value: String): GpuPriority? = GpuPriority.values().find { it.value == value }
}
}
......@@ -4,4 +4,5 @@ internal data class SkiaLayerProperties(
val isVsyncEnabled: Boolean = SkikoProperties.vsyncEnabled,
val isVsyncFramelimitFallbackEnabled: Boolean = SkikoProperties.vsyncFramelimitFallbackEnabled,
val renderApi: GraphicsApi = SkikoProperties.renderApi,
val adapterPriority: GpuPriority = SkikoProperties.gpuPriority,
)
package org.jetbrains.skiko
import java.lang.System.getProperty
// TODO maybe we can get rid of global properties, and pass SkiaLayerProperties to Window -> ComposeWindow -> SkiaLayer
@Suppress("SameParameterValue")
internal object SkikoProperties {
val vsyncEnabled: Boolean = property("skiko.vsync.enabled", default = true)
/**
* Global Skiko properties, which are read from system JDK variables orr from environment variables
*/
object SkikoProperties {
val vsyncEnabled: Boolean get() = getProperty("skiko.vsync.enabled")?.toBoolean() ?: true
/**
* If vsync is enabled, but platform can't support it (Software renderer, Linux with uninstalled drivers),
* we enable frame limit by the display refresh rate.
*/
val vsyncFramelimitFallbackEnabled: Boolean = property(
"skiko.vsync.framelimit.fallback.enabled", default = true
)
val vsyncFramelimitFallbackEnabled: Boolean get() = getProperty(
"skiko.vsync.framelimit.fallback.enabled"
)?.toBoolean() ?: true
val fpsEnabled: Boolean = property("skiko.fps.enabled", default = false)
val fpsPeriodSeconds: Double = property("skiko.fps.periodSeconds", default = 2.0)
val fpsEnabled: Boolean get() = getProperty("skiko.fps.enabled")?.toBoolean() ?: false
val fpsPeriodSeconds: Double get() = getProperty("skiko.fps.periodSeconds")?.toDouble() ?: 2.0
/**
* Show long frames which is longer than [fpsLongFramesMillis].
* If [fpsLongFramesMillis] isn't defined will show frames longer than 1.5 * (1000 / displayRefreshRate)
*/
val fpsLongFramesShow: Boolean = property("skiko.fps.longFrames.show", default = false)
val fpsLongFramesShow: Boolean get() = getProperty("skiko.fps.longFrames.show")?.toBoolean() ?: false
val fpsLongFramesMillis: Double? = property("skiko.fps.longFrames.millis", default = null)
val fpsLongFramesMillis: Double? get() = getProperty("skiko.fps.longFrames.millis")?.toDouble()
val renderApi: GraphicsApi get() {
val environment = System.getenv("SKIKO_RENDER_API")
val property = System.getProperty("skiko.renderApi")
val property = getProperty("skiko.renderApi")
return if (environment != null) {
parseRenderApi(environment)
} else {
......@@ -34,6 +39,14 @@ internal object SkikoProperties {
}
}
val gpuPriority: GpuPriority get() {
val value = getProperty("skiko.gpu.priority") ?:
getProperty("skiko.metal.gpu.priority") ?: // for backward compatability
getProperty("skiko.directx.gpu.priority") // for backward compatability
return value?.let(GpuPriority::parseOrNull) ?: GpuPriority.Auto
}
internal fun parseRenderApi(text: String?): GraphicsApi {
when(text) {
"SOFTWARE_COMPAT" -> return GraphicsApi.SOFTWARE_COMPAT
......@@ -61,7 +74,7 @@ internal object SkikoProperties {
}
}
fun fallbackRenderApiQueue(initialApi: GraphicsApi) : List<GraphicsApi> {
internal fun fallbackRenderApiQueue(initialApi: GraphicsApi) : List<GraphicsApi> {
var fallbackApis = when (hostOs) {
OS.Linux -> listOf(GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
OS.MacOS -> listOf(GraphicsApi.METAL, GraphicsApi.SOFTWARE_COMPAT)
......@@ -78,13 +91,4 @@ internal object SkikoProperties {
return listOf(initialApi) + fallbackApis
}
private fun property(name: String, default: Boolean) =
System.getProperty(name)?.toBoolean() ?: default
private fun property(name: String, default: Double) =
System.getProperty(name)?.toDouble() ?: default
private fun property(name: String, default: Double?) =
System.getProperty(name)?.toDouble() ?: default
}
\ No newline at end of file
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