Commit cb46d6d2 authored by Roman Sedaikin's avatar Roman Sedaikin

Implemented a fallback rendering API queue. Added recycling of DirectX devices.

parent d66910d3
...@@ -184,7 +184,7 @@ HRESULT CreateDXGIFactory2( ...@@ -184,7 +184,7 @@ HRESULT CreateDXGIFactory2(
} }
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_createDevice( JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_createDirectXDevice(
JNIEnv *env, jobject redrawer, jlong windowHandle) JNIEnv *env, jobject redrawer, jlong windowHandle)
{ {
DirectXDevice *d3dDevice = new DirectXDevice(); DirectXDevice *d3dDevice = new DirectXDevice();
...@@ -279,6 +279,13 @@ HRESULT CreateDXGIFactory2( ...@@ -279,6 +279,13 @@ HRESULT CreateDXGIFactory2(
WaitForSingleObjectEx(d3dDevice->fenceEvent, INFINITE, FALSE); WaitForSingleObjectEx(d3dDevice->fenceEvent, INFINITE, FALSE);
} }
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_Direct3DRedrawer_disposeDevice(
JNIEnv *env, jobject redrawer, jlong devicePtr)
{
DirectXDevice *d3dDevice = fromJavaPointer<DirectXDevice*>(devicePtr);
delete d3dDevice;
}
} }
#endif #endif
package org.jetbrains.skiko package org.jetbrains.skiko
import org.jetbrains.skiko.SkikoProperties.renderApi
import org.jetbrains.skiko.redrawer.LinuxOpenGLRedrawer import org.jetbrains.skiko.redrawer.LinuxOpenGLRedrawer
import org.jetbrains.skiko.redrawer.MacOsOpenGLRedrawer import org.jetbrains.skiko.redrawer.MacOsOpenGLRedrawer
import org.jetbrains.skiko.redrawer.SoftwareRedrawer import org.jetbrains.skiko.redrawer.SoftwareRedrawer
...@@ -15,7 +14,7 @@ internal interface PlatformOperations { ...@@ -15,7 +14,7 @@ internal interface PlatformOperations {
fun isFullscreen(component: Component): Boolean fun isFullscreen(component: Component): Boolean
fun setFullscreen(component: Component, value: Boolean) fun setFullscreen(component: Component, value: Boolean)
fun getDpiScale(component: Component): Float fun getDpiScale(component: Component): Float
fun createRedrawer(layer: HardwareLayer): Redrawer fun createRedrawer(layer: HardwareLayer, renderApi: GraphicsApi): Redrawer
} }
internal val platformOperations: PlatformOperations by lazy { internal val platformOperations: PlatformOperations by lazy {
...@@ -33,7 +32,7 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -33,7 +32,7 @@ internal val platformOperations: PlatformOperations by lazy {
return component.graphicsConfiguration.defaultTransform.scaleX.toFloat() return component.graphicsConfiguration.defaultTransform.scaleX.toFloat()
} }
override fun createRedrawer(layer: HardwareLayer) = when(renderApi) { override fun createRedrawer(layer: HardwareLayer, renderApi: GraphicsApi) = when (renderApi) {
GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer) GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer)
else -> MacOsOpenGLRedrawer(layer) else -> MacOsOpenGLRedrawer(layer)
} }
...@@ -56,7 +55,7 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -56,7 +55,7 @@ internal val platformOperations: PlatformOperations by lazy {
return component.graphicsConfiguration.defaultTransform.scaleX.toFloat() return component.graphicsConfiguration.defaultTransform.scaleX.toFloat()
} }
override fun createRedrawer(layer: HardwareLayer) = when(renderApi) { override fun createRedrawer(layer: HardwareLayer, renderApi: GraphicsApi) = when (renderApi) {
GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer) GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer)
GraphicsApi.DIRECT3D -> Direct3DRedrawer(layer) GraphicsApi.DIRECT3D -> Direct3DRedrawer(layer)
else -> WindowsOpenGLRedrawer(layer) else -> WindowsOpenGLRedrawer(layer)
...@@ -93,7 +92,7 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -93,7 +92,7 @@ internal val platformOperations: PlatformOperations by lazy {
// return component.useDrawingSurfacePlatformInfo(::linuxGetDpiScaleNative) // return component.useDrawingSurfacePlatformInfo(::linuxGetDpiScaleNative)
} }
override fun createRedrawer(layer: HardwareLayer) = when(renderApi) { override fun createRedrawer(layer: HardwareLayer, renderApi: GraphicsApi) = when (renderApi) {
GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer) GraphicsApi.SOFTWARE -> SoftwareRedrawer(layer)
else -> LinuxOpenGLRedrawer(layer) else -> LinuxOpenGLRedrawer(layer)
} }
......
...@@ -11,6 +11,8 @@ import org.jetbrains.skiko.redrawer.SoftwareRedrawer ...@@ -11,6 +11,8 @@ import org.jetbrains.skiko.redrawer.SoftwareRedrawer
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.redrawer.Redrawer
import java.awt.Graphics import java.awt.Graphics
import javax.swing.SwingUtilities.isEventDispatchThread import javax.swing.SwingUtilities.isEventDispatchThread
import kotlin.collections.MutableList
import kotlin.collections.toMutableList
interface SkiaRenderer { interface SkiaRenderer {
fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long)
...@@ -19,10 +21,11 @@ interface SkiaRenderer { ...@@ -19,10 +21,11 @@ interface SkiaRenderer {
private class PictureHolder(val instance: Picture, val width: Int, val height: Int) private class PictureHolder(val instance: Picture, val width: Int, val height: Int)
open class SkiaLayer : HardwareLayer() { open class SkiaLayer : HardwareLayer() {
val fallbackRenderApiQueue = SkikoProperties.fallbackRenderApiQueue.toMutableList()
var renderer: SkiaRenderer? = null var renderer: SkiaRenderer? = null
val clipComponents = mutableListOf<ClipRectangle>() val clipComponents = mutableListOf<ClipRectangle>()
private var contextHandler = createContextHandler(this) private var contextHandler = createContextHandler(this, SkikoProperties.renderApi)
@Volatile @Volatile
private var isDisposed = false private var isDisposed = false
...@@ -35,7 +38,7 @@ open class SkiaLayer : HardwareLayer() { ...@@ -35,7 +38,7 @@ open class SkiaLayer : HardwareLayer() {
override fun init() { override fun init() {
super.init() super.init()
redrawer = platformOperations.createRedrawer(this) redrawer = platformOperations.createRedrawer(this, SkikoProperties.renderApi)
redrawer?.syncSize() redrawer?.syncSize()
redrawer?.redrawImmediately() redrawer?.redrawImmediately()
} }
...@@ -43,6 +46,7 @@ open class SkiaLayer : HardwareLayer() { ...@@ -43,6 +46,7 @@ open class SkiaLayer : HardwareLayer() {
override fun dispose() { override fun dispose() {
check(!isDisposed) check(!isDisposed)
check(isEventDispatchThread()) check(isEventDispatchThread())
contextHandler.dispose()
redrawer?.dispose() redrawer?.dispose()
picture?.instance?.close() picture?.instance?.close()
pictureRecorder.close() pictureRecorder.close()
...@@ -104,7 +108,7 @@ open class SkiaLayer : HardwareLayer() { ...@@ -104,7 +108,7 @@ open class SkiaLayer : HardwareLayer() {
check(!isDisposed) check(!isDisposed)
contextHandler.apply { contextHandler.apply {
if (!initContext()) { if (!initContext()) {
fallbackToRaster() fallbackToNextApi()
return return
} }
initCanvas() initCanvas()
...@@ -133,11 +137,12 @@ open class SkiaLayer : HardwareLayer() { ...@@ -133,11 +137,12 @@ open class SkiaLayer : HardwareLayer() {
) )
} }
private fun fallbackToRaster() { private fun fallbackToNextApi() {
println("Falling back to software rendering...") val nextApi = fallbackRenderApiQueue.removeAt(0)
println("Falling back to $nextApi rendering...")
redrawer?.dispose() redrawer?.dispose()
contextHandler = SoftwareContextHandler(this) contextHandler = createContextHandler(this, nextApi)
redrawer = SoftwareRedrawer(this) redrawer = platformOperations.createRedrawer(this, nextApi)
needRedraw() needRedraw()
} }
} }
...@@ -49,6 +49,14 @@ internal object SkikoProperties { ...@@ -49,6 +49,14 @@ internal object SkikoProperties {
} }
} }
val fallbackRenderApiQueue : List<GraphicsApi> by lazy {
when (hostOs) {
OS.MacOS -> listOf(GraphicsApi.SOFTWARE)
OS.Linux -> listOf(GraphicsApi.SOFTWARE)
OS.Windows -> listOf(GraphicsApi.OPENGL, GraphicsApi.SOFTWARE)
}
}
private fun property(name: String, default: Boolean) = lazy { private fun property(name: String, default: Boolean) = lazy {
System.getProperty(name)?.toBoolean() ?: default System.getProperty(name)?.toBoolean() ?: default
} }
......
...@@ -12,8 +12,8 @@ import org.jetbrains.skiko.SkikoProperties ...@@ -12,8 +12,8 @@ import org.jetbrains.skiko.SkikoProperties
import org.jetbrains.skiko.hostOs import org.jetbrains.skiko.hostOs
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.redrawer.Redrawer
internal fun createContextHandler(layer: SkiaLayer): ContextHandler { internal fun createContextHandler(layer: SkiaLayer, renderApi: GraphicsApi): ContextHandler {
return when (SkikoProperties.renderApi) { return when (renderApi) {
GraphicsApi.SOFTWARE -> SoftwareContextHandler(layer) GraphicsApi.SOFTWARE -> SoftwareContextHandler(layer)
GraphicsApi.OPENGL -> OpenGLContextHandler(layer) GraphicsApi.OPENGL -> OpenGLContextHandler(layer)
GraphicsApi.DIRECT3D -> Direct3DContextHandler(layer) GraphicsApi.DIRECT3D -> Direct3DContextHandler(layer)
......
...@@ -20,12 +20,14 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer) ...@@ -20,12 +20,14 @@ internal class Direct3DContextHandler(layer: SkiaLayer) : ContextHandler(layer)
override fun initContext(): Boolean { override fun initContext(): Boolean {
try { try {
if (context == null) { if (context == null) {
device = directXRedrawer.createDevice(layer.windowHandle) device = directXRedrawer.createDevice()
if (device == 0L) return false if (device == 0L) {
throw Exception("Failed to create DirectX12 device.")
}
context = directXRedrawer.makeContext(device) context = directXRedrawer.makeContext(device)
} }
} catch (e: Exception) { } catch (e: Exception) {
println("Failed to create Skia Direct3D context!\n ${e.stackTrace}") println("${e.message}\nFailed to create Skia Direct3D context!")
return false return false
} }
return true return true
......
...@@ -11,6 +11,8 @@ internal class Direct3DRedrawer( ...@@ -11,6 +11,8 @@ internal class Direct3DRedrawer(
private val layer: HardwareLayer private val layer: HardwareLayer
) : Redrawer { ) : Redrawer {
private var device: Long = 0
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) { private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
layer.update(System.nanoTime()) layer.update(System.nanoTime())
layer.draw() layer.draw()
...@@ -18,6 +20,7 @@ internal class Direct3DRedrawer( ...@@ -18,6 +20,7 @@ internal class Direct3DRedrawer(
override fun dispose() { override fun dispose() {
frameDispatcher.cancel() frameDispatcher.cancel()
disposeDevice(device)
} }
override fun needRedraw() { override fun needRedraw() {
...@@ -37,9 +40,15 @@ internal class Direct3DRedrawer( ...@@ -37,9 +40,15 @@ internal class Direct3DRedrawer(
makeDirectXRenderTarget(device, width, height) makeDirectXRenderTarget(device, width, height)
) )
external fun createDevice(windowHandle: Long): Long fun createDevice(): Long {
device = createDirectXDevice(layer.windowHandle)
return device
}
external fun createDirectXDevice(windowHandle: Long): Long
external fun makeDirectXContext(device: Long): Long external fun makeDirectXContext(device: Long): Long
external fun makeDirectXRenderTarget(device: Long, width: Int, height: Int): Long external fun makeDirectXRenderTarget(device: Long, width: Int, height: Int): Long
external fun resizeBuffers(device: Long, width: Int, height: Int) external fun resizeBuffers(device: Long, width: Int, height: Int)
external fun finishFrame(device: Long, context: Long, surface: Long) external fun finishFrame(device: Long, context: Long, surface: Long)
external fun disposeDevice(device: Long)
} }
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