Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
skiko
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
liuqiang
skiko
Commits
ec704f7b
Unverified
Commit
ec704f7b
authored
Apr 01, 2021
by
Igor Demin
Committed by
GitHub
Apr 01, 2021
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #88 from JetBrains/fix_blocking_vsync
macOs, Windows. draw in a background thread
parents
b0bcda7b
b207ba16
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
72 additions
and
22 deletions
+72
-22
SkiaLayer.kt
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkiaLayer.kt
+11
-4
SkikoProperties.kt
...src/jvmMain/kotlin/org/jetbrains/skiko/SkikoProperties.kt
+1
-1
Direct3DRedrawer.kt
...n/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt
+17
-5
LinuxOpenGLRedrawer.kt
...otlin/org/jetbrains/skiko/redrawer/LinuxOpenGLRedrawer.kt
+3
-1
MacOsOpenGLRedrawer.kt
...otlin/org/jetbrains/skiko/redrawer/MacOsOpenGLRedrawer.kt
+3
-3
MetalRedrawer.kt
...Main/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt
+28
-5
SoftwareRedrawer.kt
...n/kotlin/org/jetbrains/skiko/redrawer/SoftwareRedrawer.kt
+6
-2
WindowsOpenGLRedrawer.kt
...lin/org/jetbrains/skiko/redrawer/WindowsOpenGLRedrawer.kt
+3
-1
No files found.
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkiaLayer.kt
View file @
ec704f7b
...
@@ -174,7 +174,7 @@ open class SkiaLayer(
...
@@ -174,7 +174,7 @@ open class SkiaLayer(
@Suppress
(
"LeakingThis"
)
@Suppress
(
"LeakingThis"
)
private
val
fpsCounter
=
defaultFPSCounter
(
this
)
private
val
fpsCounter
=
defaultFPSCounter
(
this
)
open
fun
update
(
nanoTime
:
Long
)
{
internal
fun
update
(
nanoTime
:
Long
)
{
check
(!
isDisposed
)
check
(!
isDisposed
)
check
(
isEventDispatchThread
())
check
(
isEventDispatchThread
())
...
@@ -208,14 +208,21 @@ open class SkiaLayer(
...
@@ -208,14 +208,21 @@ open class SkiaLayer(
}
}
}
}
open
fun
draw
()
{
internal
fun
prepareDrawContext
():
Boolean
{
check
(!
isDisposed
)
check
(!
isDisposed
)
contextHandler
?.
apply
{
contextHandler
?.
apply
{
if
(!
initContext
())
{
if
(!
initContext
())
{
fallbackToNextApi
()
fallbackToNextApi
()
return
return
false
}
}
initCanvas
()
initCanvas
()
}
return
true
}
internal
fun
draw
()
{
check
(!
isDisposed
)
contextHandler
?.
apply
{
clearCanvas
()
clearCanvas
()
synchronized
(
pictureLock
)
{
synchronized
(
pictureLock
)
{
val
picture
=
picture
val
picture
=
picture
...
@@ -248,6 +255,6 @@ open class SkiaLayer(
...
@@ -248,6 +255,6 @@ open class SkiaLayer(
redrawer
?.
dispose
()
redrawer
?.
dispose
()
contextHandler
=
createContextHandler
(
this
,
renderApi
)
contextHandler
=
createContextHandler
(
this
,
renderApi
)
redrawer
=
platformOperations
.
createRedrawer
(
this
,
renderApi
,
properties
)
redrawer
=
platformOperations
.
createRedrawer
(
this
,
renderApi
,
properties
)
re
paint
()
re
drawer
!!
.
redrawImmediately
()
}
}
}
}
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/SkikoProperties.kt
View file @
ec704f7b
...
@@ -55,7 +55,7 @@ internal object SkikoProperties {
...
@@ -55,7 +55,7 @@ internal object SkikoProperties {
when
(
hostOs
)
{
when
(
hostOs
)
{
OS
.
Linux
->
renderApiList
=
mutableListOf
(
GraphicsApi
.
OPENGL
,
GraphicsApi
.
SOFTWARE
)
OS
.
Linux
->
renderApiList
=
mutableListOf
(
GraphicsApi
.
OPENGL
,
GraphicsApi
.
SOFTWARE
)
OS
.
MacOS
->
renderApiList
=
mutableListOf
(
GraphicsApi
.
METAL
,
GraphicsApi
.
OPENGL
,
GraphicsApi
.
SOFTWARE
)
OS
.
MacOS
->
renderApiList
=
mutableListOf
(
GraphicsApi
.
METAL
,
GraphicsApi
.
SOFTWARE
)
OS
.
Windows
->
renderApiList
=
mutableListOf
(
GraphicsApi
.
DIRECT3D
,
GraphicsApi
.
OPENGL
,
GraphicsApi
.
SOFTWARE
)
OS
.
Windows
->
renderApiList
=
mutableListOf
(
GraphicsApi
.
DIRECT3D
,
GraphicsApi
.
OPENGL
,
GraphicsApi
.
SOFTWARE
)
}
}
renderApiList
.
remove
(
head
)
renderApiList
.
remove
(
head
)
...
...
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/redrawer/Direct3DRedrawer.kt
View file @
ec704f7b
...
@@ -2,6 +2,7 @@ package org.jetbrains.skiko.redrawer
...
@@ -2,6 +2,7 @@ package org.jetbrains.skiko.redrawer
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.swing.Swing
import
kotlinx.coroutines.swing.Swing
import
kotlinx.coroutines.withContext
import
org.jetbrains.skija.BackendRenderTarget
import
org.jetbrains.skija.BackendRenderTarget
import
org.jetbrains.skija.DirectContext
import
org.jetbrains.skija.DirectContext
import
org.jetbrains.skiko.FrameDispatcher
import
org.jetbrains.skiko.FrameDispatcher
...
@@ -14,13 +15,14 @@ internal class Direct3DRedrawer(
...
@@ -14,13 +15,14 @@ internal class Direct3DRedrawer(
)
:
Redrawer
{
)
:
Redrawer
{
private
var
isDisposed
=
false
private
var
isDisposed
=
false
private
var
disposeLock
=
Any
()
private
val
frameDispatcher
=
FrameDispatcher
(
Dispatchers
.
Swing
)
{
private
val
frameDispatcher
=
FrameDispatcher
(
Dispatchers
.
Swing
)
{
update
(
System
.
nanoTime
())
update
(
System
.
nanoTime
())
draw
()
draw
()
}
}
override
fun
dispose
()
{
override
fun
dispose
()
=
synchronized
(
disposeLock
)
{
frameDispatcher
.
cancel
()
frameDispatcher
.
cancel
()
isDisposed
=
true
isDisposed
=
true
}
}
...
@@ -32,17 +34,27 @@ internal class Direct3DRedrawer(
...
@@ -32,17 +34,27 @@ internal class Direct3DRedrawer(
override
fun
redrawImmediately
()
{
override
fun
redrawImmediately
()
{
check
(!
isDisposed
)
check
(!
isDisposed
)
update
(
System
.
nanoTime
())
// TODO now we wait until previous layer.draw is finished. it ends only on the next vsync.
draw
()
// because of that we lose one frame on resize and can theoretically see very small white bars on the sides of the window
// to avoid this we should be able to draw in two modes: with vsync and without.
frameDispatcher
.
scheduleFrame
()
}
}
private
fun
update
(
nanoTime
:
Long
)
{
private
fun
update
(
nanoTime
:
Long
)
{
layer
.
update
(
nanoTime
)
layer
.
update
(
nanoTime
)
}
}
private
fun
draw
()
{
private
suspend
fun
draw
()
{
if
(
layer
.
prepareDrawContext
())
{
withContext
(
Dispatchers
.
IO
)
{
synchronized
(
disposeLock
)
{
if
(!
isDisposed
)
{
layer
.
draw
()
layer
.
draw
()
}
}
}
}
}
}
fun
makeContext
(
device
:
Long
)
=
DirectContext
(
fun
makeContext
(
device
:
Long
)
=
DirectContext
(
makeDirectXContext
(
device
)
makeDirectXContext
(
device
)
...
...
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/redrawer/LinuxOpenGLRedrawer.kt
View file @
ec704f7b
...
@@ -49,8 +49,10 @@ internal class LinuxOpenGLRedrawer(
...
@@ -49,8 +49,10 @@ internal class LinuxOpenGLRedrawer(
}
}
private
fun
draw
()
{
private
fun
draw
()
{
if
(
layer
.
prepareDrawContext
())
{
layer
.
draw
()
layer
.
draw
()
}
}
}
companion
object
{
companion
object
{
private
val
toRedraw
=
mutableSetOf
<
LinuxOpenGLRedrawer
>()
private
val
toRedraw
=
mutableSetOf
<
LinuxOpenGLRedrawer
>()
...
...
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/redrawer/MacOsOpenGLRedrawer.kt
View file @
ec704f7b
package
org.jetbrains.skiko.redrawer
package
org.jetbrains.skiko.redrawer
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.swing.Swing
import
kotlinx.coroutines.swing.Swing
import
org.jetbrains.skiko.FrameDispatcher
import
org.jetbrains.skiko.FrameDispatcher
import
org.jetbrains.skiko.SkiaLayer
import
org.jetbrains.skiko.SkiaLayer
...
@@ -11,7 +10,6 @@ import org.jetbrains.skiko.Task
...
@@ -11,7 +10,6 @@ import org.jetbrains.skiko.Task
import
org.jetbrains.skiko.useDrawingSurfacePlatformInfo
import
org.jetbrains.skiko.useDrawingSurfacePlatformInfo
import
javax.swing.SwingUtilities.convertPoint
import
javax.swing.SwingUtilities.convertPoint
import
javax.swing.SwingUtilities.getRootPane
import
javax.swing.SwingUtilities.getRootPane
import
kotlin.system.measureNanoTime
// Current implementation is fragile (it works in all tested cases, but we can't test everything)
// Current implementation is fragile (it works in all tested cases, but we can't test everything)
//
//
...
@@ -31,9 +29,11 @@ internal class MacOsOpenGLRedrawer(
...
@@ -31,9 +29,11 @@ internal class MacOsOpenGLRedrawer(
private
val
drawLayer
=
object
:
AWTGLLayer
(
containerLayerPtr
,
setNeedsDisplayOnBoundsChange
=
true
)
{
private
val
drawLayer
=
object
:
AWTGLLayer
(
containerLayerPtr
,
setNeedsDisplayOnBoundsChange
=
true
)
{
override
fun
draw
()
=
synchronized
(
drawLock
)
{
override
fun
draw
()
=
synchronized
(
drawLock
)
{
if
(!
isDisposed
)
{
if
(!
isDisposed
)
{
if
(
layer
.
prepareDrawContext
())
{
layer
.
draw
()
layer
.
draw
()
}
}
}
}
}
suspend
fun
display
()
=
display
(
::
setNeedsDisplay
)
suspend
fun
display
()
=
display
(
::
setNeedsDisplay
)
}
}
...
...
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/redrawer/MetalRedrawer.kt
View file @
ec704f7b
...
@@ -2,6 +2,7 @@ package org.jetbrains.skiko.redrawer
...
@@ -2,6 +2,7 @@ package org.jetbrains.skiko.redrawer
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.swing.Swing
import
kotlinx.coroutines.swing.Swing
import
kotlinx.coroutines.withContext
import
org.jetbrains.skija.BackendRenderTarget
import
org.jetbrains.skija.BackendRenderTarget
import
org.jetbrains.skija.DirectContext
import
org.jetbrains.skija.DirectContext
import
org.jetbrains.skiko.FrameDispatcher
import
org.jetbrains.skiko.FrameDispatcher
...
@@ -16,6 +17,7 @@ internal class MetalRedrawer(
...
@@ -16,6 +17,7 @@ internal class MetalRedrawer(
private
val
properties
:
SkiaLayerProperties
private
val
properties
:
SkiaLayerProperties
)
:
Redrawer
{
)
:
Redrawer
{
private
var
isDisposed
=
false
private
var
isDisposed
=
false
private
var
disposeLock
=
Any
()
private
val
device
=
layer
.
backedLayer
.
useDrawingSurfacePlatformInfo
(
::
createMetalDevice
)
private
val
device
=
layer
.
backedLayer
.
useDrawingSurfacePlatformInfo
(
::
createMetalDevice
)
private
val
frameDispatcher
=
FrameDispatcher
(
Dispatchers
.
Swing
)
{
private
val
frameDispatcher
=
FrameDispatcher
(
Dispatchers
.
Swing
)
{
...
@@ -23,7 +25,7 @@ internal class MetalRedrawer(
...
@@ -23,7 +25,7 @@ internal class MetalRedrawer(
draw
()
draw
()
}
}
override
fun
dispose
()
{
override
fun
dispose
()
=
synchronized
(
disposeLock
)
{
frameDispatcher
.
cancel
()
frameDispatcher
.
cancel
()
disposeDevice
(
device
)
disposeDevice
(
device
)
isDisposed
=
true
isDisposed
=
true
...
@@ -36,17 +38,38 @@ internal class MetalRedrawer(
...
@@ -36,17 +38,38 @@ internal class MetalRedrawer(
override
fun
redrawImmediately
()
{
override
fun
redrawImmediately
()
{
check
(!
isDisposed
)
check
(!
isDisposed
)
update
(
System
.
nanoTime
())
// TODO now we wait until previous layer.draw is finished. it ends only on the next vsync.
draw
()
// because of that we lose one frame on resize and can theoretically see very small white bars on the sides of the window
// to avoid this we should be able to draw in two modes: with vsync and without.
frameDispatcher
.
scheduleFrame
()
}
}
private
fun
update
(
nanoTime
:
Long
)
{
private
fun
update
(
nanoTime
:
Long
)
{
layer
.
update
(
nanoTime
)
layer
.
update
(
nanoTime
)
}
}
private
fun
draw
()
{
private
suspend
fun
draw
()
{
if
(
layer
.
prepareDrawContext
())
{
// 2,3 GHz 8-Core Intel Core i9
//
// Test1. 8 windows, multiple clocks, 800x600
//
// Executors.newSingleThreadExecutor().asCoroutineDispatcher(): 20 FPS, 130% CPU
// Dispatchers.IO: 58 FPS, 460% CPU
//
// Test2. 60 windows, single clock, 800x600
//
// Executors.newSingleThreadExecutor().asCoroutineDispatcher(): 50 FPS, 150% CPU
// Dispatchers.IO: 50 FPS, 200% CPU
withContext
(
Dispatchers
.
IO
)
{
synchronized
(
disposeLock
)
{
if
(!
isDisposed
)
{
layer
.
draw
()
layer
.
draw
()
}
}
}
}
}
}
override
fun
syncSize
()
{
override
fun
syncSize
()
{
val
rootPane
=
getRootPane
(
layer
)
val
rootPane
=
getRootPane
(
layer
)
...
...
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/redrawer/SoftwareRedrawer.kt
View file @
ec704f7b
...
@@ -11,8 +11,10 @@ internal class SoftwareRedrawer(
...
@@ -11,8 +11,10 @@ internal class SoftwareRedrawer(
private
val
frameDispatcher
=
FrameDispatcher
(
Dispatchers
.
Swing
)
{
private
val
frameDispatcher
=
FrameDispatcher
(
Dispatchers
.
Swing
)
{
layer
.
update
(
System
.
nanoTime
())
layer
.
update
(
System
.
nanoTime
())
if
(
layer
.
prepareDrawContext
())
{
layer
.
draw
()
layer
.
draw
()
}
}
}
override
fun
dispose
()
{
override
fun
dispose
()
{
frameDispatcher
.
cancel
()
frameDispatcher
.
cancel
()
...
@@ -24,6 +26,8 @@ internal class SoftwareRedrawer(
...
@@ -24,6 +26,8 @@ internal class SoftwareRedrawer(
override
fun
redrawImmediately
()
{
override
fun
redrawImmediately
()
{
layer
.
update
(
System
.
nanoTime
())
layer
.
update
(
System
.
nanoTime
())
if
(
layer
.
prepareDrawContext
())
{
layer
.
draw
()
layer
.
draw
()
}
}
}
}
}
\ No newline at end of file
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/redrawer/WindowsOpenGLRedrawer.kt
View file @
ec704f7b
...
@@ -53,8 +53,10 @@ internal class WindowsOpenGLRedrawer(
...
@@ -53,8 +53,10 @@ internal class WindowsOpenGLRedrawer(
}
}
private
fun
draw
()
{
private
fun
draw
()
{
if
(
layer
.
prepareDrawContext
())
{
layer
.
draw
()
layer
.
draw
()
}
}
}
private
fun
makeCurrent
()
=
makeCurrent
(
device
,
context
)
private
fun
makeCurrent
()
=
makeCurrent
(
device
,
context
)
private
fun
swapBuffers
()
=
swapBuffers
(
device
)
private
fun
swapBuffers
()
=
swapBuffers
(
device
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment