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
c5bc301e
Commit
c5bc301e
authored
Feb 03, 2021
by
Igor Demin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MacOsOpenGLRedrawer. Refactor Task, use Channel instead of CompletableDeferred
parent
a306eae8
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
242 additions
and
26 deletions
+242
-26
build.gradle.kts
skiko/build.gradle.kts
+12
-1
Task.kt
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/Task.kt
+28
-0
MacOsOpenGLRedrawer.kt
...otlin/org/jetbrains/skiko/redrawer/MacOsOpenGLRedrawer.kt
+2
-25
TaskTest.kt
skiko/src/jvmTest/kotlin/org/jetbrains/skiko/TaskTest.kt
+200
-0
No files found.
skiko/build.gradle.kts
View file @
c5bc301e
import
de.undercouch.gradle.tasks.download.Download
import
de.undercouch.gradle.tasks.download.Download
import
org.gradle.crypto.checksum.Checksum
import
org.gradle.crypto.checksum.Checksum
import
org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import
org.jetbrains.kotlin.gradle.tasks.KotlinTest
plugins
{
plugins
{
kotlin
(
"multiplatform"
)
version
"1.3.72"
kotlin
(
"multiplatform"
)
version
"1.3.72"
...
@@ -9,6 +11,8 @@ plugins {
...
@@ -9,6 +11,8 @@ plugins {
id
(
"de.undercouch.download"
)
version
"4.1.1"
id
(
"de.undercouch.download"
)
version
"4.1.1"
}
}
val
coroutinesVersion
=
"1.4.1"
buildscript
{
buildscript
{
dependencies
{
dependencies
{
classpath
(
"org.kohsuke:github-api:1.116"
)
classpath
(
"org.kohsuke:github-api:1.116"
)
...
@@ -166,7 +170,7 @@ kotlin {
...
@@ -166,7 +170,7 @@ kotlin {
kotlin
.
srcDirs
(
skijaSrcDir
)
kotlin
.
srcDirs
(
skijaSrcDir
)
dependencies
{
dependencies
{
implementation
(
kotlin
(
"stdlib-jdk8"
))
implementation
(
kotlin
(
"stdlib-jdk8"
))
implementation
(
"org.jetbrains.kotlinx:kotlinx-coroutines-swing:
1.4.1
"
)
implementation
(
"org.jetbrains.kotlinx:kotlinx-coroutines-swing:
$coroutinesVersion
"
)
compileOnly
(
lombok
)
compileOnly
(
lombok
)
compileOnly
(
jetbrainsAnnotations
)
compileOnly
(
jetbrainsAnnotations
)
}
}
...
@@ -174,6 +178,7 @@ kotlin {
...
@@ -174,6 +178,7 @@ kotlin {
}
}
val
jvmTest
by
getting
{
val
jvmTest
by
getting
{
dependencies
{
dependencies
{
implementation
(
"org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"
)
implementation
(
kotlin
(
"test-junit"
))
implementation
(
kotlin
(
"test-junit"
))
}
}
}
}
...
@@ -565,3 +570,9 @@ publishing {
...
@@ -565,3 +570,9 @@ publishing {
}
}
}
}
}
}
tasks
.
withType
<
KotlinCompile
>().
configureEach
{
if
(
name
==
"compileTestKotlinJvm"
)
{
kotlinOptions
.
freeCompilerArgs
+=
"-Xopt-in=kotlin.RequiresOptIn"
}
}
\ No newline at end of file
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/Task.kt
0 → 100644
View file @
c5bc301e
package
org.jetbrains.skiko
import
kotlinx.coroutines.channels.Channel
import
java.util.concurrent.atomic.AtomicBoolean
internal
class
Task
{
private
val
onFinish
=
Channel
<
Unit
>(
1
)
private
var
done
=
AtomicBoolean
(
true
)
/**
* Run task and await its finishing (i.e. calling of [finish])
*/
suspend
fun
runAndAwait
(
run
:
suspend
()
->
Unit
)
{
done
.
set
(
false
)
run
()
onFinish
.
receive
()
}
/**
* Finish running task. If there is no running task, do nothing.
*/
fun
finish
()
{
if
(!
done
.
getAndSet
(
true
))
{
onFinish
.
offer
(
Unit
)
}
}
}
\ No newline at end of file
skiko/src/jvmMain/kotlin/org/jetbrains/skiko/redrawer/MacOsOpenGLRedrawer.kt
View file @
c5bc301e
package
org.jetbrains.skiko.redrawer
package
org.jetbrains.skiko.redrawer
import
kotlinx.coroutines.CompletableDeferred
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.swing.Swing
import
kotlinx.coroutines.swing.Swing
import
org.jetbrains.skiko.FrameDispatcher
import
org.jetbrains.skiko.FrameDispatcher
import
org.jetbrains.skiko.HardwareLayer
import
org.jetbrains.skiko.HardwareLayer
import
org.jetbrains.skiko.OpenGLApi
import
org.jetbrains.skiko.OpenGLApi
import
org.jetbrains.skiko.SkikoProperties
import
org.jetbrains.skiko.SkikoProperties
import
org.jetbrains.skiko.Task
import
javax.swing.SwingUtilities.convertPoint
import
javax.swing.SwingUtilities.convertPoint
import
javax.swing.SwingUtilities.getRootPane
import
javax.swing.SwingUtilities.getRootPane
...
@@ -165,26 +165,3 @@ private external fun initContainer(layer: HardwareLayer): Long
...
@@ -165,26 +165,3 @@ private external fun initContainer(layer: HardwareLayer): Long
private
external
fun
setContentScale
(
layerNativePtr
:
Long
,
contentScale
:
Float
)
private
external
fun
setContentScale
(
layerNativePtr
:
Long
,
contentScale
:
Float
)
private
external
fun
initAWTGLLayer
(
containerPtr
:
Long
,
layer
:
AWTGLLayer
,
setNeedsDisplayOnBoundsChange
:
Boolean
):
Long
private
external
fun
initAWTGLLayer
(
containerPtr
:
Long
,
layer
:
AWTGLLayer
,
setNeedsDisplayOnBoundsChange
:
Boolean
):
Long
private
external
fun
disposeAWTGLLayer
(
ptr
:
Long
)
private
external
fun
disposeAWTGLLayer
(
ptr
:
Long
)
\ No newline at end of file
internal
class
Task
{
@Volatile
private
var
onFinish
:
CompletableDeferred
<
Unit
>?
=
null
/**
* Run task and await its finishing (i.e. calling of [finish])
*/
suspend
fun
runAndAwait
(
run
:
suspend
()
->
Unit
)
{
check
(
onFinish
==
null
)
onFinish
=
CompletableDeferred
()
run
()
onFinish
!!
.
await
()
onFinish
=
null
}
/**
* Finish running task. If there is no running task, do nothing.
*/
fun
finish
()
{
onFinish
?.
complete
(
Unit
)
}
}
\ No newline at end of file
skiko/src/jvmTest/kotlin/org/jetbrains/skiko/TaskTest.kt
0 → 100644
View file @
c5bc301e
package
org.jetbrains.skiko
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.ExperimentalCoroutinesApi
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.asCoroutineDispatcher
import
kotlinx.coroutines.isActive
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.runBlocking
import
kotlinx.coroutines.test.TestCoroutineScope
import
kotlinx.coroutines.test.runBlockingTest
import
kotlinx.coroutines.yield
import
org.junit.Assert.assertFalse
import
org.junit.Assert.assertTrue
import
org.junit.Test
import
java.util.concurrent.Executors.newSingleThreadExecutor
import
java.util.concurrent.atomic.AtomicBoolean
import
kotlin.random.Random
@OptIn
(
ExperimentalCoroutinesApi
::
class
)
internal
class
TaskTest
{
@Test
fun
`
runAndAwait
with
finish
`
()
=
test
{
val
task
=
Task
()
val
job
=
launch
{
task
.
runAndAwait
{}
}
advanceUntilIdle
()
task
.
finish
()
advanceUntilIdle
()
assertTrue
(
job
.
isCompleted
)
}
@Test
fun
`
runAndAwait
without
finish
`
()
=
test
{
val
task
=
Task
()
val
job
=
launch
{
task
.
runAndAwait
{}
}
advanceUntilIdle
()
assertFalse
(
job
.
isCompleted
)
}
@Test
fun
`
finish
inside
runAndAwait
`
()
=
test
{
val
task
=
Task
()
val
job
=
launch
{
task
.
runAndAwait
{
task
.
finish
()
}
}
advanceUntilIdle
()
assertTrue
(
job
.
isCompleted
)
}
@Test
fun
`
finish
before
runAndAwait
`
()
=
test
{
val
task
=
Task
()
val
job
=
launch
{
task
.
finish
()
task
.
runAndAwait
{}
}
advanceUntilIdle
()
assertFalse
(
job
.
isCompleted
)
}
@Test
(
timeout
=
5000
)
fun
`
finish
in
another
thread
`
()
{
val
task
=
Task
()
runBlocking
{
repeat
(
1000
)
{
task
.
runAndAwait
{
launch
(
Dispatchers
.
IO
)
{
task
.
finish
()
}
}
}
}
}
@Test
(
timeout
=
5000
)
fun
`
simulate
MacOs
layer
`
()
{
runBlocking
{
val
job
=
Job
()
val
layer
=
object
:
MacOsSimulatedLayer
(
scope
=
CoroutineScope
(
coroutineContext
+
job
))
{
val
draw
=
Task
()
override
fun
draw
()
{
draw
.
finish
()
}
suspend
fun
display
()
{
draw
.
runAndAwait
{
setNeedsDisplay
()
}
}
}
repeat
(
10000
)
{
layer
.
display
()
}
job
.
cancel
()
}
}
@Test
(
timeout
=
5000
)
fun
`
simulate
MacOs
layer
with
another
renderings
`
()
{
runBlocking
{
val
job
=
Job
()
val
layer
=
object
:
MacOsSimulatedLayer
(
scope
=
CoroutineScope
(
coroutineContext
+
job
))
{
val
draw
=
Task
()
override
fun
draw
()
{
draw
.
finish
()
}
suspend
fun
display
()
{
draw
.
runAndAwait
{
setNeedsDisplay
()
}
}
}
val
random
=
Random
(
42
)
val
anotherRenderingsJob1
=
launch
(
newSingleThreadExecutor
().
asCoroutineDispatcher
())
{
while
(
true
)
{
repeat
(
random
.
nextInt
(
4
))
{
layer
.
setNeedsDisplay
()
}
yield
()
}
}
val
anotherRenderingsJob2
=
launch
(
newSingleThreadExecutor
().
asCoroutineDispatcher
())
{
while
(
true
)
{
repeat
(
random
.
nextInt
(
4
))
{
layer
.
setNeedsDisplay
()
}
yield
()
}
}
repeat
(
10000
)
{
layer
.
display
()
}
job
.
cancel
()
anotherRenderingsJob1
.
cancel
()
anotherRenderingsJob2
.
cancel
()
}
}
private
abstract
class
MacOsSimulatedLayer
(
scope
:
CoroutineScope
)
{
private
val
dispatcher
=
newSingleThreadExecutor
().
asCoroutineDispatcher
()
private
var
needsDisplay
=
AtomicBoolean
(
false
)
init
{
scope
.
launch
(
dispatcher
)
{
while
(
isActive
)
{
if
(
needsDisplay
.
getAndSet
(
false
))
{
draw
()
}
yield
()
}
}
}
abstract
fun
draw
()
fun
setNeedsDisplay
()
{
needsDisplay
.
set
(
true
)
}
}
private
fun
test
(
block
:
suspend
TestCoroutineScope
.()
->
Unit
)
=
runBlockingTest
{
pauseDispatcher
()
val
job
=
Job
()
TestCoroutineScope
(
coroutineContext
+
job
).
block
()
job
.
cancel
()
}
}
\ No newline at end of file
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