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