Unverified Commit 4abc90f9 authored by Igor Demin's avatar Igor Demin Committed by GitHub

Don't draw if window is invisible (JFrame.isVisible = false) (#149)

Partially fix https://github.com/JetBrains/skiko/issues/137
parent 57f3f868
......@@ -30,13 +30,13 @@ open class SkiaLayer(
ContentScale,
}
internal val backedLayer : HardwareLayer
internal val backedLayer: HardwareLayer
val canvas: java.awt.Canvas
get() = backedLayer
init {
setOpaque(false)
isOpaque = false
layout = null
backedLayer = object : HardwareLayer() {
override fun paint(g: Graphics) {
......@@ -54,9 +54,12 @@ open class SkiaLayer(
return this@SkiaLayer.inputMethodRequests
}
}
add(backedLayer)
@Suppress("LeakingThis")
add(backedLayer)
backedLayer.addHierarchyListener {
if (it.changeFlags and HierarchyEvent.SHOWING_CHANGED.toLong() != 0L) {
checkShowing()
}
if (it.changeFlags and HierarchyEvent.DISPLAYABILITY_CHANGED.toLong() != 0L) {
checkInit()
}
......@@ -69,10 +72,24 @@ open class SkiaLayer(
private fun checkInit() {
if (!isInited && isDisplayable) {
backedLayer.defineContentScale()
checkShowing()
init()
}
}
private fun checkShowing() {
isShowingCached = super.isShowing()
if (isShowing) {
repaint()
}
}
private var isShowingCached = false
override fun isShowing(): Boolean {
return isShowingCached
}
val contentScale: Float
get() = backedLayer.contentScale
......@@ -84,7 +101,9 @@ open class SkiaLayer(
var fullscreen: Boolean
get() = backedLayer.fullscreen
set(value) { backedLayer.fullscreen = value }
set(value) {
backedLayer.fullscreen = value
}
var renderer: SkiaRenderer? = null
val clipComponents = mutableListOf<ClipRectangle>()
......@@ -117,7 +136,7 @@ open class SkiaLayer(
do {
thrown = false
try {
renderApi = fallbackRenderApiQueue.removeAt(0)
renderApi = fallbackRenderApiQueue.removeAt(0)
contextHandler?.dispose()
redrawer?.dispose()
contextHandler = createContextHandler(this, renderApi)
......@@ -137,10 +156,10 @@ open class SkiaLayer(
}
private val stateHandlers =
mutableMapOf<PropertyKind, MutableList<(SkiaLayer) -> Unit>>()
mutableMapOf<PropertyKind, MutableList<(SkiaLayer) -> Unit>>()
fun onStateChanged(kind: PropertyKind, handler: (SkiaLayer) -> Unit) {
stateHandlers.getOrPut( kind, { mutableListOf() }) += handler
stateHandlers.getOrPut(kind, { mutableListOf() }) += handler
}
private fun notifyChange(kind: PropertyKind) {
......@@ -386,5 +405,5 @@ open class SkiaLayer(
rounded = value.toFloat()
}
return rounded.toInt()
}
}
}
......@@ -17,8 +17,10 @@ internal class AngleRedrawer(
private var device: Long = 0
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
update(System.nanoTime())
draw()
if (layer.isShowing) {
update(System.nanoTime())
draw()
}
}
override fun dispose() {
......
......@@ -25,8 +25,10 @@ internal class Direct3DRedrawer(
}
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
update(System.nanoTime())
draw()
if (layer.isShowing) {
update(System.nanoTime())
draw()
}
}
override fun dispose() = synchronized(drawLock) {
......
......@@ -83,11 +83,14 @@ internal class LinuxOpenGLRedrawer(
companion object {
private val toRedraw = mutableSetOf<LinuxOpenGLRedrawer>()
private val toRedrawCopy = mutableSetOf<LinuxOpenGLRedrawer>()
private val toRedrawAlive = toRedrawCopy.asSequence().filterNot(LinuxOpenGLRedrawer::isDisposed)
private val toRedrawVisible = toRedrawCopy
.asSequence()
.filterNot(LinuxOpenGLRedrawer::isDisposed)
.filter { it.layer.isShowing }
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
// we should wait for the window with the maximum frame limit to avoid bottleneck when there is a window on a slower monitor
toRedrawAlive.maxByOrNull { it.frameLimit }?.limitFramesIfNeeded()
toRedrawVisible.maxByOrNull { it.frameLimit }?.limitFramesIfNeeded()
toRedrawCopy.clear()
toRedrawCopy.addAll(toRedraw)
......@@ -95,7 +98,7 @@ internal class LinuxOpenGLRedrawer(
val nanoTime = System.nanoTime()
for (redrawer in toRedrawAlive) {
for (redrawer in toRedrawVisible) {
try {
redrawer.update(nanoTime)
} catch (e: CancellationException) {
......@@ -103,9 +106,9 @@ internal class LinuxOpenGLRedrawer(
}
}
val drawingSurfaces = toRedrawAlive.associateWith { lockLinuxDrawingSurface(it.layer.backedLayer) }
val drawingSurfaces = toRedrawVisible.associateWith { lockLinuxDrawingSurface(it.layer.backedLayer) }
try {
toRedrawAlive.forEach { redrawer ->
toRedrawVisible.forEach { redrawer ->
drawingSurfaces[redrawer]!!.makeCurrent(redrawer.context)
redrawer.draw()
}
......@@ -113,11 +116,11 @@ internal class LinuxOpenGLRedrawer(
// TODO(demin) it seems now vsync doesn't work as expected with two windows (we have fps = refreshRate / windowCount)
// perhaps we should create frameDispatcher for each display.
// Don't know what happened, but on 620547a commit everything was okay. maybe something changed in the code, maybe my system changed
toRedrawAlive.forEach { redrawer ->
toRedrawVisible.forEach { redrawer ->
drawingSurfaces[redrawer]!!.swapBuffers()
}
toRedrawAlive.forEach { redrawer ->
toRedrawVisible.forEach { redrawer ->
drawingSurfaces[redrawer]!!.makeCurrent(redrawer.context)
OpenGLApi.instance.glFinish()
}
......
......@@ -9,7 +9,6 @@ import org.jetbrains.skia.DirectContext
import org.jetbrains.skiko.*
import javax.swing.SwingUtilities.convertPoint
import javax.swing.SwingUtilities.getRootPane
import kotlin.time.ExperimentalTime
internal class MetalRedrawer(
private val layer: SkiaLayer,
......@@ -32,8 +31,10 @@ internal class MetalRedrawer(
}
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
update(System.nanoTime())
draw()
if (layer.isShowing) {
update(System.nanoTime())
draw()
}
}
override fun dispose() = synchronized(drawLock) {
......
......@@ -19,9 +19,11 @@ internal class SoftwareRedrawer(
frameLimiter.awaitNextFrame()
}
layer.update(System.nanoTime())
if (layer.prepareDrawContext()) {
layer.draw()
if (layer.isShowing) {
layer.update(System.nanoTime())
if (layer.prepareDrawContext()) {
layer.draw()
}
}
}
......
......@@ -65,7 +65,10 @@ internal class WindowsOpenGLRedrawer(
companion object {
private val toRedraw = mutableSetOf<WindowsOpenGLRedrawer>()
private val toRedrawCopy = mutableSetOf<WindowsOpenGLRedrawer>()
private val toRedrawAlive = toRedrawCopy.asSequence().filterNot(WindowsOpenGLRedrawer::isDisposed)
private val toRedrawVisible = toRedrawCopy
.asSequence()
.filterNot(WindowsOpenGLRedrawer::isDisposed)
.filter { it.layer.isShowing }
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
toRedrawCopy.clear()
......@@ -74,7 +77,7 @@ internal class WindowsOpenGLRedrawer(
val nanoTime = System.nanoTime()
for (redrawer in toRedrawAlive) {
for (redrawer in toRedrawVisible) {
try {
redrawer.update(nanoTime)
} catch (e: CancellationException) {
......@@ -82,21 +85,21 @@ internal class WindowsOpenGLRedrawer(
}
}
for (redrawer in toRedrawAlive) {
for (redrawer in toRedrawVisible) {
redrawer.makeCurrent()
redrawer.draw()
}
for (redrawer in toRedrawAlive) {
for (redrawer in toRedrawVisible) {
redrawer.swapBuffers()
}
for (redrawer in toRedrawAlive) {
for (redrawer in toRedrawVisible) {
redrawer.makeCurrent()
OpenGLApi.instance.glFinish()
}
val isVsyncEnabled = toRedrawAlive.all { it.properties.isVsyncEnabled }
val isVsyncEnabled = toRedrawVisible.all { it.properties.isVsyncEnabled }
if (isVsyncEnabled) {
withContext(Dispatchers.IO) {
dwmFlush() // wait for vsync
......
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