Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bidirectional IPC packets, support view tree operations for external debugger, support for offscreen GameWindow and rendering and initial incremental compilation without Gradle for faster, more-stable hot reloading #2249

Merged
merged 19 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/DEPLOY.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ env:

jobs:
publish:
runs-on: macos-11
runs-on: macos-latest
steps:
- { name: Checkout, uses: actions/checkout@v3 }
- { name: Use Node.js 20.x, uses: actions/setup-node@v3, with: { node-version: 20.x } }
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/TEST.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ jobs:
fail-fast: false # Once working, comment this
matrix:
include:
- { outputKey: testIos, os: macos-11, testTask: iosX64Test, precompileTask: compileTestKotlinIosX64, enableKotlinNative: true }
- { outputKey: testIos, os: macos-latest, testTask: iosX64Test, precompileTask: compileTestKotlinIosX64, enableKotlinNative: true }
- { outputKey: testJs, os: ubuntu-latest, testTask: "wasmJsBrowserTest", buildTasks: "jsBrowserTest", precompileTask: "wasmJsTestClasses jsTestClasses" }
- { outputKey: testAndroid, os: ubuntu-latest, enableAndroid: true, precompileTask: "compileDebugAndroidTestSources" }
- { outputKey: testJvmMacos, os: macos-11, testTask: jvmTest, precompileTask: "compileTestKotlinJvm compileTestKotlin" }
- { outputKey: testJvmMacos, os: macos-latest, testTask: jvmTest, precompileTask: "compileTestKotlinJvm compileTestKotlin" }
- { outputKey: testJvmLinux, os: ubuntu-latest, testTask: jvmTest, precompileTask: "compileTestKotlinJvm compileTestKotlin", enableKotlinNative: true, enableSandbox: true, e2e: true }
- { outputKey: testJvmWindows, os: windows-latest, testTask: jvmTest, precompileTask: "compileTestKotlinJvm compileTestKotlin" }
#if: ${{ needs.changes.outputs[matrix.outputKey] == 'true' }}
Expand Down
9 changes: 9 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import korlibs.root.*
import org.jetbrains.kotlin.backend.common.serialization.*
import org.jetbrains.kotlin.gradle.tasks.*

plugins {
//id "com.dorongold.task-tree" version "2.1.1"
Expand Down Expand Up @@ -91,3 +93,10 @@ tasks {
)
}
}

afterEvaluate {
println("-----------")
println(tasks.findByPath(":korge:jvmMainClasses")!!::class)
println(tasks.findByPath(":korge:compileKotlinJvm")!!::class)
//org.jetbrains.kotlin.gradle.tasks.KotlinCompile
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ const val ANDROID_DEFAULT_MIN_SDK = 21 // Android 5.0
const val ANDROID_DEFAULT_COMPILE_SDK = 33
const val ANDROID_DEFAULT_TARGET_SDK = 33

val GRADLE_JAVA_VERSION_STR = "11"
//val GRADLE_JAVA_VERSION_STR = "11"
val GRADLE_JAVA_VERSION_STR = "17"

val ANDROID_JAVA_VERSION = JavaVersion.VERSION_1_8
//val ANDROID_JAVA_VERSION = JavaVersion.VERSION_11
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ open class KorgeJavaExecWithAutoreload : KorgeJavaExec() {
)

environment("KORGE_AUTORELOAD", "true")

environment("KORGE_IPC", project.findProperty("korge.ipc")?.toString())
environment("KORGE_HEADLESS", project.findProperty("korge.headless")?.toString())
}
}
}
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/korlibs/root/RootKorlibsPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ fun Project.mustAutoconfigureKMM(): Boolean =
project.name != "korge-kotlin-plugin" &&
project.name != "korge-reload-agent" &&
project.name != "korge-ipc" &&
project.name != "korge-kotlin-compiler" &&
project.name != "korge-benchmarks" &&
project.hasBuildGradle()

Expand Down
4 changes: 4 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ korlibs-inject = { module = "com.soywiz:korlibs-inject", version.ref = "korlibs"
korlibs-template = { module = "com.soywiz:korlibs-template", version.ref = "korlibs" }
korlibs-time = { module = "com.soywiz:korlibs-time", version.ref = "korlibs" }
korlibs-serialization = { module = "com.soywiz:korlibs-serialization", version.ref = "korlibs" }
korlibs-datastructure = { module = "com.soywiz:korlibs-datastructure", version.ref = "korlibs" }
korlibs-datastructure-core = { module = "com.soywiz:korlibs-datastructure-core", version.ref = "korlibs" }
korlibs-memory = { module = "com.soywiz:korlibs-memory", version.ref = "korlibs" }
korlibs-io-stream = { module = "com.soywiz:korlibs-io-stream", version.ref = "korlibs" }
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
junit = { module = "junit:junit", version.ref = "junit" }
Expand Down
3 changes: 2 additions & 1 deletion korge-core/src/korlibs/event/Events.kt
Original file line number Diff line number Diff line change
Expand Up @@ -465,14 +465,15 @@ data class ChangeEvent(var oldValue: Any? = null, var newValue: Any? = null) : T
}
}

data class ReshapeEvent(var x: Int = 0, var y: Int = 0, var width: Int = 0, var height: Int = 0) : TypedEvent<ReshapeEvent>(ReshapeEvent) {
data class ReshapeEvent(var x: Int = 0, var y: Int = 0, var width: Int = 0, var height: Int = 0, var setPos: Boolean = true) : TypedEvent<ReshapeEvent>(ReshapeEvent) {
companion object : EventType<ReshapeEvent>

fun copyFrom(other: ReshapeEvent) {
this.x = other.x
this.y = other.y
this.width = other.width
this.height = other.height
this.setPos = other.setPos
}
}

Expand Down
66 changes: 64 additions & 2 deletions korge-core/src/korlibs/kgl/KmlGlContext.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,71 @@
package korlibs.kgl

import korlibs.io.lang.*

expect fun KmlGlContextDefault(window: Any? = null, parent: KmlGlContext? = null): KmlGlContext

class OffscreenKmlGlContext(
val colorRenderbuffer: Int,
val depthRenderbuffer: Int,
val framebuffer: Int,
val ctx: KmlGlContext,
var width: Int = 0,
var height: Int = 0,
) {
val gl get() = ctx.gl

fun setSize(width: Int, height: Int) {
this.width = width
this.height = height

val GL_RGBA8 = 0x8058

gl.bindRenderbuffer(KmlGl.RENDERBUFFER, colorRenderbuffer)
gl.renderbufferStorage(KmlGl.RENDERBUFFER, GL_RGBA8, width, height)
gl.bindRenderbuffer(KmlGl.RENDERBUFFER, 0)

// Build the texture that will serve as the depth attachment for the framebuffer.
gl.bindRenderbuffer(KmlGl.RENDERBUFFER, depthRenderbuffer)
gl.renderbufferStorage(KmlGl.RENDERBUFFER, KmlGl.DEPTH_COMPONENT, width, height)
gl.bindRenderbuffer(KmlGl.RENDERBUFFER, 0)
}

fun doClear() {
gl.bindFramebuffer(KmlGl.FRAMEBUFFER, framebuffer)
gl.clear(KmlGl.COLOR_BUFFER_BIT or KmlGl.DEPTH_BUFFER_BIT)
}
}

fun OffsetKmlGlContext(fboWidth: Int, fboHeight: Int, doUnset: Boolean = true): KmlGlContext {
return NewOffsetKmlGlContext(fboWidth, fboHeight, doUnset).ctx
}

fun NewOffsetKmlGlContext(fboWidth: Int, fboHeight: Int, doUnset: Boolean = true): OffscreenKmlGlContext {
val ctx = KmlGlContextDefault()
ctx.set()

val gl = ctx.gl

// Build the texture that will serve as the color attachment for the framebuffer.
val colorRenderbuffer = gl.genRenderbuffer()
val depthRenderbuffer = gl.genRenderbuffer()
val framebuffer = gl.genFramebuffer()
val out = OffscreenKmlGlContext(colorRenderbuffer, depthRenderbuffer, framebuffer, ctx)

out.setSize(fboWidth, fboHeight)

// Build the framebuffer.
gl.bindFramebuffer(KmlGl.FRAMEBUFFER, framebuffer)
gl.framebufferRenderbuffer(KmlGl.FRAMEBUFFER, KmlGl.COLOR_ATTACHMENT0, KmlGl.RENDERBUFFER, colorRenderbuffer)
gl.framebufferRenderbuffer(KmlGl.FRAMEBUFFER, KmlGl.DEPTH_ATTACHMENT, KmlGl.RENDERBUFFER, depthRenderbuffer)

val status = gl.checkFramebufferStatus(KmlGl.FRAMEBUFFER)
//if (status != GL_FRAMEBUFFER_COMPLETE)
// Error

if (doUnset) ctx.unset()

return out
}

inline fun KmlGlContextDefaultTemp(block: (KmlGl) -> Unit) {
KmlGlContextDefault().use {
it.set()
Expand Down
32 changes: 26 additions & 6 deletions korge-core/src/korlibs/render/GameWindow.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package korlibs.render

import korlibs.concurrent.lock.*
import korlibs.concurrent.thread.*
import korlibs.datastructure.*
import korlibs.event.*
import korlibs.graphics.*
Expand Down Expand Up @@ -261,6 +262,9 @@ open class GameWindow :
return onEvent(RenderEvent, block)
}

val fastCounterTimePerFrame: FastDuration get() = (1_000_000.0 / fps).fastMicroseconds
val fastTimePerFrame: FastDuration get() = fastCounterTimePerFrame

val counterTimePerFrame: Duration get() = (1_000_000.0 / fps).microseconds
val timePerFrame: Duration get() = counterTimePerFrame

Expand Down Expand Up @@ -390,11 +394,27 @@ open class GameWindow :
launchImmediately(getCoroutineDispatcherWithCurrentContext()) {
entry()
}
while (running) {
val elapsed = frame()
val available = counterTimePerFrame - elapsed
if (available > TimeSpan.ZERO) delay(available)
}
//withContext(getCoroutineDispatcherWithCurrentContext()) {
//delay(1L)
while (running) {
var elapsed: FastDuration
val realElapsed = measureTime {
elapsed = frame()
}
val available = fastCounterTimePerFrame - elapsed
//val available = fastCounterTimePerFrame - realElapsed
if (available > FastDuration.ZERO) {
//println("delay=$available, elapsed=$elapsed, realElapsed=$realElapsed, fastCounterTimePerFrame=$fastCounterTimePerFrame")
loopDelay(available)
//NativeThread.sleepExact(available)
//NativeThread.sleepExact(available)
}
}
//}
}

open suspend fun loopDelay(time: FastDuration) {
delay(time)
}

// Referenced from korge-plugins repo
Expand Down Expand Up @@ -567,7 +587,7 @@ open class GameWindow :
dispatchReshapeEventEx(x, y, width, height, width, height)
}

fun dispatchReshapeEventEx(x: Int, y: Int, width: Int, height: Int, fullWidth: Int, fullHeight: Int) {
fun dispatchReshapeEventEx(x: Int, y: Int, width: Int, height: Int, fullWidth: Int = width, fullHeight: Int = height) {
ag.mainFrameBuffer.setSize(x, y, width, height, fullWidth, fullHeight)
dispatch(reshapeEvent.reset {
this.x = x
Expand Down
6 changes: 5 additions & 1 deletion korge-core/src@jvm/korlibs/render/DefaultGameWindowJvm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package korlibs.render
import korlibs.graphics.*
import korlibs.render.awt.*

actual fun CreateDefaultGameWindow(config: GameWindowCreationConfig): GameWindow = AwtGameWindow(config)
actual fun CreateDefaultGameWindow(config: GameWindowCreationConfig): GameWindow = when {
System.getenv("KORGE_HEADLESS") == "true" -> AwtOffscreenGameWindow(config)
else -> AwtGameWindow(config)
}

object JvmAGFactory : AGFactory {
override val supportsNativeFrame: Boolean = true
Expand All @@ -19,3 +22,4 @@ object JvmAGFactory : AGFactory {
}
}
}

57 changes: 57 additions & 0 deletions korge-core/src@jvm/korlibs/render/awt/AwtOffscreenGameWindow.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package korlibs.render.awt

import korlibs.concurrent.thread.*
import korlibs.graphics.gl.*
import korlibs.kgl.*
import korlibs.math.geom.*
import korlibs.render.*
import korlibs.time.*

class AwtOffscreenGameWindow(
var size: Size = Size(640, 480),
val context: OffscreenKmlGlContext = NewOffsetKmlGlContext(size.width.toInt(), size.height.toInt(), doUnset = true),
val draw: Boolean = false,
override val ag: AGOpengl = AGOpenglAWT(context = context.ctx),
exitProcessOnClose: Boolean = false,
override var devicePixelRatio: Double = 1.0,
) : GameWindow() {
constructor(
config: GameWindowCreationConfig,
size: Size = Size(640, 480),
context: OffscreenKmlGlContext = NewOffsetKmlGlContext(size.width.toInt(), size.height.toInt(), doUnset = true),
) : this(
size = size,
//draw = config.draw,
context = context,
ag = AGOpenglAWT(config, context.ctx),
//exitProcessOnClose = config.exitProcessOnClose,
//devicePixelRatio = config.devicePixelRatio
)

override val width: Int get() = context.width
override val height: Int get() = context.height

init {
this.exitProcessOnClose = exitProcessOnClose
//onEvent(ReshapeEvent) {
// context.setSize(it.width, it.height)
// //size = Size(it.width.toDouble(), it.height.toDouble())
//}
}

override fun setSize(width: Int, height: Int) {
val rwidth = (width * devicePixelRatio).toInt()
val rheight = (height * devicePixelRatio).toInt()
//println("OFFSCREEN: setSize: $width, $height")
context.setSize(rwidth, rheight)
context.doClear()
dispatchReshapeEvent(0, 0, rwidth, rheight)
}

override suspend fun loopDelay(time: FastDuration) {
NativeThread.sleepExact(time)
}

//override val ag: AG = if (draw) AGSoftware(width, height) else DummyAG(width, height)
//override val ag: AG = AGDummy(width, height)
}
9 changes: 8 additions & 1 deletion korge-ipc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import korlibs.root.*

plugins {
//id "kotlin" version "1.6.21"
id("kotlin")
kotlin("jvm")
//kotlin("plugin.serialization")
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0"
//id "org.jetbrains.kotlin.jvm"
id("maven-publish")
}
Expand Down Expand Up @@ -56,6 +58,11 @@ korlibs.NativeTools.groovyConfigurePublishing(project, false)
korlibs.NativeTools.groovyConfigureSigning(project)

dependencies {
//implementation(libs.kotlinx.coroutines.core)
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0")
implementation(libs.korlibs.datastructure.core)
implementation(libs.korlibs.memory)
implementation(libs.korlibs.io.stream)
testImplementation(libs.bundles.kotlin.test)
}

Expand Down
Loading