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
import platform.AppKit.*
import org.jetbrains.skia.*
import org.jetbrains.skiko.native.SkiaLayer
import org.jetbrains.skiko.native.SkiaRenderer
import org.jetbrains.skiko.native.SkiaWindow
import org.jetbrains.skiko.*
import kotlinx.cinterop.*
import kotlin.math.cos
import kotlin.math.sin
fun main(args: Array<String>) {
fun main() {
// TODO: Remove me! This is to run all cleaners before main() exits.
kotlin.native.internal.Debugging.forceCheckedShutdown = true
......
......@@ -325,7 +325,11 @@ kotlin {
val skiaBinDir = "$skiaDir/out/${buildType.id}-${osArch.first.id}-${osArch.second.id}"
kotlinOptions {
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",
"-linker-option", "-framework", "-linker-option", "CoreGraphics",
"-linker-option", "-framework", "-linker-option", "CoreText")
......
......@@ -283,7 +283,7 @@ class Surface : RefCnt {
surfaceProps
)
require(ptr != NullPointer) {
"Failed Surface.makeFromBackendRenderTarget($context, $rt, $origin, $colorFormat, $colorSpace)"
"Failed Surface.makeFromBackendRenderTarget"
}
Surface(ptr, context, rt)
} finally {
......
......@@ -6,6 +6,11 @@ class SurfaceProps constructor(
) {
constructor(geo: PixelGeometry) : this(false, geo)
// Used from JNI code.
private fun _getPixelGeometryOrdinal(): Int {
return pixelGeometry.ordinal
}
fun _getFlags(): Int {
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
import org.jetbrains.skia.DirectContext
import org.jetbrains.skia.Picture
import org.jetbrains.skia.Surface
import org.jetbrains.skiko.GraphicsApi
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.hostArch
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) {
open val bleachConstant = if (hostOs == OS.MacOS) 0 else -1
......@@ -35,7 +32,7 @@ internal abstract class ContextHandler(val layer: SkiaLayer) {
context?.flush()
}
fun dispose() {
open fun dispose() {
disposeCanvas()
destroyContext()
}
......@@ -47,9 +44,7 @@ internal abstract class ContextHandler(val layer: SkiaLayer) {
open fun rendererInfo(): String {
return "GraphicsApi: ${layer.renderApi}\n" +
"OS: $hostFullName\n" +
"Java: $javaVendor\n" +
"Java location: $javaLocation\n"
"OS: ${hostOs.id} ${hostArch.id}\n"
}
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.redrawer.Redrawer
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties
internal class IosOpenGLRedrawer(
private val layer: HardwareLayer,
internal class OpenGLRedrawer(
private val layer: SkiaLayer,
private val properties: SkiaLayerProperties
) : Redrawer {
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
import java.awt.Component
interface ClipRectangle {
val x: Float
val y: Float
val width: Float
val height: Float
}
class ClipComponent(val component: Component) : ClipRectangle {
override val x: Float
get() = component.x.toFloat()
......
......@@ -24,7 +24,7 @@ internal open class HardwareLayer : Canvas() {
useDrawingSurfacePlatformInfo(::nativeInit)
}
fun dispose() {
open fun dispose() {
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
import javax.swing.JPanel
import javax.swing.SwingUtilities.isEventDispatchThread
interface SkiaRenderer {
fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long)
}
private class PictureHolder(val instance: Picture, val width: Int, val height: Int)
open class SkiaLayer internal constructor(
private val properties: SkiaLayerProperties = SkiaLayerProperties(),
actual open class SkiaLayer internal constructor(
private val properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties(),
private val renderFactory: RenderFactory
) : JPanel() {
companion object {
......@@ -34,7 +28,7 @@ open class SkiaLayer internal constructor(
internal val backedLayer: HardwareLayer
constructor(
properties: SkiaLayerProperties = SkiaLayerProperties()
properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties()
) : this(properties, RenderFactory.Default)
val canvas: java.awt.Canvas
......@@ -95,7 +89,7 @@ open class SkiaLayer internal constructor(
return isShowingCached
}
val contentScale: Float
actual val contentScale: Float
get() = backedLayer.contentScale
val contentHandle: Long
......@@ -119,7 +113,7 @@ open class SkiaLayer internal constructor(
private var contextHandler: ContextHandler? = null
private val fallbackRenderApiQueue = SkikoProperties.fallbackRenderApiQueue.toMutableList()
private var renderApi_ = fallbackRenderApiQueue[0]
var renderApi: GraphicsApi
actual var renderApi: GraphicsApi
get() = renderApi_
private set(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
import javax.swing.JFrame
open class SkiaWindow(
properties: SkiaLayerProperties = SkiaLayerProperties(),
properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties(),
layerFactory: () -> SkiaLayer = { SkiaLayer(properties) }
) : JFrame() {
val layer = layerFactory()
......
package org.jetbrains.skiko.redrawer
import org.jetbrains.skia.Surface
import kotlinx.coroutines.*
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.*
internal class LinuxSoftwareRedrawer(
......
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.SkiaLayerProperties
import org.jetbrains.skiko.RenderException
......
......@@ -233,7 +233,7 @@ class SkiaWindowTest {
@Test(timeout = 60000)
fun `stress test - resize and paint immediately`() = swingTest {
fun openWindow() = SkiaWindow(
properties = SkiaLayerProperties(isVsyncEnabled = false)
properties = SkiaLayerProperties(isVsyncEnabled = false, isVsyncFramelimitFallbackEnabled = true)
).apply {
setLocation(200,200)
setSize(400, 200)
......@@ -256,7 +256,7 @@ class SkiaWindowTest {
@Test(timeout = 60000)
fun `stress test - open and paint immediately`() = swingTest {
fun openWindow() = SkiaWindow(
properties = SkiaLayerProperties(isVsyncEnabled = false)
properties = SkiaLayerProperties(isVsyncEnabled = false, isVsyncFramelimitFallbackEnabled = true)
).apply {
setLocation(200,200)
setSize(400, 200)
......@@ -415,7 +415,8 @@ class SkiaWindowTest {
val window = SkiaWindow(
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 org.jetbrains.skiko.native.context.*
import org.jetbrains.skiko.context.*
import org.jetbrains.skia.*
import org.jetbrains.skiko.redrawer.Redrawer
import platform.AppKit.NSView
import platform.Foundation.NSMakeRect
interface SkiaRenderer {
fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long)
}
actual open class SkiaLayer(
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!
private class PictureHolder(val instance: Picture, val width: Int, val height: Int)
val nsView = NSView(NSMakeRect(0.0, 0.0, 640.0, 480.0))
var _contentScale: Float = 1.0f
open class SkiaLayer(
private val properties: SkiaLayerProperties = SkiaLayerProperties()
) : HardwareLayer() {
var renderer: SkiaRenderer? = null
internal var skiaState = createContextHandler(this)
private var isDisposed = false
private var contextHandler = MacOSOpenGLContextHandler(this)
private var redrawer: Redrawer? = null
private var picture: PictureHolder? = null
private val pictureRecorder = PictureRecorder()
private val pictureLock = Any()
override fun init() {
println("SkiaLayer::init")
super.init()
redrawer = platformOperations.createRedrawer(this, properties)
fun initLayer() {
println("SkiaLayer.initLayer")
redrawer = createNativeRedrawer(this, GraphicsApi.OPENGL, properties)
redrawer?.redrawImmediately()
}
override fun dispose() {
fun disposeLayer() {
redrawer?.dispose()
super.dispose()
redrawer = null
initedCanvas = false
}
fun needRedraw() {
redrawer?.needRedraw()
}
override fun update(nanoTime: Long) {
println("SkiaLayer::update")
fun update(nanoTime: Long) {
println("SkiaLayer.update")
val width = nsView.frame.useContents { size.width }
val height = nsView.frame.useContents { size.height }
......@@ -60,17 +59,22 @@ open class SkiaLayer(
this.picture = PictureHolder(picture, pictureWidth.toInt(), pictureHeight.toInt())
}
override fun draw() {
println("SkiaLayer::draw")
skiaState.apply {
private var initedCanvas = false
fun draw() {
println("SkiaLayer.draw")
contextHandler.apply {
if (!initedCanvas) {
if (!initContext()) {
error("initContext() failure. No fallback to raster for Skia/native yet.")
error("initContext() failure")
return
}
initCanvas()
initedCanvas = true
}
clearCanvas()
val picture = picture
println("SkiaLayer::draw: picture=$picture")
println("SkiaLayer.draw: picture=$picture")
if (picture != null) {
drawOnCanvas(picture.instance)
}
......
package org.jetbrains.skiko.native
package org.jetbrains.skiko
import platform.AppKit.*
import platform.Cocoa.*
import platform.Foundation.*
open class SkiaWindow(
properties: SkiaLayerProperties = SkiaLayerProperties()
properties: SkiaLayerProperties = makeDefaultSkiaLayerProperties()
) {
val windowStyle =
private val windowStyle =
NSWindowStyleMaskTitled or
NSWindowStyleMaskMiniaturizable or
NSWindowStyleMaskClosable or
......@@ -26,7 +25,7 @@ open class SkiaWindow(
val layer = SkiaLayer(properties)
init {
nsWindow.contentView?.addSubview(layer.nsView)
layer.checkIsShowing() // TODO: The awt versions has hierarchy listener. What should we use here?
nsWindow.contentView!!.addSubview(layer.nsView)
layer.initLayer()
}
}
package org.jetbrains.skiko.native.context
package org.jetbrains.skiko.context
import kotlinx.cinterop.*
import org.jetbrains.skia.*
import org.jetbrains.skiko.native.*
import org.jetbrains.skiko.SkiaLayer
import platform.OpenGL.GL_DRAW_FRAMEBUFFER_BINDING
import platform.OpenGL.glGetIntegerv
import platform.OpenGL.*
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 MacOSOpenGLContextHandler(layer: SkiaLayer) : ContextHandler(layer) {
override fun initContext(): Boolean {
println("OpenGLContextHandler::initContext")
println("MacOSOpenGLContextHandler.initContext")
try {
if (context == null) {
context = DirectContext.makeGL()
......@@ -43,11 +32,8 @@ internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer
return result
}
@ExperimentalUnsignedTypes
override fun initCanvas() {
println("OpenGLContextHandler::initCanvas")
dispose()
println("MacOSOpenGLContextHandler.initCanvas")
val scale = layer.contentScale
val w = (layer.nsView.frame.useContents { size.width } * scale).toInt().coerceAtLeast(0)
val h = (layer.nsView.frame.useContents { size.height } * scale).toInt().coerceAtLeast(0)
......@@ -69,7 +55,7 @@ internal class OpenGLContextHandler(layer: HardwareLayer) : ContextHandler(layer
ColorSpace.sRGB
)
canvas = surface!!.canvas
canvas = surface?.canvas
?: 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.useContents
import org.jetbrains.skiko.native.*
import org.jetbrains.skiko.redrawer.Redrawer
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties
import platform.CoreFoundation.CFTimeInterval
import platform.CoreGraphics.CGRectMake
import platform.CoreVideo.CVTimeStamp
......@@ -15,10 +15,12 @@ import platform.QuartzCore.*
import kotlin.system.getTimeNanos
internal class MacOsOpenGLRedrawer(
private val layer: HardwareLayer,
private val layer: SkiaLayer,
private val properties: SkiaLayerProperties
) : Redrawer {
private var isDisposed = false
init {
println("create MacOsOpenGLRedrawer")
}
private val drawLayer = MacosGLLayer(layer, setNeedsDisplayOnBoundsChange = true)
......@@ -46,28 +48,23 @@ internal class MacOsOpenGLRedrawer(
}
}
class MacosGLLayer(val layer: HardwareLayer, setNeedsDisplayOnBoundsChange: Boolean) : CAOpenGLLayer() {
val container = layer.nsView
class MacosGLLayer(val layer: SkiaLayer, setNeedsDisplayOnBoundsChange: Boolean) : CAOpenGLLayer() {
init {
this.setNeedsDisplayOnBoundsChange(setNeedsDisplayOnBoundsChange)
this.removeAllAnimations()
this.setAutoresizingMask(kCALayerWidthSizable or kCALayerHeightSizable )
this.setAsynchronous(true)
container.layer = this
container.wantsLayer = true
layer.nsView.layer = this
layer.nsView.wantsLayer = true
}
fun draw() {
println("MacosGLLayer::draw")
layer.update(getTimeNanos())
layer.draw()
}
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.setDisableActions(true)
......@@ -80,8 +77,6 @@ class MacosGLLayer(val layer: HardwareLayer, setNeedsDisplayOnBoundsChange: Bool
// TODO: anything else to dispose the layer?
}
protected open fun canDraw() = true
@Suppress("unused")
private fun performDraw() {
try {
......@@ -98,7 +93,7 @@ class MacosGLLayer(val layer: HardwareLayer, setNeedsDisplayOnBoundsChange: Bool
forLayerTime: CFTimeInterval,
displayTime: CPointer<CVTimeStamp>?
): Boolean {
return canDraw()
return true
}
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