Unverified Commit 8cde16e1 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

iOS cross-compilation support (#236)

parent d0a425f4
...@@ -12,7 +12,7 @@ repositories { ...@@ -12,7 +12,7 @@ repositories {
} }
val osName = System.getProperty("os.name") val osName = System.getProperty("os.name")
val targetOs = when { val hostOs = when {
osName == "Mac OS X" -> "macos" osName == "Mac OS X" -> "macos"
osName.startsWith("Win") -> "windows" osName.startsWith("Win") -> "windows"
osName.startsWith("Linux") -> "linux" osName.startsWith("Linux") -> "linux"
...@@ -20,13 +20,13 @@ val targetOs = when { ...@@ -20,13 +20,13 @@ val targetOs = when {
} }
val osArch = System.getProperty("os.arch") val osArch = System.getProperty("os.arch")
var targetArch = when (osArch) { var hostArch = when (osArch) {
"x86_64", "amd64" -> "x64" "x86_64", "amd64" -> "x64"
"aarch64" -> "arm64" "aarch64" -> "arm64"
else -> error("Unsupported arch: $osArch") else -> error("Unsupported arch: $osArch")
} }
val target = "${targetOs}-${targetArch}" val host = "${hostOs}-${hostArch}"
var version = "0.0.0-SNAPSHOT" var version = "0.0.0-SNAPSHOT"
if (project.hasProperty("skiko.version")) { if (project.hasProperty("skiko.version")) {
...@@ -34,20 +34,30 @@ if (project.hasProperty("skiko.version")) { ...@@ -34,20 +34,30 @@ if (project.hasProperty("skiko.version")) {
} }
kotlin { kotlin {
val nativeTarget = when (target) { val targets = mutableListOf<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>()
val nativeHostTarget = when (host) {
"macos-x64" -> macosX64() "macos-x64" -> macosX64()
"macos-arm64" -> macosArm64() "macos-arm64" -> macosArm64()
else -> throw GradleException("Host OS is not supported in Kotlin/Native.") else -> throw GradleException("Host OS is not supported yet")
} }
nativeTarget.apply { targets.add(nativeHostTarget)
if (hostOs == "macos") {
targets.add(iosX64())
targets.add(iosArm64())
}
targets.forEach {
it.apply {
binaries { binaries {
executable { executable {
entryPoint = "org.jetbrains.skiko.sample.native.main" entryPoint = "org.jetbrains.skiko.sample.main"
freeCompilerArgs += listOf("-linker-options", "-framework", "-linker-option", "Metal") freeCompilerArgs += listOf("-linker-options", "-framework", "-linker-option", "Metal")
} }
} }
} }
}
sourceSets { sourceSets {
val commonMain by getting { val commonMain by getting {
...@@ -61,20 +71,54 @@ kotlin { ...@@ -61,20 +71,54 @@ kotlin {
dependsOn(commonMain) dependsOn(commonMain)
} }
val archTargetMain = when (target) { val macosMain by creating {
dependsOn(nativeMain)
}
val archTargetMain = when (host) {
"macos-x64" -> { "macos-x64" -> {
val macosX64Main by getting { val macosX64Main by getting {
dependsOn(nativeMain) dependsOn(macosMain)
} }
macosX64Main macosX64Main
} }
"macos-arm64" -> { "macos-arm64" -> {
val macosArm64Main by getting { val macosArm64Main by getting {
dependsOn(nativeMain) dependsOn(macosMain)
} }
macosArm64Main macosArm64Main
} }
else -> throw GradleException("Host OS is not supported in Kotlin/Native.") else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
} }
if (hostOs == "macos") {
val iosMain by creating {
dependsOn(nativeMain)
}
val iosX64Main by getting {
dependsOn(iosMain)
}
val iosArm64Main by getting {
dependsOn(iosMain)
}
}
}
}
project.tasks.register<Exec>("runIosSim") {
val device = "iPhone 11"
workingDir = project.buildDir
val binTask = project.tasks.named("linkReleaseExecutableIosX64")
dependsOn(binTask)
commandLine = listOf(
"xcrun",
"simctl",
"spawn",
"--standalone",
device
)
argumentProviders.add {
val out = fileTree(binTask.get().outputs.files.files.single()) { include("*.kexe") }
listOf(out.single { it.name.endsWith(".kexe") }.absolutePath)
} }
} }
package org.jetbrains.skiko.sample
import org.jetbrains.skia.*
fun main() {
val paint = Paint().apply { color = Color.GREEN }
println("HI: $paint")
}
package org.jetbrains.skiko.sample.native package org.jetbrains.skiko.sample
import platform.AppKit.* import platform.AppKit.*
...@@ -25,7 +25,7 @@ fun createWindow(title: String) { ...@@ -25,7 +25,7 @@ fun createWindow(title: String) {
var angle = 0.0f var angle = 0.0f
window.layer.renderer = Renderer(window.layer) { window.layer.renderer = Renderer(window.layer) {
renderer, w, h, nanoTime -> displayScene(renderer, nanoTime) renderer, w, h, nanoTime -> displayScene(renderer.canvas!!, nanoTime)
} }
window.nsWindow.orderFrontRegardless() window.nsWindow.orderFrontRegardless()
...@@ -46,18 +46,3 @@ class Renderer( ...@@ -46,18 +46,3 @@ class Renderer(
} }
} }
fun displayScene(renderer: Renderer, nanoTime: Long) {
val canvas = renderer.canvas!!
val paint = Paint().apply { color = Color.GREEN}
canvas.clear(Color.RED)
canvas.save();
canvas.translate(128.0f, 128.0f)
canvas.rotate(nanoTime.toFloat() / 1e7f)
val rect = Rect.makeXYWH(-90.5f, -90.5f, 181.0f, 181.0f)
canvas.drawRect(rect, paint)
canvas.restore();
}
package org.jetbrains.skiko.sample
import org.jetbrains.skia.*
fun displayScene(canvas: Canvas, nanoTime: Long) {
val paint = Paint().apply { color = Color.GREEN }
canvas.clear(Color.RED)
canvas.save();
canvas.translate(128.0f, 128.0f)
canvas.rotate(nanoTime.toFloat() / 1e7f)
val rect = Rect.makeXYWH(-90.5f, -90.5f, 181.0f, 181.0f)
canvas.drawRect(rect, paint)
canvas.restore();
}
...@@ -54,9 +54,19 @@ val skiaZip = run { ...@@ -54,9 +54,19 @@ val skiaZip = run {
} }
val crossTargets = listOf( val crossTargets = listOf(
OS.Wasm to Arch.Wasm OS.Wasm to Arch.Wasm,
OS.IOS to Arch.X64,
OS.IOS to Arch.Arm64,
OS.MacOS to Arch.X64,
OS.MacOS to Arch.Arm64,
) )
class NativeCompilationInfo(val target: org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget) {
var linkTask: Provider<Exec>? = null
}
val allNativeTargets = mutableMapOf<Pair<OS, Arch>, NativeCompilationInfo>()
val skiaCrossDownloadTasks: Map<Pair<OS, Arch>, Provider<File>> = crossTargets.keysToMap { osArch -> val skiaCrossDownloadTasks: Map<Pair<OS, Arch>, Provider<File>> = crossTargets.keysToMap { osArch ->
val suffix = targetSuffix(osArch.first, osArch.second) val suffix = targetSuffix(osArch.first, osArch.second)
val out = skiko.dependenciesDir.resolve("skia/skia-$suffix.zip") val out = skiko.dependenciesDir.resolve("skia/skia-$suffix.zip")
...@@ -122,6 +132,76 @@ val wasmCrossCompile = tasks.register<CrossCompileTask>("wasmCrossCompile") { ...@@ -122,6 +132,76 @@ val wasmCrossCompile = tasks.register<CrossCompileTask>("wasmCrossCompile") {
)) ))
} }
fun registerNativeBridgesTask(os: OS, arch: Arch): TaskProvider<CrossCompileTask> {
return tasks.register<CrossCompileTask>("${os.id}_${arch.id}_CrossCompile") {
val osArch = os to arch
val unzipper = skiaDirProviderForCrossTargets[osArch]!!
dependsOn(unzipper)
val unpackedSkia = unzipper.get()
compiler.set("clang++")
when (os) {
OS.IOS -> {
val sdkRoot = "/Applications/Xcode.app/Contents/Developer/Platforms"
val iosFlags = listOf(
"-std=c++17",
"-stdlib=libc++",
"-DSK_SHAPER_CORETEXT_AVAILABLE",
"-DSK_BUILD_FOR_IOS",
"-DSK_METAL",
"-DSK_SUPPORT_GPU=1"
)
when (arch) {
Arch.Arm64 ->
flags.set(
listOf(
"-target", "arm64-apple-ios",
"-isysroot", "$sdkRoot/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
) +
iosFlags +
skiaPreprocessorFlags()
)
Arch.X64 -> flags.set(
listOf(
"-target", "x86_64-apple-ios-simulator",
"-isysroot", "$sdkRoot/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk")
+ iosFlags
+ skiaPreprocessorFlags()
)
else -> throw GradleException("Unsupported arch: $arch")
}
}
OS.MacOS -> {
flags.set(listOf(
"-std=c++17",
"-DSK_SHAPER_CORETEXT_AVAILABLE",
"-DSK_BUILD_FOR_MAC",
"-DSK_METAL",
"-DSK_SUPPORT_GPU=1",
*skiaPreprocessorFlags()
))
}
}
crossCompileTargetOS.set(osArch.first)
crossCompileTargetArch.set(osArch.second)
buildVariant.set(buildType)
sourceFiles =
project.fileTree("src/nativeMain/cpp") { include("**/*.cc") } +
project.fileTree("src/commonMain/cpp") { include("**/*.cc") }
if (skiko.includeTestHelpers) {
sourceFiles += project.fileTree("src/commonTest/cpp") { include("**/*.cc") }
}
outDir.set(project.layout.buildDirectory.dir("out/compile/${buildType.id}-${osArch.first.id}-${osArch.second.id}"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp"))
includeHeadersNonRecursive(skiaHeadersDirs(unpackedSkia))
}
}
val linkWasm = tasks.register<LinkWasmTask>("linkWasm") { val linkWasm = tasks.register<LinkWasmTask>("linkWasm") {
val osArch = OS.Wasm to Arch.Wasm val osArch = OS.Wasm to Arch.Wasm
...@@ -186,6 +266,7 @@ val Project.supportNative: Boolean ...@@ -186,6 +266,7 @@ val Project.supportNative: Boolean
val Project.supportWasm: Boolean val Project.supportWasm: Boolean
get() = properties.get("skiko.wasm.enabled") == "true" get() = properties.get("skiko.wasm.enabled") == "true"
kotlin { kotlin {
jvm { jvm {
compilations.all { compilations.all {
...@@ -207,15 +288,26 @@ kotlin { ...@@ -207,15 +288,26 @@ kotlin {
} }
if (supportNative) { if (supportNative) {
val skiaDir = skiaDir.get().absolutePath when ("${hostOs.id}-${hostArch.id}") {
val nativeTarget = when (target) { "macos-x64" -> allNativeTargets[OS.MacOS to Arch.X64] = NativeCompilationInfo(macosX64())
"macos-x64" -> macosX64 {} "macos-arm64" -> allNativeTargets[OS.MacOS to Arch.Arm64] = NativeCompilationInfo(macosArm64())
"macos-arm64" -> macosArm64 {} }
else -> null
} if (hostOs == OS.MacOS) {
val targetString = target allNativeTargets[OS.IOS to Arch.Arm64] = NativeCompilationInfo(iosArm64())
nativeTarget?.let { allNativeTargets[OS.IOS to Arch.X64] = NativeCompilationInfo(iosX64())
it.compilations.all { }
for ((osArch, compilation) in allNativeTargets) {
val targetString = "${osArch.first.id}-${osArch.second.id}"
val unzipper = skiaDirProviderForCrossTargets[osArch]!!
val unpackedSkia = unzipper.get()
val skiaDir = unpackedSkia.absolutePath
val skiaBinSubdir = "out/${buildType.id}-$targetString"
compilation.target.compilations.all {
kotlinOptions { kotlinOptions {
freeCompilerArgs += listOf( freeCompilerArgs += listOf(
"-include-binary", "-include-binary",
...@@ -229,6 +321,31 @@ kotlin { ...@@ -229,6 +321,31 @@ kotlin {
) )
} }
} }
val crossCompileTask = registerNativeBridgesTask(osArch.first, osArch.second)
allNativeTargets[osArch]!!.linkTask = project.tasks.register<Exec>("linkNativeBridges$targetString") {
dependsOn(crossCompileTask)
val objectFilesDir = crossCompileTask.map { it.outDir.get() }
val objectFiles = project.fileTree(objectFilesDir) {
include("**/*.o")
}
inputs.files(objectFiles)
val outDir = "$buildDir/nativeBridges/static/$targetString"
val staticLib = "$outDir/skiko-native-bridges-$targetString.a"
workingDir = File(outDir)
executable = "libtool"
argumentProviders.add {
listOf(
"-static",
"-o",
staticLib
)
}
argumentProviders.add { objectFiles.files.map { it.absolutePath } }
file(outDir).mkdirs()
outputs.dir(outDir)
}
} }
} }
...@@ -275,10 +392,13 @@ kotlin { ...@@ -275,10 +392,13 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
} }
} }
if (targetOs == OS.MacOS) { if (hostOs == OS.MacOS) {
val macosMain by creating { val macosMain by creating {
dependsOn(nativeMain) dependsOn(nativeMain)
} }
val iosMain by creating {
dependsOn(nativeMain)
}
val macosArchMain = when (targetArch) { val macosArchMain = when (targetArch) {
Arch.X64 -> { Arch.X64 -> {
val macosX64Main by getting { val macosX64Main by getting {
...@@ -294,6 +414,12 @@ kotlin { ...@@ -294,6 +414,12 @@ kotlin {
} }
else -> throw GradleException("Unsupported arch $targetArch for macOS") else -> throw GradleException("Unsupported arch $targetArch for macOS")
} }
val iosX64Main by getting {
dependsOn(iosMain)
}
val iosArm64Main by getting {
dependsOn(iosMain)
}
} }
} }
} }
...@@ -412,7 +538,7 @@ tasks.withType(CppCompile::class.java).configureEach { ...@@ -412,7 +538,7 @@ tasks.withType(CppCompile::class.java).configureEach {
) )
) )
} }
OS.Wasm -> throw GradleException("Should not reach here") OS.Wasm, OS.IOS -> throw GradleException("Should not reach here")
} }
} }
...@@ -469,60 +595,6 @@ val generateVersion = project.tasks.register("generateVersion") { ...@@ -469,60 +595,6 @@ val generateVersion = project.tasks.register("generateVersion") {
} }
} }
// Very hacky way to compile native bridges and add the
// resulting object files into the final native klib.
val compileNativeBridges = project.tasks.register<CrossCompileTask>("compileNativeBridges") {
dependsOn(skiaDir)
compiler.set("clang++")
crossCompileTargetOS.set(targetOs)
crossCompileTargetArch.set(targetArch)
buildVariant.set(buildType)
sourceFiles =
project.fileTree("src/nativeMain/cpp") { include("**/*.cc") } +
project.fileTree("src/commonMain/cpp") { include("**/*.cc") }
if (skiko.includeTestHelpers) {
sourceFiles += project.fileTree("src/commonTest/cpp") { include("**/*.cc") }
}
outDir.set(project.layout.buildDirectory.dir("nativeBridges/obj/$target"))
includeHeadersNonRecursive(projectDir.resolve("src/commonMain/cpp"))
includeHeadersNonRecursive(skiaHeadersDirs(skiaDir.get()))
flags.set(listOf(
"-DSK_SHAPER_CORETEXT_AVAILABLE",
"-DSK_BUILD_FOR_MAC",
"-DSK_METAL",
*skiaPreprocessorFlags(),
))
}
val linkNativeBridges = project.tasks.register<Exec>("linkNativeBridges") {
dependsOn(compileNativeBridges)
val objectFilesDir = compileNativeBridges.map { it.outDir.get() }
val objectFiles = project.fileTree(objectFilesDir) {
include("**/*.o")
}
inputs.files(objectFiles)
val outDir = "$buildDir/nativeBridges/static/$target"
val staticLib = "$outDir/skiko-native-bridges-$target.a"
workingDir = File(outDir)
executable = "libtool"
argumentProviders.add {
listOf(
"-static",
"-o",
staticLib
)
}
argumentProviders.add { objectFiles.files.map { it.absolutePath } }
file(outDir).mkdirs()
outputs.dir(outDir)
}
fun localSign(signer: String, lib: File): File { fun localSign(signer: String, lib: File): File {
println("Local signing $lib as $signer") println("Local signing $lib as $signer")
val proc = ProcessBuilder("codesign", "-f", "-s", signer, lib.absolutePath) val proc = ProcessBuilder("codesign", "-f", "-s", signer, lib.absolutePath)
...@@ -672,8 +744,8 @@ tasks.withType(LinkSharedLibrary::class.java).configureEach { ...@@ -672,8 +744,8 @@ tasks.withType(LinkSharedLibrary::class.java).configureEach {
) )
) )
} }
OS.Wasm -> { OS.Wasm, OS.IOS -> {
throw GradleException("This task shalln't be used with WASM") throw GradleException("This task shalln't be used with $targetOs")
} }
} }
} }
...@@ -952,9 +1024,11 @@ afterEvaluate { ...@@ -952,9 +1024,11 @@ afterEvaluate {
tasks.withType<KotlinNativeCompile>().configureEach { tasks.withType<KotlinNativeCompile>().configureEach {
dependsOn(generateVersion) dependsOn(generateVersion)
source(generatedKotlin) source(generatedKotlin)
// TDOD: do we need this 'if'?
if (supportNative) { if (supportNative) {
dependsOn(linkNativeBridges) val compilationInfoKey = allNativeTargets.keys.singleOrNull { "${it.first.id}_${it.second.id}" == this.target }
?: throw GradleException("No cross-target for ${this.target}")
dependsOn(allNativeTargets[compilationInfoKey]!!.linkTask)
} }
} }
} }
......
...@@ -8,7 +8,8 @@ enum class OS( ...@@ -8,7 +8,8 @@ enum class OS(
Linux("linux", arrayOf()), Linux("linux", arrayOf()),
Windows("windows", arrayOf()), Windows("windows", arrayOf()),
MacOS("macos", arrayOf("-mmacosx-version-min=10.13")), MacOS("macos", arrayOf("-mmacosx-version-min=10.13")),
Wasm("wasm", arrayOf()) Wasm("wasm", arrayOf()),
IOS("ios", arrayOf())
; ;
val isWindows val isWindows
......
...@@ -8,5 +8,7 @@ dependencies.skia.macos-x64=m94-fd7c5792ca ...@@ -8,5 +8,7 @@ dependencies.skia.macos-x64=m94-fd7c5792ca
dependencies.skia.linux-arm64=m94-fd7c5792ca dependencies.skia.linux-arm64=m94-fd7c5792ca
dependencies.skia.macos-arm64=m94-fd7c5792ca dependencies.skia.macos-arm64=m94-fd7c5792ca
dependencies.skia.wasm-wasm=m94-fd7c5792ca dependencies.skia.wasm-wasm=m94-fd7c5792ca
dependencies.skia.ios-x64=m94-fd7c5792ca
dependencies.skia.ios-arm64=m94-fd7c5792ca
org.gradle.jvmargs=-Xmx3G org.gradle.jvmargs=-Xmx3G
package org.jetbrains.skiko.native.context
import org.jetbrains.skia.*
import org.jetbrains.skiko.native.*
internal actual fun createContextHandler(layer: HardwareLayer): ContextHandler {
TODO()
}
package org.jetbrains.skiko.native
actual abstract class HardwareLayer
\ No newline at end of file
package org.jetbrains.skiko.native
import org.jetbrains.skiko.GraphicsApi
import org.jetbrains.skiko.redrawer.Redrawer
import org.jetbrains.skiko.native.redrawer.IosOpenGLRedrawer
internal actual fun makePlatformOperations(): PlatformOperations {
return object: PlatformOperations {
override fun createRedrawer(layer: HardwareLayer, properties: SkiaLayerProperties): Redrawer =
when (SkikoProperties.renderApi) {
GraphicsApi.OPENGL -> IosOpenGLRedrawer(layer, properties)
else -> error("No other renderings for native yet")
}
}
}
\ No newline at end of file
package org.jetbrains.skiko.native.redrawer
import org.jetbrains.skiko.native.*
import org.jetbrains.skiko.redrawer.Redrawer
internal class IosOpenGLRedrawer(
private val layer: HardwareLayer,
private val properties: SkiaLayerProperties
) : Redrawer {
override fun dispose() {
TODO()
}
override fun syncSize() {
TODO()
}
override fun needRedraw() {
TODO()
}
override fun redrawImmediately() {
TODO()
}
}
...@@ -3,7 +3,7 @@ package org.jetbrains.skia.impl ...@@ -3,7 +3,7 @@ package org.jetbrains.skia.impl
import org.jetbrains.skia.ExternalSymbolName import org.jetbrains.skia.ExternalSymbolName
actual abstract class RefCnt : Managed { actual abstract class RefCnt : Managed {
actual protected constructor(ptr: NativePointer): super(ptr, _FinalizerHolder.PTR, false) actual protected constructor(ptr: NativePointer): super(ptr, _FinalizerHolder.PTR, true)
actual protected constructor(ptr: NativePointer, allowClose: Boolean): super(ptr, _FinalizerHolder.PTR, allowClose) actual protected constructor(ptr: NativePointer, allowClose: Boolean): super(ptr, _FinalizerHolder.PTR, allowClose)
val refCount: Int val refCount: Int
......
...@@ -3,7 +3,7 @@ package org.jetbrains.skia.impl ...@@ -3,7 +3,7 @@ package org.jetbrains.skia.impl
import java.lang.ref.Reference import java.lang.ref.Reference
actual abstract class RefCnt : Managed { actual abstract class RefCnt : Managed {
protected actual constructor(ptr: NativePointer) : super(ptr, _FinalizerHolder.PTR) protected actual constructor(ptr: NativePointer) : super(ptr, _FinalizerHolder.PTR, true)
protected actual constructor(ptr: NativePointer, allowClose: Boolean) : super(ptr, _FinalizerHolder.PTR, allowClose) protected actual constructor(ptr: NativePointer, allowClose: Boolean) : super(ptr, _FinalizerHolder.PTR, allowClose)
val refCount: Int val refCount: Int
......
...@@ -4,11 +4,20 @@ import kotlinx.cinterop.* ...@@ -4,11 +4,20 @@ import kotlinx.cinterop.*
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skiko.native.* import org.jetbrains.skiko.native.*
import platform.OpenGL.GL_DRAW_FRAMEBUFFER_BINDING import platform.OpenGL.GL_DRAW_FRAMEBUFFER_BINDING
import platform.OpenGL.GL_RGBA8
import platform.OpenGL.glGetIntegerv import platform.OpenGL.glGetIntegerv
import platform.OpenGL.* import platform.OpenGL.*
import platform.OpenGLCommon.GLenum import platform.OpenGLCommon.GLenum
internal actual fun createContextHandler(layer: HardwareLayer): ContextHandler {
return OpenGLContextHandler(layer)
//return when (SkikoProperties.renderApi) {
// GraphicsApi.SOFTWARE -> SoftwareContextHandler(layer)
// GraphicsApi.OPENGL -> OpenGLContextHandler(layer)
// else -> TODO("Unsupported yet")
//}
}
internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer) { internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer) {
override fun initContext(): Boolean { override fun initContext(): Boolean {
println("OpenGLContextHandler::initContext") println("OpenGLContextHandler::initContext")
......
package org.jetbrains.skiko.native
import platform.AppKit.*
import platform.Foundation.*
actual abstract class HardwareLayer {
val nsView = NSView(NSMakeRect(0.0, 0.0, 640.0, 480.0))
// getDpiScale is expensive operation on some platforms, so we cache it
private var _contentScale: Float? = null
private var isInit = false
fun checkIsShowing() {
if (!isInit && !nsView.hiddenOrHasHiddenAncestor) {
// _contentScale = getDpiScale()
_contentScale = 1.0f // TODO: what's the proper way here?
init()
isInit = true
}
}
open fun init() {
}
protected open fun nativeInit(platformInfo: Long) {
}
open fun dispose() {
}
protected open fun contentScaleChanged() = Unit
private fun checkContentScale() {
}
internal abstract fun update(nanoTime: Long)
internal abstract fun draw()
val contentScale: Float
get() = _contentScale!!
}
...@@ -7,7 +7,6 @@ import kotlin.native.concurrent.freeze ...@@ -7,7 +7,6 @@ import kotlin.native.concurrent.freeze
import kotlin.native.internal.createCleaner import kotlin.native.internal.createCleaner
private class FinalizationThunk(private val finalizer: NativePointer, val className: String, obj: NativePointer) { private class FinalizationThunk(private val finalizer: NativePointer, val className: String, obj: NativePointer) {
private var obj = AtomicNativePtr(obj) private var obj = AtomicNativePtr(obj)
fun clean() { fun clean() {
......
...@@ -3,7 +3,7 @@ package org.jetbrains.skia.impl ...@@ -3,7 +3,7 @@ package org.jetbrains.skia.impl
import org.jetbrains.skia.ExternalSymbolName import org.jetbrains.skia.ExternalSymbolName
actual abstract class RefCnt : Managed { actual abstract class RefCnt : Managed {
protected actual constructor(ptr: NativePointer) : super(ptr, _FinalizerHolder.PTR) {} protected actual constructor(ptr: NativePointer) : super(ptr, _FinalizerHolder.PTR, true) {}
protected actual constructor(ptr: NativePointer, allowClose: Boolean) : super(ptr, _FinalizerHolder.PTR, allowClose) protected actual constructor(ptr: NativePointer, allowClose: Boolean) : super(ptr, _FinalizerHolder.PTR, allowClose)
val refCount: Int val refCount: Int
......
package org.jetbrains.skiko.native.context package org.jetbrains.skiko.native.context
import kotlinx.cinterop.ptr
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skiko.native.* import org.jetbrains.skiko.native.*
internal fun createContextHandler(layer: HardwareLayer): ContextHandler { internal expect fun createContextHandler(layer: HardwareLayer): ContextHandler
return OpenGLContextHandler(layer)
//return when (SkikoProperties.renderApi) {
// GraphicsApi.SOFTWARE -> SoftwareContextHandler(layer)
// GraphicsApi.OPENGL -> OpenGLContextHandler(layer)
// else -> TODO("Unsupported yet")
//}
}
internal abstract class ContextHandler(val layer: HardwareLayer) { internal abstract class ContextHandler(val layer: HardwareLayer) {
......
package org.jetbrains.skiko.native package org.jetbrains.skiko.native
import kotlinx.cinterop.readValue expect abstract class HardwareLayer()
import platform.Cocoa.* \ No newline at end of file
import platform.AppKit.*
import platform.Foundation.*
import platform.CoreGraphics.*
abstract class HardwareLayer {
val nsView = NSView(NSMakeRect(0.0, 0.0, 640.0, 480.0))
// getDpiScale is expensive operation on some platforms, so we cache it
private var _contentScale: Float? = null
private var isInit = false
fun checkIsShowing() {
if (!isInit && !nsView.hiddenOrHasHiddenAncestor) {
// _contentScale = getDpiScale()
_contentScale = 1.0f // TODO: what's the proper way here?
init()
isInit = true
}
}
open fun init() {
}
protected open fun nativeInit(platformInfo: Long) {
}
open fun dispose() {
}
protected open fun contentScaleChanged() = Unit
private fun checkContentScale() {
}
internal abstract fun update(nanoTime: Long)
internal abstract fun draw()
val contentScale: Float
get() = _contentScale!!
}
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