Unverified Commit 4615faa1 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

First take on rendering commonization (#245)

parent 50cbeb65
...@@ -3,14 +3,12 @@ package org.jetbrains.skiko.sample ...@@ -3,14 +3,12 @@ package org.jetbrains.skiko.sample
import platform.AppKit.* import platform.AppKit.*
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skiko.native.SkiaLayer import org.jetbrains.skiko.*
import org.jetbrains.skiko.native.SkiaRenderer
import org.jetbrains.skiko.native.SkiaWindow
import kotlinx.cinterop.* import kotlinx.cinterop.*
import kotlin.math.cos import kotlin.math.cos
import kotlin.math.sin import kotlin.math.sin
fun main(args: Array<String>) { fun main() {
// TODO: Remove me! This is to run all cleaners before main() exits. // TODO: Remove me! This is to run all cleaners before main() exits.
kotlin.native.internal.Debugging.forceCheckedShutdown = true kotlin.native.internal.Debugging.forceCheckedShutdown = true
......
...@@ -325,7 +325,11 @@ kotlin { ...@@ -325,7 +325,11 @@ kotlin {
val skiaBinDir = "$skiaDir/out/${buildType.id}-${osArch.first.id}-${osArch.second.id}" val skiaBinDir = "$skiaDir/out/${buildType.id}-${osArch.first.id}-${osArch.second.id}"
kotlinOptions { kotlinOptions {
val linkerFlags = when (osArch.first) { val linkerFlags = when (osArch.first) {
OS.MacOS -> listOf("-linker-option", "-framework", "-linker-option", "Metal") OS.MacOS -> listOf("-linker-option", "-framework", "-linker-option", "Metal",
"-linker-option", "-framework", "-linker-option", "CoreGraphics",
"-linker-option", "-framework", "-linker-option", "CoreText",
"-linker-option", "-framework", "-linker-option", "CoreServices"
)
OS.IOS -> listOf("-linker-option", "-framework", "-linker-option", "Metal", OS.IOS -> listOf("-linker-option", "-framework", "-linker-option", "Metal",
"-linker-option", "-framework", "-linker-option", "CoreGraphics", "-linker-option", "-framework", "-linker-option", "CoreGraphics",
"-linker-option", "-framework", "-linker-option", "CoreText") "-linker-option", "-framework", "-linker-option", "CoreText")
......
...@@ -283,7 +283,7 @@ class Surface : RefCnt { ...@@ -283,7 +283,7 @@ class Surface : RefCnt {
surfaceProps surfaceProps
) )
require(ptr != NullPointer) { require(ptr != NullPointer) {
"Failed Surface.makeFromBackendRenderTarget($context, $rt, $origin, $colorFormat, $colorSpace)" "Failed Surface.makeFromBackendRenderTarget"
} }
Surface(ptr, context, rt) Surface(ptr, context, rt)
} finally { } finally {
......
...@@ -6,6 +6,11 @@ class SurfaceProps constructor( ...@@ -6,6 +6,11 @@ class SurfaceProps constructor(
) { ) {
constructor(geo: PixelGeometry) : this(false, geo) constructor(geo: PixelGeometry) : this(false, geo)
// Used from JNI code.
private fun _getPixelGeometryOrdinal(): Int {
return pixelGeometry.ordinal
}
fun _getFlags(): Int { fun _getFlags(): Int {
return 0 or if (isDeviceIndependentFonts) 1 else 0 return 0 or if (isDeviceIndependentFonts) 1 else 0
} }
......
package org.jetbrains.skiko
interface ClipRectangle {
val x: Float
val y: Float
val width: Float
val height: Float
}
package org.jetbrains.skiko
internal expect fun makeDefaultSkiaLayerProperties(): SkiaLayerProperties
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skiko.context.*
import org.jetbrains.skiko.redrawer.*
internal interface RenderFactory {
fun createContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler
fun createRedrawer(layer: SkiaLayer, renderApi: GraphicsApi, properties: SkiaLayerProperties): Redrawer
companion object {
val Default = makeDefaultRenderFactory()
}
}
internal expect fun makeDefaultRenderFactory(): RenderFactory
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skia.Canvas
import org.jetbrains.skia.Picture
interface SkiaRenderer {
fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long)
}
expect open class SkiaLayer {
var renderApi: GraphicsApi
val contentScale: Float
}
internal class PictureHolder(val instance: Picture, val width: Int, val height: Int)
package org.jetbrains.skiko
class SkiaLayerProperties(
val isVsyncEnabled: Boolean,
val isVsyncFramelimitFallbackEnabled: Boolean
)
...@@ -5,13 +5,10 @@ import org.jetbrains.skia.Canvas ...@@ -5,13 +5,10 @@ import org.jetbrains.skia.Canvas
import org.jetbrains.skia.DirectContext import org.jetbrains.skia.DirectContext
import org.jetbrains.skia.Picture import org.jetbrains.skia.Picture
import org.jetbrains.skia.Surface import org.jetbrains.skia.Surface
import org.jetbrains.skiko.GraphicsApi
import org.jetbrains.skiko.OS import org.jetbrains.skiko.OS
import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.hostArch
import org.jetbrains.skiko.hostOs import org.jetbrains.skiko.hostOs
import org.jetbrains.skiko.hostFullName
import org.jetbrains.skiko.javaLocation
import org.jetbrains.skiko.javaVendor
internal abstract class ContextHandler(val layer: SkiaLayer) { internal abstract class ContextHandler(val layer: SkiaLayer) {
open val bleachConstant = if (hostOs == OS.MacOS) 0 else -1 open val bleachConstant = if (hostOs == OS.MacOS) 0 else -1
...@@ -35,7 +32,7 @@ internal abstract class ContextHandler(val layer: SkiaLayer) { ...@@ -35,7 +32,7 @@ internal abstract class ContextHandler(val layer: SkiaLayer) {
context?.flush() context?.flush()
} }
fun dispose() { open fun dispose() {
disposeCanvas() disposeCanvas()
destroyContext() destroyContext()
} }
...@@ -47,9 +44,7 @@ internal abstract class ContextHandler(val layer: SkiaLayer) { ...@@ -47,9 +44,7 @@ internal abstract class ContextHandler(val layer: SkiaLayer) {
open fun rendererInfo(): String { open fun rendererInfo(): String {
return "GraphicsApi: ${layer.renderApi}\n" + return "GraphicsApi: ${layer.renderApi}\n" +
"OS: $hostFullName\n" + "OS: ${hostOs.id} ${hostArch.id}\n"
"Java: $javaVendor\n" +
"Java location: $javaLocation\n"
} }
protected open fun destroyContext() { protected open fun destroyContext() {
......
package org.jetbrains.skiko
import org.jetbrains.skiko.context.ContextHandler
import org.jetbrains.skiko.redrawer.OpenGLRedrawer
import org.jetbrains.skiko.redrawer.Redrawer
internal actual fun createNativeContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler {
TODO()
}
internal actual fun createNativeRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer {
return OpenGLRedrawer(layer, properties)
}
\ No newline at end of file
package org.jetbrains.skiko
actual open class SkiaLayer {
actual var renderApi: GraphicsApi
get() = TODO("Not yet implemented")
set(value) {}
actual val contentScale: Float
get() = TODO("Not yet implemented")
}
\ No newline at end of file
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 package org.jetbrains.skiko.redrawer
import org.jetbrains.skiko.native.* import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.SkiaLayerProperties
internal class IosOpenGLRedrawer( internal class OpenGLRedrawer(
private val layer: HardwareLayer, private val layer: SkiaLayer,
private val properties: SkiaLayerProperties private val properties: SkiaLayerProperties
) : Redrawer { ) : Redrawer {
override fun dispose() { override fun dispose() {
......
package org.jetbrains.skiko
internal actual fun makeDefaultSkiaLayerProperties(): SkiaLayerProperties {
TODO()
}
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skiko.context.*
import org.jetbrains.skiko.redrawer.*
internal actual fun makeDefaultRenderFactory(): RenderFactory {
return object : RenderFactory {
override fun createContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler {
TODO()
}
override fun createRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer {
TODO()
}
}
}
package org.jetbrains.skiko
actual open class SkiaLayer {
actual var renderApi: GraphicsApi = GraphicsApi.WEBGL
actual val contentScale: Float
get() = 1.0f
}
package org.jetbrains.skiko
internal actual fun makeDefaultSkiaLayerProperties(): SkiaLayerProperties {
return SkiaLayerProperties(SkikoProperties.vsyncEnabled, SkikoProperties.vsyncFramelimitFallbackEnabled)
}
\ No newline at end of file
...@@ -2,13 +2,6 @@ package org.jetbrains.skiko ...@@ -2,13 +2,6 @@ package org.jetbrains.skiko
import java.awt.Component import java.awt.Component
interface ClipRectangle {
val x: Float
val y: Float
val width: Float
val height: Float
}
class ClipComponent(val component: Component) : ClipRectangle { class ClipComponent(val component: Component) : ClipRectangle {
override val x: Float override val x: Float
get() = component.x.toFloat() get() = component.x.toFloat()
......
...@@ -24,7 +24,7 @@ internal open class HardwareLayer : Canvas() { ...@@ -24,7 +24,7 @@ internal open class HardwareLayer : Canvas() {
useDrawingSurfacePlatformInfo(::nativeInit) useDrawingSurfacePlatformInfo(::nativeInit)
} }
fun dispose() { open fun dispose() {
nativeDispose() nativeDispose()
} }
......
package org.jetbrains.skiko
import org.jetbrains.skiko.context.*
import org.jetbrains.skiko.redrawer.*
internal actual fun makeDefaultRenderFactory(): RenderFactory {
return object : RenderFactory {
override fun createContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler {
return when (renderApi) {
GraphicsApi.DIRECT_SOFTWARE -> return when (hostOs) {
OS.Windows, OS.Linux -> DirectSoftwareContextHandler(layer)
else -> SoftwareContextHandler(layer)
}
GraphicsApi.SOFTWARE -> SoftwareContextHandler(layer)
GraphicsApi.OPENGL -> OpenGLContextHandler(layer)
GraphicsApi.DIRECT3D -> Direct3DContextHandler(layer)
GraphicsApi.METAL -> MetalContextHandler(layer)
else -> TODO("Unsupported yet.")
}
}
override fun createRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer = when (hostOs) {
OS.MacOS -> when (renderApi) {
GraphicsApi.SOFTWARE, GraphicsApi.DIRECT_SOFTWARE -> SoftwareRedrawer(layer, properties)
else -> MetalRedrawer(layer, properties)
}
OS.Windows -> when (renderApi) {
GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer, properties)
GraphicsApi.DIRECT_SOFTWARE -> WindowsSoftwareRedrawer(layer, properties)
GraphicsApi.OPENGL -> WindowsOpenGLRedrawer(layer, properties)
else -> Direct3DRedrawer(layer, properties)
}
OS.Linux -> when (renderApi) {
GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer, properties)
GraphicsApi.DIRECT_SOFTWARE -> LinuxSoftwareRedrawer(layer, properties)
else -> LinuxOpenGLRedrawer(layer, properties)
}
OS.JS -> {
TODO("Commonize me")
}
}
}
}
package org.jetbrains.skiko
import org.jetbrains.skiko.context.*
import org.jetbrains.skiko.redrawer.*
internal interface RenderFactory {
fun createContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler
fun createRedrawer(layer: SkiaLayer, renderApi: GraphicsApi, properties: SkiaLayerProperties): Redrawer
companion object {
val Default = object : RenderFactory {
override fun createContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler {
return when (renderApi) {
GraphicsApi.DIRECT_SOFTWARE -> return when (hostOs) {
OS.Windows, OS.Linux -> DirectSoftwareContextHandler(layer)
else -> SoftwareContextHandler(layer)
}
GraphicsApi.SOFTWARE -> SoftwareContextHandler(layer)
GraphicsApi.OPENGL -> OpenGLContextHandler(layer)
GraphicsApi.DIRECT3D -> Direct3DContextHandler(layer)
GraphicsApi.METAL -> MetalContextHandler(layer)
else -> TODO("Unsupported yet.")
}
}
override fun createRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer = when (hostOs) {
OS.MacOS -> when (renderApi) {
GraphicsApi.SOFTWARE, GraphicsApi.DIRECT_SOFTWARE -> SoftwareRedrawer(layer, properties)
else -> MetalRedrawer(layer, properties)
}
OS.Windows -> when (renderApi) {
GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer, properties)
GraphicsApi.DIRECT_SOFTWARE -> WindowsSoftwareRedrawer(layer, properties)
GraphicsApi.OPENGL -> WindowsOpenGLRedrawer(layer, properties)
else -> Direct3DRedrawer(layer, properties)
}
OS.Linux -> when (renderApi) {
GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer, properties)
GraphicsApi.DIRECT_SOFTWARE -> LinuxSoftwareRedrawer(layer, properties)
else -> LinuxOpenGLRedrawer(layer, properties)
}
OS.JS -> {
TODO("Commonize me")
}
}
}
}
}
\ No newline at end of file
...@@ -10,14 +10,8 @@ import java.util.concurrent.CancellationException ...@@ -10,14 +10,8 @@ import java.util.concurrent.CancellationException
import javax.swing.JPanel import javax.swing.JPanel
import javax.swing.SwingUtilities.isEventDispatchThread import javax.swing.SwingUtilities.isEventDispatchThread
interface SkiaRenderer { actual open class SkiaLayer internal constructor(
fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) private val properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties(),
}
private class PictureHolder(val instance: Picture, val width: Int, val height: Int)
open class SkiaLayer internal constructor(
private val properties: SkiaLayerProperties = SkiaLayerProperties(),
private val renderFactory: RenderFactory private val renderFactory: RenderFactory
) : JPanel() { ) : JPanel() {
companion object { companion object {
...@@ -34,7 +28,7 @@ open class SkiaLayer internal constructor( ...@@ -34,7 +28,7 @@ open class SkiaLayer internal constructor(
internal val backedLayer: HardwareLayer internal val backedLayer: HardwareLayer
constructor( constructor(
properties: SkiaLayerProperties = SkiaLayerProperties() properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties()
) : this(properties, RenderFactory.Default) ) : this(properties, RenderFactory.Default)
val canvas: java.awt.Canvas val canvas: java.awt.Canvas
...@@ -95,7 +89,7 @@ open class SkiaLayer internal constructor( ...@@ -95,7 +89,7 @@ open class SkiaLayer internal constructor(
return isShowingCached return isShowingCached
} }
val contentScale: Float actual val contentScale: Float
get() = backedLayer.contentScale get() = backedLayer.contentScale
val contentHandle: Long val contentHandle: Long
...@@ -119,7 +113,7 @@ open class SkiaLayer internal constructor( ...@@ -119,7 +113,7 @@ open class SkiaLayer internal constructor(
private var contextHandler: ContextHandler? = null private var contextHandler: ContextHandler? = null
private val fallbackRenderApiQueue = SkikoProperties.fallbackRenderApiQueue.toMutableList() private val fallbackRenderApiQueue = SkikoProperties.fallbackRenderApiQueue.toMutableList()
private var renderApi_ = fallbackRenderApiQueue[0] private var renderApi_ = fallbackRenderApiQueue[0]
var renderApi: GraphicsApi actual var renderApi: GraphicsApi
get() = renderApi_ get() = renderApi_
private set(value) { private set(value) {
this.renderApi_ = value this.renderApi_ = value
......
package org.jetbrains.skiko
class SkiaLayerProperties(
val isVsyncEnabled: Boolean = SkikoProperties.vsyncEnabled,
val isVsyncFramelimitFallbackEnabled: Boolean = SkikoProperties.vsyncFramelimitFallbackEnabled
)
\ No newline at end of file
...@@ -3,7 +3,7 @@ package org.jetbrains.skiko ...@@ -3,7 +3,7 @@ package org.jetbrains.skiko
import javax.swing.JFrame import javax.swing.JFrame
open class SkiaWindow( open class SkiaWindow(
properties: SkiaLayerProperties = SkiaLayerProperties(), properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties(),
layerFactory: () -> SkiaLayer = { SkiaLayer(properties) } layerFactory: () -> SkiaLayer = { SkiaLayer(properties) }
) : JFrame() { ) : JFrame() {
val layer = layerFactory() val layer = layerFactory()
......
package org.jetbrains.skiko.redrawer package org.jetbrains.skiko.redrawer
import org.jetbrains.skia.Surface
import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.* import org.jetbrains.skiko.*
internal class LinuxSoftwareRedrawer( internal class LinuxSoftwareRedrawer(
......
package org.jetbrains.skiko.redrawer package org.jetbrains.skiko.redrawer
import org.jetbrains.skia.Surface
import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.FrameLimiter
import org.jetbrains.skiko.SkiaLayer import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties import org.jetbrains.skiko.SkiaLayerProperties
import org.jetbrains.skiko.RenderException import org.jetbrains.skiko.RenderException
......
...@@ -233,7 +233,7 @@ class SkiaWindowTest { ...@@ -233,7 +233,7 @@ class SkiaWindowTest {
@Test(timeout = 60000) @Test(timeout = 60000)
fun `stress test - resize and paint immediately`() = swingTest { fun `stress test - resize and paint immediately`() = swingTest {
fun openWindow() = SkiaWindow( fun openWindow() = SkiaWindow(
properties = SkiaLayerProperties(isVsyncEnabled = false) properties = SkiaLayerProperties(isVsyncEnabled = false, isVsyncFramelimitFallbackEnabled = true)
).apply { ).apply {
setLocation(200,200) setLocation(200,200)
setSize(400, 200) setSize(400, 200)
...@@ -256,7 +256,7 @@ class SkiaWindowTest { ...@@ -256,7 +256,7 @@ class SkiaWindowTest {
@Test(timeout = 60000) @Test(timeout = 60000)
fun `stress test - open and paint immediately`() = swingTest { fun `stress test - open and paint immediately`() = swingTest {
fun openWindow() = SkiaWindow( fun openWindow() = SkiaWindow(
properties = SkiaLayerProperties(isVsyncEnabled = false) properties = SkiaLayerProperties(isVsyncEnabled = false, isVsyncFramelimitFallbackEnabled = true)
).apply { ).apply {
setLocation(200,200) setLocation(200,200)
setSize(400, 200) setSize(400, 200)
...@@ -415,7 +415,8 @@ class SkiaWindowTest { ...@@ -415,7 +415,8 @@ class SkiaWindowTest {
val window = SkiaWindow( val window = SkiaWindow(
properties = SkiaLayerProperties( properties = SkiaLayerProperties(
isVsyncEnabled = false isVsyncEnabled = false,
isVsyncFramelimitFallbackEnabled = true
) )
) )
......
package org.jetbrains.skiko
import org.jetbrains.skiko.redrawer.Redrawer
import org.jetbrains.skiko.context.ContextHandler
internal actual fun createNativeContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler {
TODO()
}
internal actual fun createNativeRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer {
TODO()
}
package org.jetbrains.skiko
actual open class SkiaLayer {
actual var renderApi: GraphicsApi
get() = TODO("Not yet implemented")
set(value) {}
actual val contentScale: Float
get() = TODO("Not yet implemented")
}
\ No newline at end of file
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.LinuxOpenGLRedrawer
internal actual fun makePlatformOperations(): PlatformOperations {
return object: PlatformOperations {
override fun createRedrawer(layer: HardwareLayer, properties: SkiaLayerProperties): Redrawer =
when (SkikoProperties.renderApi) {
GraphicsApi.OPENGL -> LinuxOpenGLRedrawer(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 LinuxOpenGLRedrawer(
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()
}
}
package org.jetbrains.skiko
import org.jetbrains.skiko.context.ContextHandler
import org.jetbrains.skiko.context.MacOSOpenGLContextHandler
import org.jetbrains.skiko.redrawer.MacOsOpenGLRedrawer
import org.jetbrains.skiko.redrawer.Redrawer
internal actual fun createNativeContextHandler(
layer: SkiaLayer, renderApi: GraphicsApi
): ContextHandler = when (renderApi) {
GraphicsApi.OPENGL -> MacOSOpenGLContextHandler(layer)
else -> throw IllegalArgumentException("Unsupported API $renderApi")
}
internal actual fun createNativeRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer {
return MacOsOpenGLRedrawer(layer, properties)
}
\ No newline at end of file
package org.jetbrains.skiko.native package org.jetbrains.skiko
import kotlinx.cinterop.useContents import kotlinx.cinterop.useContents
import org.jetbrains.skiko.native.context.* import org.jetbrains.skiko.context.*
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.redrawer.Redrawer
import platform.AppKit.NSView
import platform.Foundation.NSMakeRect
interface SkiaRenderer { actual open class SkiaLayer(
fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) private val properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties()
} ) {
actual var renderApi: GraphicsApi = GraphicsApi.OPENGL
actual val contentScale: Float
get() = _contentScale
// TODO: this is exact copy of jvm counterpart. Commonize! val nsView = NSView(NSMakeRect(0.0, 0.0, 640.0, 480.0))
private class PictureHolder(val instance: Picture, val width: Int, val height: Int) var _contentScale: Float = 1.0f
open class SkiaLayer(
private val properties: SkiaLayerProperties = SkiaLayerProperties()
) : HardwareLayer() {
var renderer: SkiaRenderer? = null var renderer: SkiaRenderer? = null
internal var skiaState = createContextHandler(this) private var contextHandler = MacOSOpenGLContextHandler(this)
private var isDisposed = false
private var redrawer: Redrawer? = null private var redrawer: Redrawer? = null
private var picture: PictureHolder? = null private var picture: PictureHolder? = null
private val pictureRecorder = PictureRecorder() private val pictureRecorder = PictureRecorder()
private val pictureLock = Any()
override fun init() { fun initLayer() {
println("SkiaLayer::init") println("SkiaLayer.initLayer")
super.init() redrawer = createNativeRedrawer(this, GraphicsApi.OPENGL, properties)
redrawer = platformOperations.createRedrawer(this, properties)
redrawer?.redrawImmediately() redrawer?.redrawImmediately()
} }
override fun dispose() { fun disposeLayer() {
redrawer?.dispose() redrawer?.dispose()
super.dispose() redrawer = null
initedCanvas = false
} }
fun needRedraw() { fun needRedraw() {
redrawer?.needRedraw() redrawer?.needRedraw()
} }
override fun update(nanoTime: Long) { fun update(nanoTime: Long) {
println("SkiaLayer::update") println("SkiaLayer.update")
val width = nsView.frame.useContents { size.width } val width = nsView.frame.useContents { size.width }
val height = nsView.frame.useContents { size.height } val height = nsView.frame.useContents { size.height }
...@@ -60,17 +59,22 @@ open class SkiaLayer( ...@@ -60,17 +59,22 @@ open class SkiaLayer(
this.picture = PictureHolder(picture, pictureWidth.toInt(), pictureHeight.toInt()) this.picture = PictureHolder(picture, pictureWidth.toInt(), pictureHeight.toInt())
} }
override fun draw() { private var initedCanvas = false
println("SkiaLayer::draw")
skiaState.apply { fun draw() {
if (!initContext()) { println("SkiaLayer.draw")
error("initContext() failure. No fallback to raster for Skia/native yet.") contextHandler.apply {
return if (!initedCanvas) {
if (!initContext()) {
error("initContext() failure")
return
}
initCanvas()
initedCanvas = true
} }
initCanvas()
clearCanvas() clearCanvas()
val picture = picture val picture = picture
println("SkiaLayer::draw: picture=$picture") println("SkiaLayer.draw: picture=$picture")
if (picture != null) { if (picture != null) {
drawOnCanvas(picture.instance) drawOnCanvas(picture.instance)
} }
......
package org.jetbrains.skiko.native package org.jetbrains.skiko
import platform.AppKit.* import platform.AppKit.*
import platform.Cocoa.*
import platform.Foundation.* import platform.Foundation.*
open class SkiaWindow( open class SkiaWindow(
properties: SkiaLayerProperties = SkiaLayerProperties() properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties()
) { ) {
val windowStyle = private val windowStyle =
NSWindowStyleMaskTitled or NSWindowStyleMaskTitled or
NSWindowStyleMaskMiniaturizable or NSWindowStyleMaskMiniaturizable or
NSWindowStyleMaskClosable or NSWindowStyleMaskClosable or
...@@ -21,12 +20,12 @@ open class SkiaWindow( ...@@ -21,12 +20,12 @@ open class SkiaWindow(
contentRect = NSMakeRect(0.0, 0.0, 640.0, 480.0), contentRect = NSMakeRect(0.0, 0.0, 640.0, 480.0),
styleMask = windowStyle, styleMask = windowStyle,
backing = NSBackingStoreBuffered, backing = NSBackingStoreBuffered,
defer = true) defer = true)
val layer = SkiaLayer(properties) val layer = SkiaLayer(properties)
init { init {
nsWindow.contentView?.addSubview(layer.nsView) nsWindow.contentView!!.addSubview(layer.nsView)
layer.checkIsShowing() // TODO: The awt versions has hierarchy listener. What should we use here? layer.initLayer()
} }
} }
package org.jetbrains.skiko.native.context package org.jetbrains.skiko.context
import kotlinx.cinterop.* import kotlinx.cinterop.*
import org.jetbrains.skia.* import org.jetbrains.skia.*
import org.jetbrains.skiko.native.* import org.jetbrains.skiko.SkiaLayer
import platform.OpenGL.GL_DRAW_FRAMEBUFFER_BINDING import platform.OpenGL.GL_DRAW_FRAMEBUFFER_BINDING
import platform.OpenGL.glGetIntegerv import platform.OpenGL.glGetIntegerv
import platform.OpenGL.*
import platform.OpenGLCommon.GLenum import platform.OpenGLCommon.GLenum
internal class MacOSOpenGLContextHandler(layer: SkiaLayer) : ContextHandler(layer) {
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) {
override fun initContext(): Boolean { override fun initContext(): Boolean {
println("OpenGLContextHandler::initContext") println("MacOSOpenGLContextHandler.initContext")
try { try {
if (context == null) { if (context == null) {
context = DirectContext.makeGL() context = DirectContext.makeGL()
...@@ -43,17 +32,14 @@ internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer ...@@ -43,17 +32,14 @@ internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer
return result return result
} }
@ExperimentalUnsignedTypes
override fun initCanvas() { override fun initCanvas() {
println("OpenGLContextHandler::initCanvas") println("MacOSOpenGLContextHandler.initCanvas")
dispose()
val scale = layer.contentScale val scale = layer.contentScale
val w = (layer.nsView.frame.useContents { size.width } * scale).toInt().coerceAtLeast(0) val w = (layer.nsView.frame.useContents { size.width } * scale).toInt().coerceAtLeast(0)
val h = (layer.nsView.frame.useContents { size.height } * scale).toInt().coerceAtLeast(0) val h = (layer.nsView.frame.useContents { size.height } * scale).toInt().coerceAtLeast(0)
val fbId = openglGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING.toUInt()) val fbId = openglGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING.toUInt())
renderTarget = BackendRenderTarget.makeGL( renderTarget = BackendRenderTarget.makeGL(
w, w,
h, h,
0, 0,
...@@ -61,7 +47,7 @@ internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer ...@@ -61,7 +47,7 @@ internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer
fbId.toInt(), fbId.toInt(),
FramebufferFormat.GR_GL_RGBA8 FramebufferFormat.GR_GL_RGBA8
) )
surface = Surface.makeFromBackendRenderTarget( surface = Surface.makeFromBackendRenderTarget(
context!!, context!!,
renderTarget!!, renderTarget!!,
SurfaceOrigin.BOTTOM_LEFT, SurfaceOrigin.BOTTOM_LEFT,
...@@ -69,7 +55,7 @@ internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer ...@@ -69,7 +55,7 @@ internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer
ColorSpace.sRGB ColorSpace.sRGB
) )
canvas = surface!!.canvas canvas = surface?.canvas
?: error("Could not obtain Canvas from Surface") ?: error("Could not obtain Canvas from Surface")
} }
} }
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!!
}
package org.jetbrains.skiko.native
import org.jetbrains.skiko.GraphicsApi
import org.jetbrains.skiko.native.redrawer.MacOsOpenGLRedrawer
internal actual fun makePlatformOperations(): PlatformOperations {
return object: PlatformOperations {
override fun createRedrawer(layer: HardwareLayer, properties: SkiaLayerProperties) =
when (SkikoProperties.renderApi) {
GraphicsApi.OPENGL -> MacOsOpenGLRedrawer(layer, properties)
else -> error("No other renderings for native yet")
}
}
}
\ No newline at end of file
package org.jetbrains.skiko.native.redrawer package org.jetbrains.skiko.redrawer
import kotlinx.cinterop.CPointer import kotlinx.cinterop.CPointer
import kotlinx.cinterop.useContents import kotlinx.cinterop.useContents
import org.jetbrains.skiko.native.* import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.SkiaLayerProperties
import platform.CoreFoundation.CFTimeInterval import platform.CoreFoundation.CFTimeInterval
import platform.CoreGraphics.CGRectMake import platform.CoreGraphics.CGRectMake
import platform.CoreVideo.CVTimeStamp import platform.CoreVideo.CVTimeStamp
...@@ -15,10 +15,12 @@ import platform.QuartzCore.* ...@@ -15,10 +15,12 @@ import platform.QuartzCore.*
import kotlin.system.getTimeNanos import kotlin.system.getTimeNanos
internal class MacOsOpenGLRedrawer( internal class MacOsOpenGLRedrawer(
private val layer: HardwareLayer, private val layer: SkiaLayer,
private val properties: SkiaLayerProperties private val properties: SkiaLayerProperties
) : Redrawer { ) : Redrawer {
private var isDisposed = false init {
println("create MacOsOpenGLRedrawer")
}
private val drawLayer = MacosGLLayer(layer, setNeedsDisplayOnBoundsChange = true) private val drawLayer = MacosGLLayer(layer, setNeedsDisplayOnBoundsChange = true)
...@@ -46,28 +48,23 @@ internal class MacOsOpenGLRedrawer( ...@@ -46,28 +48,23 @@ internal class MacOsOpenGLRedrawer(
} }
} }
class MacosGLLayer(val layer: HardwareLayer, setNeedsDisplayOnBoundsChange: Boolean) : CAOpenGLLayer() { class MacosGLLayer(val layer: SkiaLayer, setNeedsDisplayOnBoundsChange: Boolean) : CAOpenGLLayer() {
val container = layer.nsView
init { init {
this.setNeedsDisplayOnBoundsChange(setNeedsDisplayOnBoundsChange) this.setNeedsDisplayOnBoundsChange(setNeedsDisplayOnBoundsChange)
this.removeAllAnimations() this.removeAllAnimations()
this.setAutoresizingMask(kCALayerWidthSizable or kCALayerHeightSizable ) this.setAutoresizingMask(kCALayerWidthSizable or kCALayerHeightSizable )
this.setAsynchronous(true) this.setAsynchronous(true)
container.layer = this layer.nsView.layer = this
container.wantsLayer = true layer.nsView.wantsLayer = true
} }
fun draw() { fun draw() {
println("MacosGLLayer::draw")
layer.update(getTimeNanos()) layer.update(getTimeNanos())
layer.draw() layer.draw()
} }
fun setFrame(x: Int, y: Int, width: Int, height: Int) { fun setFrame(x: Int, y: Int, width: Int, height: Int) {
val newY = container.frame.useContents { size.height } - y - height val newY = layer.nsView.frame.useContents { size.height } - y - height
CATransaction.begin() CATransaction.begin()
CATransaction.setDisableActions(true) CATransaction.setDisableActions(true)
...@@ -80,8 +77,6 @@ class MacosGLLayer(val layer: HardwareLayer, setNeedsDisplayOnBoundsChange: Bool ...@@ -80,8 +77,6 @@ class MacosGLLayer(val layer: HardwareLayer, setNeedsDisplayOnBoundsChange: Bool
// TODO: anything else to dispose the layer? // TODO: anything else to dispose the layer?
} }
protected open fun canDraw() = true
@Suppress("unused") @Suppress("unused")
private fun performDraw() { private fun performDraw() {
try { try {
...@@ -98,7 +93,7 @@ class MacosGLLayer(val layer: HardwareLayer, setNeedsDisplayOnBoundsChange: Bool ...@@ -98,7 +93,7 @@ class MacosGLLayer(val layer: HardwareLayer, setNeedsDisplayOnBoundsChange: Bool
forLayerTime: CFTimeInterval, forLayerTime: CFTimeInterval,
displayTime: CPointer<CVTimeStamp>? displayTime: CPointer<CVTimeStamp>?
): Boolean { ): Boolean {
return canDraw() return true
} }
override fun drawInCGLContext( override fun drawInCGLContext(
......
package org.jetbrains.skiko
internal actual fun makeDefaultSkiaLayerProperties(): SkiaLayerProperties {
return SkiaLayerProperties(true, true)
}
\ No newline at end of file
package org.jetbrains.skiko
import org.jetbrains.skiko.context.*
import org.jetbrains.skiko.redrawer.*
internal expect fun createNativeContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler
internal expect fun createNativeRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer
internal actual fun makeDefaultRenderFactory(): RenderFactory {
return object : RenderFactory {
override fun createContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler {
return createNativeContextHandler(layer, renderApi)
}
override fun createRedrawer(
layer: SkiaLayer,
renderApi: GraphicsApi,
properties: SkiaLayerProperties
): Redrawer {
return createNativeRedrawer(layer, renderApi, properties)
}
}
}
package org.jetbrains.skiko.native.context
import org.jetbrains.skia.*
import org.jetbrains.skiko.native.*
internal expect fun createContextHandler(layer: HardwareLayer): ContextHandler
internal abstract class ContextHandler(val layer: HardwareLayer) {
// TODO: hostOs is all written in jdk kotlin.
// open val bleachConstant = if (hostOs == OS.MacOS) 0 else -1
open val bleachConstant = 0
var context: DirectContext? = null
var renderTarget: BackendRenderTarget? = null
var surface: Surface? = null
var canvas: Canvas? = null
abstract fun initContext(): Boolean
abstract fun initCanvas()
fun clearCanvas() {
println("ContextHandler::clearCanvas")
canvas?.clear(bleachConstant)
}
open fun drawOnCanvas(picture: Picture) {
println("ContextHandler::drawOnCanvas")
canvas?.drawPicture(picture)
}
open fun flush() {
println("ContextHandler::flush")
context?.flush()
}
fun dispose() {
surface?.close()
renderTarget?.close()
}
}
package org.jetbrains.skiko.native
expect abstract class HardwareLayer()
\ No newline at end of file
package org.jetbrains.skiko.native
import org.jetbrains.skiko.redrawer.Redrawer
internal interface PlatformOperations {
fun createRedrawer(layer: HardwareLayer, properties: SkiaLayerProperties): Redrawer
}
// TODO: commonize more.
internal val platformOperations: PlatformOperations by lazy {
makePlatformOperations()
}
internal expect fun makePlatformOperations(): PlatformOperations
package org.jetbrains.skiko.native
class SkiaLayerProperties(
val isVsyncEnabled: Boolean = SkikoProperties.vsyncEnabled
)
\ No newline at end of file
package org.jetbrains.skiko.native
import org.jetbrains.skiko.GraphicsApi
// TODO: jvm version uses java properties here.
// there is no properties support available for native.
internal object SkikoProperties {
val vsyncEnabled: Boolean = true
val renderApi: GraphicsApi by lazy {
GraphicsApi.OPENGL
}
private fun parseRenderApi(text: String?): GraphicsApi {
when(text) {
"SOFTWARE" -> return GraphicsApi.SOFTWARE
"OPENGL" -> return GraphicsApi.OPENGL
else -> return GraphicsApi.OPENGL
}
}
}
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