Unverified Commit ed693b57 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

Separate AWT from JVM code. (#427)

parent d389d095
...@@ -29,7 +29,7 @@ jobs: ...@@ -29,7 +29,7 @@ jobs:
- shell: bash - shell: bash
run: | run: |
cd $GITHUB_WORKSPACE/skiko cd $GITHUB_WORKSPACE/skiko
./gradlew --stacktrace --info -Pskiko.native.enabled=true jvmTest ./gradlew --stacktrace --info -Pskiko.native.enabled=true awtTest
./gradlew --stacktrace --info -Pskiko.native.enabled=true macosX64Test ./gradlew --stacktrace --info -Pskiko.native.enabled=true macosX64Test
./gradlew --stacktrace --info -Pskiko.native.enabled=true publishToMavenLocal ./gradlew --stacktrace --info -Pskiko.native.enabled=true publishToMavenLocal
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
...@@ -87,7 +87,7 @@ jobs: ...@@ -87,7 +87,7 @@ jobs:
sudo apt-get install ninja-build fontconfig libfontconfig1-dev libglu1-mesa-dev libxrandr-dev zip xvfb -y sudo apt-get install ninja-build fontconfig libfontconfig1-dev libglu1-mesa-dev libxrandr-dev zip xvfb -y
sudo Xvfb :0 -screen 0 1280x720x24 & sudo Xvfb :0 -screen 0 1280x720x24 &
export DISPLAY=:0 export DISPLAY=:0
./gradlew --stacktrace --info -Pskiko.native.enabled=true linuxX64Test jvmTest ./gradlew --stacktrace --info -Pskiko.native.enabled=true linuxX64Test awtTest
./gradlew --stacktrace --info publishToMavenLocal ./gradlew --stacktrace --info publishToMavenLocal
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
with: with:
...@@ -145,7 +145,7 @@ jobs: ...@@ -145,7 +145,7 @@ jobs:
- shell: bash - shell: bash
run: | run: |
cd ./skiko cd ./skiko
./gradlew --stacktrace --info jvmTest ./gradlew --stacktrace --info awtTest
./gradlew --stacktrace --info publishToMavenLocal ./gradlew --stacktrace --info publishToMavenLocal
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
with: with:
......
...@@ -110,6 +110,6 @@ Add `-Dskiko.test.ui.enabled=true` to enable UI tests (integration tests, which ...@@ -110,6 +110,6 @@ Add `-Dskiko.test.ui.enabled=true` to enable UI tests (integration tests, which
For example, if we want to include UI tests when we test JVM target, call this: For example, if we want to include UI tests when we test JVM target, call this:
``` ```
./gradlew jvmTest -Dskiko.test.ui.enabled=true ./gradlew awtTest -Dskiko.test.ui.enabled=true
``` ```
Don't run any background tasks, click mouse, or press keys during the tests. Otherwise, they probably fail. Don't run any background tasks, click mouse, or press keys during the tests. Otherwise, they probably fail.
...@@ -110,10 +110,13 @@ kotlin { ...@@ -110,10 +110,13 @@ kotlin {
resources.srcDirs(unzipTask.map { it.destinationDir }) resources.srcDirs(unzipTask.map { it.destinationDir })
} }
val macosMain by creating { val darwinMain by creating {
dependsOn(nativeMain) dependsOn(nativeMain)
} }
val macosMain by creating {
dependsOn(darwinMain)
}
if (hostOs == "macos") { if (hostOs == "macos") {
val archTargetMain = when (host) { val archTargetMain = when (host) {
...@@ -132,7 +135,7 @@ kotlin { ...@@ -132,7 +135,7 @@ kotlin {
else -> throw GradleException("Host OS is not supported") else -> throw GradleException("Host OS is not supported")
} }
val iosMain by creating { val iosMain by creating {
dependsOn(nativeMain) dependsOn(darwinMain)
} }
val iosX64Main by getting { val iosX64Main by getting {
dependsOn(iosMain) dependsOn(iosMain)
......
<component name="ProjectRunConfigurationManager"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="jvmTest" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="awtTest" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings> <ExternalSystemSettings>
<option name="executionName" /> <option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" /> <option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="jvmTest -Dskiko.test.ui.enabled=true -Dskiko.test.ui.renderApi=all" /> <option name="scriptParameters" value="awtTest -Dskiko.test.ui.enabled=true -Dskiko.test.ui.renderApi=all" />
<option name="taskDescriptions"> <option name="taskDescriptions">
<list /> <list />
</option> </option>
...@@ -18,4 +18,4 @@ ...@@ -18,4 +18,4 @@
<DebugAllEnabled>false</DebugAllEnabled> <DebugAllEnabled>false</DebugAllEnabled>
<method v="2" /> <method v="2" />
</configuration> </configuration>
</component> </component>
\ No newline at end of file
...@@ -214,12 +214,20 @@ val Project.supportAndroid: Boolean ...@@ -214,12 +214,20 @@ val Project.supportAndroid: Boolean
get() = findProperty("skiko.android.enabled") == "true" get() = findProperty("skiko.android.enabled") == "true"
kotlin { kotlin {
jvm { jvm("awt") {
compilations.all { compilations.all {
kotlinOptions.jvmTarget = "11" kotlinOptions.jvmTarget = "11"
} }
} }
if (supportAndroid) {
jvm("android") {
compilations.all {
kotlinOptions.jvmTarget = "11"
}
}
}
if (supportWasm) { if (supportWasm) {
js(IR) { js(IR) {
browser() { browser() {
...@@ -245,7 +253,7 @@ kotlin { ...@@ -245,7 +253,7 @@ kotlin {
sourceSets { sourceSets {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {
implementation(kotlin("stdlib-common")) implementation(kotlin("stdlib"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
} }
} }
...@@ -259,18 +267,37 @@ kotlin { ...@@ -259,18 +267,37 @@ kotlin {
/* /*
val androidMain by getting { val androidMain by getting {
dependencies { dependencies {
compileOnly(files(androidJar()))
} }
} */ } */
val jvmMain by getting { val jvmMain by creating {
dependsOn(commonMain)
dependencies { dependencies {
implementation(kotlin("stdlib")) implementation(kotlin("stdlib"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion")
}
}
val awtMain by getting {
dependsOn(jvmMain)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion")
} }
}
if (supportAndroid) {
val androidMain by getting {
dependsOn(jvmMain)
dependencies {
compileOnly(files(androidJar()))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion")
}
}
} }
val jvmTest by getting {
val jvmTest by creating {
dependencies { dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
implementation(kotlin("test-junit")) implementation(kotlin("test-junit"))
...@@ -278,6 +305,16 @@ kotlin { ...@@ -278,6 +305,16 @@ kotlin {
} }
} }
val awtTest by getting {
dependsOn(jvmTest)
}
if (supportAndroid) {
val androidTest by getting {
dependsOn(jvmTest)
}
}
if (supportWasm || supportNative) { if (supportWasm || supportNative) {
val nativeJsMain by creating { val nativeJsMain by creating {
dependsOn(commonMain) dependsOn(commonMain)
...@@ -838,7 +875,7 @@ fun generateVersionTask(targetOs: OS, targetArch: Arch) = project.tasks.register ...@@ -838,7 +875,7 @@ fun generateVersionTask(targetOs: OS, targetArch: Arch) = project.tasks.register
val skikoJvmJar by project.tasks.registering(Jar::class) { val skikoJvmJar by project.tasks.registering(Jar::class) {
archiveBaseName.set("skiko-jvm") archiveBaseName.set("skiko-jvm")
from(kotlin.jvm().compilations["main"].output.allOutputs) from(kotlin.jvm("awt").compilations["main"].output.allOutputs)
} }
fun maybeSignTask(targetOs: OS, targetArch: Arch, linkJvmBindings: Provider<LinkSkikoTask>) = fun maybeSignTask(targetOs: OS, targetArch: Arch, linkJvmBindings: Provider<LinkSkikoTask>) =
...@@ -1037,7 +1074,7 @@ publishing { ...@@ -1037,7 +1074,7 @@ publishing {
afterEvaluate { afterEvaluate {
artifact(entry.value.map { it.archiveFile.get() }) artifact(entry.value.map { it.archiveFile.get() })
var jvmSourcesArtifact: Any? = null var jvmSourcesArtifact: Any? = null
kotlin.jvm().mavenPublication { kotlin.jvm("awt").mavenPublication {
jvmSourcesArtifact = artifacts.find { it.classifier == "sources" } jvmSourcesArtifact = artifacts.find { it.classifier == "sources" }
} }
if (jvmSourcesArtifact == null) { if (jvmSourcesArtifact == null) {
......
package org.jetbrains.skiko
import org.jetbrains.skiko.redrawer.*
import javax.swing.UIManager
actual fun setSystemLookAndFeel() = UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
internal actual fun makeDefaultRenderFactory(): RenderFactory {
return object : RenderFactory {
override fun createRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer = when (hostOs) {
OS.MacOS -> when (renderApi) {
GraphicsApi.SOFTWARE_COMPAT, GraphicsApi.SOFTWARE_FAST -> SoftwareRedrawer(layer, properties)
else -> MetalRedrawer(layer, properties)
}
OS.Windows -> when (renderApi) {
GraphicsApi.SOFTWARE_COMPAT -> SoftwareRedrawer(layer, properties)
GraphicsApi.SOFTWARE_FAST -> WindowsSoftwareRedrawer(layer, properties)
GraphicsApi.OPENGL -> WindowsOpenGLRedrawer(layer, properties)
else -> Direct3DRedrawer(layer, properties)
}
OS.Linux -> when (renderApi) {
GraphicsApi.SOFTWARE_COMPAT -> SoftwareRedrawer(layer, properties)
GraphicsApi.SOFTWARE_FAST -> LinuxSoftwareRedrawer(layer, properties)
else -> LinuxOpenGLRedrawer(layer, properties)
}
OS.Android -> TODO()
OS.JS, OS.Ios -> {
TODO("Commonize me")
}
}
}
}
package org.jetbrains.skiko package org.jetbrains.skiko
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.awt.Canvas import java.awt.Canvas
import java.awt.Component import java.awt.Component
import java.awt.Graphics import java.awt.Graphics
import java.awt.event.InputMethodEvent import java.awt.event.InputMethodEvent
import javax.accessibility.Accessible import javax.accessibility.Accessible
import javax.accessibility.AccessibleContext import javax.accessibility.AccessibleContext
import kotlin.time.ExperimentalTime
internal open class HardwareLayer( internal open class HardwareLayer(
externalAccessibleFactory: ((Component) -> Accessible)? = null externalAccessibleFactory: ((Component) -> Accessible)? = null
...@@ -81,4 +86,51 @@ internal open class HardwareLayer( ...@@ -81,4 +86,51 @@ internal open class HardwareLayer(
val res = _externalAccessible?.accessibleContext val res = _externalAccessible?.accessibleContext
return res ?: super.getAccessibleContext() return res ?: super.getAccessibleContext()
} }
}
/**
* HardwareLayer should not dispose native resources while [scope] is active.
*
* So wait for scope cancellation in dispose method:
* ```
* runBlocking {
* frameJob.cancelAndJoin()
* }
* ```
*
* Can be accessed from multiple threads.
*/
@OptIn(ExperimentalTime::class)
@Suppress("UNUSED_PARAMETER")
internal fun FrameLimiter(
scope: CoroutineScope,
component: HardwareLayer,
onNewFrameLimit: (frameLimit: Double) -> Unit = {}
): FrameLimiter {
val state = object {
@Volatile
var frameLimit = MinMainstreamMonitorRefreshRate
}
val frames = Channel<Unit>(Channel.CONFLATED)
frames.trySend(Unit)
scope.launch {
while (true) {
frames.receive()
// TODO will lockLinuxDrawingSurface inside getDisplayRefreshRate can cause draw lock too?
// it takes 2ms on my machine on Linux (0.01ms on macOs, 0.1ms on Windows)
state.frameLimit = component.getDisplayRefreshRate()
onNewFrameLimit(state.frameLimit)
delay(1000)
}
}
return FrameLimiter(
scope,
frameMillis = {
frames.trySend(Unit)
(1000 / state.frameLimit).toLong()
}
)
} }
\ No newline at end of file
...@@ -74,13 +74,13 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -74,13 +74,13 @@ internal val platformOperations: PlatformOperations by lazy {
override fun isFullscreen(component: Component): Boolean { override fun isFullscreen(component: Component): Boolean {
val window = SwingUtilities.getRoot(component) as Window val window = SwingUtilities.getRoot(component) as Window
val device = window.graphicsConfiguration.device val device = window.graphicsConfiguration.device
return device.getFullScreenWindow() == window return device.fullScreenWindow == window
} }
override fun setFullscreen(component: Component, value: Boolean) { override fun setFullscreen(component: Component, value: Boolean) {
val window = SwingUtilities.getRoot(component) as Window val window = SwingUtilities.getRoot(component) as Window
val device = window.graphicsConfiguration.device val device = window.graphicsConfiguration.device
device.setFullScreenWindow(if (value) window else null) device.fullScreenWindow = if (value) window else null
} }
override fun disableTitleBar(component: Component, headerHeight: Float) { override fun disableTitleBar(component: Component, headerHeight: Float) {
...@@ -99,13 +99,13 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -99,13 +99,13 @@ internal val platformOperations: PlatformOperations by lazy {
override fun isFullscreen(component: Component): Boolean { override fun isFullscreen(component: Component): Boolean {
val window = SwingUtilities.getRoot(component) as Window val window = SwingUtilities.getRoot(component) as Window
val device = window.graphicsConfiguration.device val device = window.graphicsConfiguration.device
return device.getFullScreenWindow() == window return device.fullScreenWindow == window
} }
override fun setFullscreen(component: Component, value: Boolean) { override fun setFullscreen(component: Component, value: Boolean) {
val window = SwingUtilities.getRoot(component) as Window val window = SwingUtilities.getRoot(component) as Window
val device = window.graphicsConfiguration.device val device = window.graphicsConfiguration.device
device.setFullScreenWindow(if (value) window else null) device.fullScreenWindow = if (value) window else null
} }
override fun disableTitleBar(component: Component, headerHeight: Float) { override fun disableTitleBar(component: Component, headerHeight: Float) {
......
package org.jetbrains.skiko package org.jetbrains.skiko
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skiko.context.ContextHandler
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.redrawer.Redrawer
import java.awt.Color import java.awt.Color
import java.awt.Component import java.awt.Component
......
package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainCoroutineDispatcher
import kotlinx.coroutines.swing.Swing
actual val MainUIDispatcher: MainCoroutineDispatcher
get() = Dispatchers.Swing
package org.jetbrains.skiko.redrawer package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
import org.jetbrains.skiko.context.OpenGLContextHandler import org.jetbrains.skiko.context.OpenGLContextHandler
...@@ -97,7 +96,7 @@ internal class LinuxOpenGLRedrawer( ...@@ -97,7 +96,7 @@ internal class LinuxOpenGLRedrawer(
.filterNot(LinuxOpenGLRedrawer::isDisposed) .filterNot(LinuxOpenGLRedrawer::isDisposed)
.filter { it.layer.isShowing } .filter { it.layer.isShowing }
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) { private val frameDispatcher = FrameDispatcher(MainUIDispatcher) {
toRedrawCopy.addAll(toRedraw) toRedrawCopy.addAll(toRedraw)
toRedraw.clear() toRedraw.clear()
......
...@@ -6,7 +6,6 @@ import kotlinx.coroutines.swing.Swing ...@@ -6,7 +6,6 @@ import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
import org.jetbrains.skiko.context.OpenGLContextHandler import org.jetbrains.skiko.context.OpenGLContextHandler
import org.jetbrains.skiko.context.SoftwareContextHandler
internal class WindowsOpenGLRedrawer( internal class WindowsOpenGLRedrawer(
private val layer: SkiaLayer, private val layer: SkiaLayer,
......
package org.jetbrains.skiko package org.jetbrains.skiko
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
...@@ -9,53 +8,6 @@ import kotlin.time.ExperimentalTime ...@@ -9,53 +8,6 @@ import kotlin.time.ExperimentalTime
private const val NanosecondsPerMillisecond = 1_000_000L private const val NanosecondsPerMillisecond = 1_000_000L
/**
* HardwareLayer should not dispose native resources while [scope] is active.
*
* So wait for scope cancellation in dispose method:
* ```
* runBlocking {
* frameJob.cancelAndJoin()
* }
* ```
*
* Can be accessed from multiple threads.
*/
@OptIn(ExperimentalTime::class)
@Suppress("UNUSED_PARAMETER")
internal fun FrameLimiter(
scope: CoroutineScope,
component: HardwareLayer,
onNewFrameLimit: (frameLimit: Double) -> Unit = {}
): FrameLimiter {
val state = object {
@Volatile
var frameLimit = MinMainstreamMonitorRefreshRate
}
val frames = Channel<Unit>(Channel.CONFLATED)
frames.trySend(Unit)
scope.launch {
while (true) {
frames.receive()
// TODO will lockLinuxDrawingSurface inside getDisplayRefreshRate can cause draw lock too?
// it takes 2ms on my machine on Linux (0.01ms on macOs, 0.1ms on Windows)
state.frameLimit = component.getDisplayRefreshRate()
onNewFrameLimit(state.frameLimit)
delay(1000)
}
}
return FrameLimiter(
scope,
frameMillis = {
frames.trySend(Unit)
(1000 / state.frameLimit).toLong()
}
)
}
/** /**
* Limit the duration of the frames (to avoid high CPU usage) to [frameMillis]. * Limit the duration of the frames (to avoid high CPU usage) to [frameMillis].
* The actual delay depends on the precision of the system timer * The actual delay depends on the precision of the system timer
......
...@@ -19,7 +19,7 @@ internal fun isVideoCardSupported(renderApi: GraphicsApi): Boolean { ...@@ -19,7 +19,7 @@ internal fun isVideoCardSupported(renderApi: GraphicsApi): Boolean {
if (it == null) { return false } if (it == null) { return false }
} }
adaptersList.forEach { adaptersList.forEach {
if (adapter.startsWith(it)) { if (adapter?.startsWith(it) == true) {
return false return false
} }
} }
......
...@@ -23,7 +23,7 @@ class OpenGLApi private constructor() { ...@@ -23,7 +23,7 @@ class OpenGLApi private constructor() {
external fun glEnable(flag: Int) external fun glEnable(flag: Int)
external fun glBindTexture(target: Int, texture: Int) external fun glBindTexture(target: Int, texture: Int)
external fun glGetIntegerv(pname: Int): Int external fun glGetIntegerv(pname: Int): Int
external fun glGetString(value: Int): String external fun glGetString(value: Int): String?
companion object { companion object {
init { init {
......
...@@ -10,32 +10,4 @@ internal interface RenderFactory { ...@@ -10,32 +10,4 @@ internal interface RenderFactory {
} }
} }
private fun makeDefaultRenderFactory(): RenderFactory { internal expect fun makeDefaultRenderFactory(): RenderFactory
return object : RenderFactory {
override fun createRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer = when (hostOs) {
OS.MacOS -> when (renderApi) {
GraphicsApi.SOFTWARE_COMPAT, GraphicsApi.SOFTWARE_FAST -> SoftwareRedrawer(layer, properties)
else -> MetalRedrawer(layer, properties)
}
OS.Windows -> when (renderApi) {
GraphicsApi.SOFTWARE_COMPAT -> SoftwareRedrawer(layer, properties)
GraphicsApi.SOFTWARE_FAST -> WindowsSoftwareRedrawer(layer, properties)
GraphicsApi.OPENGL -> WindowsOpenGLRedrawer(layer, properties)
else -> Direct3DRedrawer(layer, properties)
}
OS.Linux -> when (renderApi) {
GraphicsApi.SOFTWARE_COMPAT -> SoftwareRedrawer(layer, properties)
GraphicsApi.SOFTWARE_FAST -> LinuxSoftwareRedrawer(layer, properties)
else -> LinuxOpenGLRedrawer(layer, properties)
}
OS.Android -> TODO()
OS.JS, OS.Ios -> {
TODO("Commonize me")
}
}
}
}
package org.jetbrains.skiko package org.jetbrains.skiko
import javax.swing.UIManager expect fun setSystemLookAndFeel()
internal object Setup { internal object Setup {
fun init( fun init(
...@@ -22,7 +22,7 @@ internal object Setup { ...@@ -22,7 +22,7 @@ internal object Setup {
try { try {
if (globalLAF) { if (globalLAF) {
// Setup menu look and feel. // Setup menu look and feel.
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) setSystemLookAndFeel()
} }
if (useScreenMenuBar) { if (useScreenMenuBar) {
System.setProperty("apple.laf.useScreenMenuBar", "true") System.setProperty("apple.laf.useScreenMenuBar", "true")
......
...@@ -2,7 +2,6 @@ package org.jetbrains.skiko.redrawer ...@@ -2,7 +2,6 @@ package org.jetbrains.skiko.redrawer
import org.jetbrains.skia.Surface import org.jetbrains.skia.Surface
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.FrameDispatcher import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.FrameLimiter import org.jetbrains.skiko.FrameLimiter
import org.jetbrains.skiko.RenderException import org.jetbrains.skiko.RenderException
...@@ -19,7 +18,7 @@ internal abstract class AbstractDirectSoftwareRedrawer( ...@@ -19,7 +18,7 @@ internal abstract class AbstractDirectSoftwareRedrawer(
private val frameJob = Job() private val frameJob = Job()
private val frameLimiter = FrameLimiter(CoroutineScope(Dispatchers.IO + frameJob), layer.backedLayer) private val frameLimiter = FrameLimiter(CoroutineScope(Dispatchers.IO + frameJob), layer.backedLayer)
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) { private val frameDispatcher = FrameDispatcher(MainUIDispatcher) {
if (properties.isVsyncEnabled && properties.isVsyncFramelimitFallbackEnabled) { if (properties.isVsyncEnabled && properties.isVsyncFramelimitFallbackEnabled) {
frameLimiter.awaitNextFrame() frameLimiter.awaitNextFrame()
} }
......
...@@ -20,7 +20,7 @@ internal class AngleRedrawer( ...@@ -20,7 +20,7 @@ internal class AngleRedrawer(
private var isDisposed = false private var isDisposed = false
private var device: Long = 0 private var device: Long = 0
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) { private val frameDispatcher = FrameDispatcher(MainUIDispatcher) {
if (layer.isShowing) { if (layer.isShowing) {
update(System.nanoTime()) update(System.nanoTime())
draw() draw()
......
...@@ -25,7 +25,7 @@ internal class Direct3DRedrawer( ...@@ -25,7 +25,7 @@ internal class Direct3DRedrawer(
} }
} }
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) { private val frameDispatcher = FrameDispatcher(MainUIDispatcher) {
if (layer.isShowing) { if (layer.isShowing) {
update(System.nanoTime()) update(System.nanoTime())
draw() draw()
......
package org.jetbrains.skiko.redrawer package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.FrameDispatcher import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.FrameLimiter import org.jetbrains.skiko.FrameLimiter
import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties import org.jetbrains.skiko.SkiaLayerProperties
import org.jetbrains.skiko.context.MetalContextHandler
import org.jetbrains.skiko.context.SoftwareContextHandler import org.jetbrains.skiko.context.SoftwareContextHandler
expect val MainUIDispatcher: MainCoroutineDispatcher
internal class SoftwareRedrawer( internal class SoftwareRedrawer(
private val layer: SkiaLayer, private val layer: SkiaLayer,
private val properties: SkiaLayerProperties private val properties: SkiaLayerProperties
...@@ -19,7 +19,7 @@ internal class SoftwareRedrawer( ...@@ -19,7 +19,7 @@ internal class SoftwareRedrawer(
private val frameJob = Job() private val frameJob = Job()
private val frameLimiter = FrameLimiter(CoroutineScope(Dispatchers.IO + frameJob), layer.backedLayer) private val frameLimiter = FrameLimiter(CoroutineScope(Dispatchers.IO + frameJob), layer.backedLayer)
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) { private val frameDispatcher = FrameDispatcher(MainUIDispatcher) {
if (properties.isVsyncEnabled && properties.isVsyncFramelimitFallbackEnabled) { if (properties.isVsyncEnabled && properties.isVsyncFramelimitFallbackEnabled) {
frameLimiter.awaitNextFrame() frameLimiter.awaitNextFrame()
} }
......
...@@ -5,8 +5,8 @@ import org.jetbrains.skiko.SkiaLayerProperties ...@@ -5,8 +5,8 @@ import org.jetbrains.skiko.SkiaLayerProperties
import org.jetbrains.skiko.RenderException import org.jetbrains.skiko.RenderException
internal class WindowsSoftwareRedrawer( internal class WindowsSoftwareRedrawer(
private val layer: SkiaLayer, layer: SkiaLayer,
private val properties: SkiaLayerProperties properties: SkiaLayerProperties
) : AbstractDirectSoftwareRedrawer(layer, properties) { ) : AbstractDirectSoftwareRedrawer(layer, properties) {
init { init {
......
...@@ -65,13 +65,13 @@ internal class MacOsMetalRedrawer( ...@@ -65,13 +65,13 @@ internal class MacOsMetalRedrawer(
override fun syncSize() { override fun syncSize() {
syncContentScale() syncContentScale()
val osView = skiaLayer.nsView!! val osFrame = skiaLayer.nsView.frame
val (w, h) = osView.frame.useContents { val (w, h) = osFrame.useContents {
size.width to size.height size.width to size.height
} }
CATransaction.begin() CATransaction.begin()
CATransaction.setDisableActions(true) CATransaction.setDisableActions(true)
metalLayer.frame = osView.frame metalLayer.frame = osFrame
metalLayer.init(skiaLayer, contextHandler, device) metalLayer.init(skiaLayer, contextHandler, device)
metalLayer.drawableSize = CGSizeMake(w * metalLayer.contentsScale, h * metalLayer.contentsScale) metalLayer.drawableSize = CGSizeMake(w * metalLayer.contentsScale, h * metalLayer.contentsScale)
CATransaction.commit() CATransaction.commit()
......
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