Unverified Commit f6f67b81 authored by Igor Demin's avatar Igor Demin Committed by GitHub

Merge pull request #55 from JetBrains/immediate-redraw

Immediate redraw on resize and window start
parents 6ad0a4e6 98358124
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="SkijaInjectSample (software)" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$/samples/SkijaInjectSample" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="-Dskiko.renderApi=SOFTWARE" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="run" />
</list>
</option>
<option name="vmOptions" value="" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2">
<option name="Gradle.BeforeRunTask" enabled="false" tasks="publishToMavenLocal" externalProjectPath="$PROJECT_DIR$/skiko" vmOptions="" scriptParameters="" />
</method>
</configuration>
</component>
\ No newline at end of file
...@@ -89,7 +89,7 @@ class Renderer( ...@@ -89,7 +89,7 @@ class Renderer(
var canvas: Canvas? = null var canvas: Canvas? = null
override suspend fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
this.canvas = canvas this.canvas = canvas
val contentScale = layer.contentScale val contentScale = layer.contentScale
canvas.scale(contentScale, contentScale) canvas.scale(contentScale, contentScale)
......
...@@ -73,7 +73,7 @@ native crash in SkiaWindowTest "render single window" ...@@ -73,7 +73,7 @@ native crash in SkiaWindowTest "render single window"
setSize(width, height) setSize(width, height)
defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
layer.renderer = object : SkiaRenderer { layer.renderer = object : SkiaRenderer {
override suspend fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
if (canCollect && frameTimes.size < frameCount) { if (canCollect && frameTimes.size < frameCount) {
frameTimes.add(System.nanoTime()) // we check the real time, not the time provided by the argument frameTimes.add(System.nanoTime()) // we check the real time, not the time provided by the argument
} }
...@@ -183,7 +183,7 @@ j org.jetbrains.skiko.redrawer.MacOsRedrawer$drawLayer$1.draw()V+7 ...@@ -183,7 +183,7 @@ j org.jetbrains.skiko.redrawer.MacOsRedrawer$drawLayer$1.draw()V+7
var t1 = Long.MAX_VALUE var t1 = Long.MAX_VALUE
val refreshRate = window.graphicsConfiguration.device.displayMode.refreshRate val refreshRate = window.graphicsConfiguration.device.displayMode.refreshRate
override suspend fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
val t2 = System.nanoTime() val t2 = System.nanoTime()
val frameTime = (t2 - t1).coerceAtLeast(0) val frameTime = (t2 - t1).coerceAtLeast(0)
t1 = t2 t1 = t2
......
...@@ -138,7 +138,7 @@ class SkiaWindowTest { ...@@ -138,7 +138,7 @@ class SkiaWindowTest {
window.setSize(40, 20) window.setSize(40, 20)
window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE window.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE
window.layer.renderer = object : SkiaRenderer { window.layer.renderer = object : SkiaRenderer {
override suspend fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
renderCount++ renderCount++
} }
} }
...@@ -231,7 +231,7 @@ class SkiaWindowTest { ...@@ -231,7 +231,7 @@ class SkiaWindowTest {
val paragraph by lazy { paragraph(window.layer.contentScale * 40, "=-+Нп") } val paragraph by lazy { paragraph(window.layer.contentScale * 40, "=-+Нп") }
window.layer.renderer = object : SkiaRenderer { window.layer.renderer = object : SkiaRenderer {
override suspend fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
paragraph.layout(Float.POSITIVE_INFINITY) paragraph.layout(Float.POSITIVE_INFINITY)
paragraph.paint(canvas, 0f, 0f) paragraph.paint(canvas, 0f, 0f)
} }
...@@ -259,7 +259,7 @@ class SkiaWindowTest { ...@@ -259,7 +259,7 @@ class SkiaWindowTest {
var rectHeight: Int, var rectHeight: Int,
private val rectColor: Color private val rectColor: Color
) : SkiaRenderer { ) : SkiaRenderer {
override suspend fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
val dpi = layer.contentScale val dpi = layer.contentScale
canvas.drawRect(Rect(0f, 0f, width.toFloat(), height.toFloat()), Paint().apply { canvas.drawRect(Rect(0f, 0f, width.toFloat(), height.toFloat()), Paint().apply {
color = Color.WHITE.rgb color = Color.WHITE.rgb
...@@ -278,7 +278,7 @@ class SkiaWindowTest { ...@@ -278,7 +278,7 @@ class SkiaWindowTest {
private var oldNanoTime = Long.MAX_VALUE private var oldNanoTime = Long.MAX_VALUE
private var x = 0.0 private var x = 0.0
override suspend fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) { override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
canvas.clear(Color.WHITE.rgb) canvas.clear(Color.WHITE.rgb)
val dt = (nanoTime - oldNanoTime).coerceAtLeast(0) / 1E9 val dt = (nanoTime - oldNanoTime).coerceAtLeast(0) / 1E9
......
...@@ -14,7 +14,7 @@ extern "C" jboolean Skiko_GetAWT(JNIEnv *env, JAWT *awt); ...@@ -14,7 +14,7 @@ extern "C" jboolean Skiko_GetAWT(JNIEnv *env, JAWT *awt);
extern "C" extern "C"
{ {
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_lockDrawingSurfaceNative(JNIEnv *env, jobject redrawer, jobject layer) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_lockDrawingSurfaceNative(JNIEnv *env, jobject redrawer, jobject layer)
{ {
JAWT awt; JAWT awt;
awt.version = (jint)JAWT_VERSION_9; awt.version = (jint)JAWT_VERSION_9;
...@@ -30,7 +30,7 @@ extern "C" ...@@ -30,7 +30,7 @@ extern "C"
return static_cast<jlong>(reinterpret_cast<uintptr_t>(ds)); return static_cast<jlong>(reinterpret_cast<uintptr_t>(ds));
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_unlockDrawingSurfaceNative(JNIEnv *env, jobject redrawer, jlong drawingSurfacePtr) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_unlockDrawingSurfaceNative(JNIEnv *env, jobject redrawer, jlong drawingSurfacePtr)
{ {
JAWT_DrawingSurface *ds = reinterpret_cast<JAWT_DrawingSurface *>(static_cast<uintptr_t>(drawingSurfacePtr)); JAWT_DrawingSurface *ds = reinterpret_cast<JAWT_DrawingSurface *>(static_cast<uintptr_t>(drawingSurfacePtr));
JAWT awt; JAWT awt;
...@@ -47,7 +47,7 @@ extern "C" ...@@ -47,7 +47,7 @@ extern "C"
return static_cast<jlong>(reinterpret_cast<uintptr_t>(ds)); return static_cast<jlong>(reinterpret_cast<uintptr_t>(ds));
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_getDisplay(JNIEnv *env, jobject redrawer, jlong drawingSurfacePtr) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_getDisplay(JNIEnv *env, jobject redrawer, jlong drawingSurfacePtr)
{ {
JAWT_DrawingSurface *ds = reinterpret_cast<JAWT_DrawingSurface *>(static_cast<uintptr_t>(drawingSurfacePtr)); JAWT_DrawingSurface *ds = reinterpret_cast<JAWT_DrawingSurface *>(static_cast<uintptr_t>(drawingSurfacePtr));
JAWT_DrawingSurfaceInfo *dsi = ds->GetDrawingSurfaceInfo(ds); JAWT_DrawingSurfaceInfo *dsi = ds->GetDrawingSurfaceInfo(ds);
...@@ -59,7 +59,7 @@ extern "C" ...@@ -59,7 +59,7 @@ extern "C"
return static_cast<jlong>(reinterpret_cast<uintptr_t>(display)); return static_cast<jlong>(reinterpret_cast<uintptr_t>(display));
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_getWindow(JNIEnv *env, jobject redrawer, jlong drawingSurfacePtr) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_getWindow(JNIEnv *env, jobject redrawer, jlong drawingSurfacePtr)
{ {
JAWT_DrawingSurface *ds = reinterpret_cast<JAWT_DrawingSurface *>(static_cast<uintptr_t>(drawingSurfacePtr)); JAWT_DrawingSurface *ds = reinterpret_cast<JAWT_DrawingSurface *>(static_cast<uintptr_t>(drawingSurfacePtr));
JAWT_DrawingSurfaceInfo *dsi = ds->GetDrawingSurfaceInfo(ds); JAWT_DrawingSurfaceInfo *dsi = ds->GetDrawingSurfaceInfo(ds);
...@@ -71,7 +71,7 @@ extern "C" ...@@ -71,7 +71,7 @@ extern "C"
return static_cast<jlong>(reinterpret_cast<uintptr_t>(window)); return static_cast<jlong>(reinterpret_cast<uintptr_t>(window));
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_setSwapInterval(JNIEnv *env, jobject redrawer, jlong displayPtr, jlong windowPtr, jint interval) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_setSwapInterval(JNIEnv *env, jobject redrawer, jlong displayPtr, jlong windowPtr, jint interval)
{ {
Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr)); Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr));
Window window = reinterpret_cast<Window>(static_cast<uintptr_t>(windowPtr)); Window window = reinterpret_cast<Window>(static_cast<uintptr_t>(windowPtr));
...@@ -104,7 +104,7 @@ extern "C" ...@@ -104,7 +104,7 @@ extern "C"
} }
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_swapBuffers(JNIEnv *env, jobject redrawer, jlong displayPtr, jlong windowPtr) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_swapBuffers(JNIEnv *env, jobject redrawer, jlong displayPtr, jlong windowPtr)
{ {
Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr)); Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr));
Window window = reinterpret_cast<Window>(static_cast<uintptr_t>(windowPtr)); Window window = reinterpret_cast<Window>(static_cast<uintptr_t>(windowPtr));
...@@ -112,7 +112,7 @@ extern "C" ...@@ -112,7 +112,7 @@ extern "C"
glXSwapBuffers(display, window); glXSwapBuffers(display, window);
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_makeCurrent(JNIEnv *env, jobject redrawer, jlong displayPtr, jlong windowPtr, jlong contextPtr) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_makeCurrent(JNIEnv *env, jobject redrawer, jlong displayPtr, jlong windowPtr, jlong contextPtr)
{ {
Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr)); Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr));
Window window = reinterpret_cast<Window>(static_cast<uintptr_t>(windowPtr)); Window window = reinterpret_cast<Window>(static_cast<uintptr_t>(windowPtr));
...@@ -121,7 +121,7 @@ extern "C" ...@@ -121,7 +121,7 @@ extern "C"
glXMakeCurrent(display, window, *context); glXMakeCurrent(display, window, *context);
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_createContext(JNIEnv *env, jobject redrawer, jlong displayPtr) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_createContext(JNIEnv *env, jobject redrawer, jlong displayPtr)
{ {
Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr)); Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr));
GLint att[] = {GLX_RGBA, GLX_DOUBLEBUFFER, True, None}; GLint att[] = {GLX_RGBA, GLX_DOUBLEBUFFER, True, None};
...@@ -131,7 +131,7 @@ extern "C" ...@@ -131,7 +131,7 @@ extern "C"
return static_cast<jlong>(reinterpret_cast<uintptr_t>(context)); return static_cast<jlong>(reinterpret_cast<uintptr_t>(context));
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_LinuxRedrawerKt_destroyContext(JNIEnv *env, jobject redrawer, jlong displayPtr, jlong contextPtr) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_LinuxOpenGLRedrawerKt_destroyContext(JNIEnv *env, jobject redrawer, jlong displayPtr, jlong contextPtr)
{ {
Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr)); Display *display = reinterpret_cast<Display *>(static_cast<uintptr_t>(displayPtr));
GLXContext *context = reinterpret_cast<GLXContext *>(static_cast<uintptr_t>(contextPtr)); GLXContext *context = reinterpret_cast<GLXContext *>(static_cast<uintptr_t>(contextPtr));
......
...@@ -8,7 +8,7 @@ extern "C" jboolean Skiko_GetAWT(JNIEnv *env, JAWT *awt); ...@@ -8,7 +8,7 @@ extern "C" jboolean Skiko_GetAWT(JNIEnv *env, JAWT *awt);
extern "C" extern "C"
{ {
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_WindowsRedrawerKt_getDevice(JNIEnv *env, jobject redrawer, jobject layer) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_getDevice(JNIEnv *env, jobject redrawer, jobject layer)
{ {
JAWT awt; JAWT awt;
awt.version = (jint)JAWT_VERSION_9; awt.version = (jint)JAWT_VERSION_9;
...@@ -48,7 +48,7 @@ extern "C" ...@@ -48,7 +48,7 @@ extern "C"
return static_cast<jlong>(reinterpret_cast<uintptr_t>(device)); return static_cast<jlong>(reinterpret_cast<uintptr_t>(device));
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsRedrawerKt_setSwapInterval(JNIEnv *env, jobject redrawer, jint interval) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_setSwapInterval(JNIEnv *env, jobject redrawer, jint interval)
{ {
typedef BOOL (WINAPI *PFNWGLSWAPINTERVALEXTPROC)(int interval); typedef BOOL (WINAPI *PFNWGLSWAPINTERVALEXTPROC)(int interval);
// according to [https://opengl.gpuinfo.org/listreports.php?extension=WGL_EXT_swap_control&option=not] (filter by OS=windows) // according to [https://opengl.gpuinfo.org/listreports.php?extension=WGL_EXT_swap_control&option=not] (filter by OS=windows)
...@@ -60,32 +60,32 @@ extern "C" ...@@ -60,32 +60,32 @@ extern "C"
} }
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsRedrawerKt_swapBuffers(JNIEnv *env, jobject redrawer, jlong devicePtr) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_swapBuffers(JNIEnv *env, jobject redrawer, jlong devicePtr)
{ {
HDC device = reinterpret_cast<HDC>(static_cast<uintptr_t>(devicePtr)); HDC device = reinterpret_cast<HDC>(static_cast<uintptr_t>(devicePtr));
SwapBuffers(device); SwapBuffers(device);
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsRedrawerKt_makeCurrent(JNIEnv *env, jobject redrawer, jlong devicePtr, jlong contextPtr) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_makeCurrent(JNIEnv *env, jobject redrawer, jlong devicePtr, jlong contextPtr)
{ {
HDC device = reinterpret_cast<HDC>(static_cast<uintptr_t>(devicePtr)); HDC device = reinterpret_cast<HDC>(static_cast<uintptr_t>(devicePtr));
HGLRC context = reinterpret_cast<HGLRC>(static_cast<uintptr_t>(contextPtr)); HGLRC context = reinterpret_cast<HGLRC>(static_cast<uintptr_t>(contextPtr));
wglMakeCurrent(device, context); wglMakeCurrent(device, context);
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_WindowsRedrawerKt_createContext(JNIEnv *env, jobject redrawer, jlong devicePtr) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_createContext(JNIEnv *env, jobject redrawer, jlong devicePtr)
{ {
HDC device = reinterpret_cast<HDC>(static_cast<uintptr_t>(devicePtr)); HDC device = reinterpret_cast<HDC>(static_cast<uintptr_t>(devicePtr));
return static_cast<jlong>(reinterpret_cast<uintptr_t>(wglCreateContext(device))); return static_cast<jlong>(reinterpret_cast<uintptr_t>(wglCreateContext(device)));
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsRedrawerKt_deleteContext(JNIEnv *env, jobject redrawer, jlong contextPtr) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_deleteContext(JNIEnv *env, jobject redrawer, jlong contextPtr)
{ {
HGLRC context = reinterpret_cast<HGLRC>(static_cast<uintptr_t>(contextPtr)); HGLRC context = reinterpret_cast<HGLRC>(static_cast<uintptr_t>(contextPtr));
wglDeleteContext(context); wglDeleteContext(context);
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsRedrawerKt_dwmFlush(JNIEnv *env, jobject redrawer) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_WindowsOpenGLRedrawerKt_dwmFlush(JNIEnv *env, jobject redrawer)
{ {
DwmFlush(); DwmFlush();
} }
......
...@@ -62,7 +62,7 @@ abstract class HardwareLayer : Canvas() { ...@@ -62,7 +62,7 @@ abstract class HardwareLayer : Canvas() {
} }
// Should be called in Swing thread // Should be called in Swing thread
internal abstract suspend fun update(nanoTime: Long) internal abstract fun update(nanoTime: Long)
// Should be called in the OpenGL thread, and only once after update // Should be called in the OpenGL thread, and only once after update
internal abstract fun draw() internal abstract fun draw()
......
package org.jetbrains.skiko package org.jetbrains.skiko
import org.jetbrains.skiko.GraphicsApi import org.jetbrains.skiko.SkikoProperties.renderApi
import org.jetbrains.skiko.context.renderApi import org.jetbrains.skiko.redrawer.LinuxOpenGLRedrawer
import org.jetbrains.skiko.redrawer.LinuxRedrawer import org.jetbrains.skiko.redrawer.MacOsOpenGLRedrawer
import org.jetbrains.skiko.redrawer.MacOsRedrawer
import org.jetbrains.skiko.redrawer.RasterRedrawer import org.jetbrains.skiko.redrawer.RasterRedrawer
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.redrawer.Redrawer
import org.jetbrains.skiko.redrawer.WindowsRedrawer import org.jetbrains.skiko.redrawer.WindowsOpenGLRedrawer
import java.awt.Component import java.awt.Component
import java.awt.Window import java.awt.Window
import javax.swing.SwingUtilities import javax.swing.SwingUtilities
...@@ -35,7 +34,7 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -35,7 +34,7 @@ internal val platformOperations: PlatformOperations by lazy {
override fun createRedrawer(layer: HardwareLayer) = when(renderApi) { override fun createRedrawer(layer: HardwareLayer) = when(renderApi) {
GraphicsApi.SOFTWARE -> RasterRedrawer(layer) GraphicsApi.SOFTWARE -> RasterRedrawer(layer)
else -> MacOsRedrawer(layer) else -> MacOsOpenGLRedrawer(layer)
} }
} }
OS.Windows -> { OS.Windows -> {
...@@ -58,7 +57,7 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -58,7 +57,7 @@ internal val platformOperations: PlatformOperations by lazy {
override fun createRedrawer(layer: HardwareLayer) = when(renderApi) { override fun createRedrawer(layer: HardwareLayer) = when(renderApi) {
GraphicsApi.SOFTWARE -> RasterRedrawer(layer) GraphicsApi.SOFTWARE -> RasterRedrawer(layer)
else -> WindowsRedrawer(layer) else -> WindowsOpenGLRedrawer(layer)
} }
} }
} }
...@@ -94,7 +93,7 @@ internal val platformOperations: PlatformOperations by lazy { ...@@ -94,7 +93,7 @@ internal val platformOperations: PlatformOperations by lazy {
override fun createRedrawer(layer: HardwareLayer) = when(renderApi) { override fun createRedrawer(layer: HardwareLayer) = when(renderApi) {
GraphicsApi.SOFTWARE -> RasterRedrawer(layer) GraphicsApi.SOFTWARE -> RasterRedrawer(layer)
else -> LinuxRedrawer(layer) else -> LinuxOpenGLRedrawer(layer)
} }
} }
} }
......
...@@ -9,7 +9,7 @@ import java.awt.Graphics ...@@ -9,7 +9,7 @@ import java.awt.Graphics
import javax.swing.SwingUtilities.isEventDispatchThread import javax.swing.SwingUtilities.isEventDispatchThread
interface SkiaRenderer { interface SkiaRenderer {
suspend fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long)
} }
private class PictureHolder(val instance: Picture, val width: Int, val height: Int) private class PictureHolder(val instance: Picture, val width: Int, val height: Int)
...@@ -33,7 +33,7 @@ open class SkiaLayer : HardwareLayer() { ...@@ -33,7 +33,7 @@ open class SkiaLayer : HardwareLayer() {
super.init() super.init()
redrawer = platformOperations.createRedrawer(this) redrawer = platformOperations.createRedrawer(this)
redrawer?.syncSize() redrawer?.syncSize()
needRedraw() redrawer?.redrawImmediately()
} }
override fun dispose() { override fun dispose() {
...@@ -49,7 +49,7 @@ open class SkiaLayer : HardwareLayer() { ...@@ -49,7 +49,7 @@ open class SkiaLayer : HardwareLayer() {
override fun setBounds(x: Int, y: Int, width: Int, height: Int) { override fun setBounds(x: Int, y: Int, width: Int, height: Int) {
super.setBounds(x, y, width, height) super.setBounds(x, y, width, height)
redrawer?.syncSize() redrawer?.syncSize()
needRedraw() redrawer?.redrawImmediately()
} }
override fun paint(g: Graphics) { override fun paint(g: Graphics) {
...@@ -69,7 +69,7 @@ open class SkiaLayer : HardwareLayer() { ...@@ -69,7 +69,7 @@ open class SkiaLayer : HardwareLayer() {
probability = SkikoProperties.fpsProbability probability = SkikoProperties.fpsProbability
) )
override suspend fun update(nanoTime: Long) { override fun update(nanoTime: Long) {
check(!isDisposed) check(!isDisposed)
check(isEventDispatchThread()) check(isEventDispatchThread())
......
...@@ -8,6 +8,24 @@ internal object SkikoProperties { ...@@ -8,6 +8,24 @@ internal object SkikoProperties {
val fpsCount: Int by property("skiko.fps.count", default = 300) val fpsCount: Int by property("skiko.fps.count", default = 300)
val fpsProbability: Double by property("skiko.fps.probability", default = 0.97) val fpsProbability: Double by property("skiko.fps.probability", default = 0.97)
val renderApi: GraphicsApi by lazy {
val environment = System.getenv("SKIKO_RENDER_API")
val property = System.getProperty("skiko.renderApi")
if (environment != null) {
parseRenderApi(environment)
} else {
parseRenderApi(property)
}
}
private fun parseRenderApi(text: String?): GraphicsApi {
when(text) {
"SOFTWARE" -> return GraphicsApi.SOFTWARE
"OPENGL" -> return GraphicsApi.OPENGL
else -> return GraphicsApi.OPENGL
}
}
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
} }
......
...@@ -7,29 +7,12 @@ import org.jetbrains.skija.Picture ...@@ -7,29 +7,12 @@ import org.jetbrains.skija.Picture
import org.jetbrains.skija.Surface import org.jetbrains.skija.Surface
import org.jetbrains.skiko.GraphicsApi import org.jetbrains.skiko.GraphicsApi
import org.jetbrains.skiko.HardwareLayer import org.jetbrains.skiko.HardwareLayer
import org.jetbrains.skiko.hostOs
import org.jetbrains.skiko.OS import org.jetbrains.skiko.OS
import org.jetbrains.skiko.SkikoProperties
internal val renderApi: GraphicsApi by lazy { import org.jetbrains.skiko.hostOs
val environment = System.getenv("SKIKO_RENDER_API")
val property = System.getProperty("skiko.renderApi")
if (environment != null) {
parseRenderApi(environment)
} else {
parseRenderApi(property)
}
}
private fun parseRenderApi(text: String?): GraphicsApi {
when(text) {
"SOFTWARE" -> return GraphicsApi.SOFTWARE
"OPENGL" -> return GraphicsApi.OPENGL
else -> return GraphicsApi.OPENGL
}
}
internal fun createContextHandler(layer: HardwareLayer): ContextHandler { internal fun createContextHandler(layer: HardwareLayer): ContextHandler {
return when (renderApi) { return when (SkikoProperties.renderApi) {
GraphicsApi.SOFTWARE -> SoftwareContextHandler(layer) GraphicsApi.SOFTWARE -> SoftwareContextHandler(layer)
GraphicsApi.OPENGL -> OpenGLContextHandler(layer) GraphicsApi.OPENGL -> OpenGLContextHandler(layer)
else -> TODO("Unsupported yet") else -> TODO("Unsupported yet")
......
...@@ -2,25 +2,19 @@ package org.jetbrains.skiko.redrawer ...@@ -2,25 +2,19 @@ package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext
import org.jetbrains.skiko.FrameDispatcher import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.HardwareLayer import org.jetbrains.skiko.HardwareLayer
import org.jetbrains.skiko.OpenGLApi import org.jetbrains.skiko.OpenGLApi
import org.jetbrains.skiko.SkikoProperties import org.jetbrains.skiko.SkikoProperties
internal class LinuxRedrawer( internal class LinuxOpenGLRedrawer(
private val layer: HardwareLayer private val layer: HardwareLayer
) : Redrawer { ) : Redrawer {
private val context = layer.lockDrawingSurface { private val context = layer.lockDrawingSurface {
val context = it.createContext() it.createContext()
it.makeCurrent(context)
it.setSwapInterval(if (SkikoProperties.vsyncEnabled) 1 else 0)
context
} }
private var isDisposed = false private var isDisposed = false
private val job = Job()
override fun dispose() { override fun dispose() {
check(!isDisposed) check(!isDisposed)
...@@ -28,7 +22,6 @@ internal class LinuxRedrawer( ...@@ -28,7 +22,6 @@ internal class LinuxRedrawer(
it.destroyContext(context) it.destroyContext(context)
} }
isDisposed = true isDisposed = true
job.cancel()
} }
override fun needRedraw() { override fun needRedraw() {
...@@ -37,10 +30,18 @@ internal class LinuxRedrawer( ...@@ -37,10 +30,18 @@ internal class LinuxRedrawer(
frameDispatcher.scheduleFrame() frameDispatcher.scheduleFrame()
} }
private suspend fun update(nanoTime: Long) { override fun redrawImmediately() = layer.lockDrawingSurface {
withContext(job) { check(!isDisposed)
layer.update(nanoTime) update(System.nanoTime())
it.makeCurrent(context)
draw()
it.setSwapInterval(0)
it.swapBuffers()
OpenGLApi.instance.glFinish()
} }
private fun update(nanoTime: Long) {
layer.update(nanoTime)
} }
private fun draw() { private fun draw() {
...@@ -48,9 +49,9 @@ internal class LinuxRedrawer( ...@@ -48,9 +49,9 @@ internal class LinuxRedrawer(
} }
companion object { companion object {
private val toRedraw = mutableSetOf<LinuxRedrawer>() private val toRedraw = mutableSetOf<LinuxOpenGLRedrawer>()
private val toRedrawCopy = mutableSetOf<LinuxRedrawer>() private val toRedrawCopy = mutableSetOf<LinuxOpenGLRedrawer>()
private val toRedrawAlive = toRedrawCopy.asSequence().filterNot(LinuxRedrawer::isDisposed) private val toRedrawAlive = toRedrawCopy.asSequence().filterNot(LinuxOpenGLRedrawer::isDisposed)
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) { private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
toRedrawCopy.clear() toRedrawCopy.clear()
...@@ -75,6 +76,8 @@ internal class LinuxRedrawer( ...@@ -75,6 +76,8 @@ internal class LinuxRedrawer(
} }
toRedrawAlive.forEachIndexed { index, _ -> toRedrawAlive.forEachIndexed { index, _ ->
// it is ok to set swap interval every frame, there is no performance overhead
drawingSurfaces[index].setSwapInterval(if (SkikoProperties.vsyncEnabled) 1 else 0)
drawingSurfaces[index].swapBuffers() drawingSurfaces[index].swapBuffers()
} }
......
...@@ -10,7 +10,7 @@ import org.jetbrains.skiko.SkikoProperties ...@@ -10,7 +10,7 @@ import org.jetbrains.skiko.SkikoProperties
import javax.swing.SwingUtilities.convertPoint import javax.swing.SwingUtilities.convertPoint
import javax.swing.SwingUtilities.getRootPane import javax.swing.SwingUtilities.getRootPane
internal class MacOsRedrawer( internal class MacOsOpenGLRedrawer(
private val layer: HardwareLayer private val layer: HardwareLayer
) : Redrawer { ) : Redrawer {
private val containerLayerPtr = initContainer(layer) private val containerLayerPtr = initContainer(layer)
...@@ -104,6 +104,11 @@ internal class MacOsRedrawer( ...@@ -104,6 +104,11 @@ internal class MacOsRedrawer(
override fun needRedraw() { override fun needRedraw() {
frameDispatcher.scheduleFrame() frameDispatcher.scheduleFrame()
} }
override fun redrawImmediately() {
layer.update(System.nanoTime())
drawLayer.setNeedsDisplay()
}
} }
private open class AWTGLLayer(private val containerPtr: Long, setNeedsDisplayOnBoundsChange: Boolean) { private open class AWTGLLayer(private val containerPtr: Long, setNeedsDisplayOnBoundsChange: Boolean) {
......
...@@ -21,4 +21,9 @@ internal class RasterRedrawer( ...@@ -21,4 +21,9 @@ internal class RasterRedrawer(
override fun needRedraw() { override fun needRedraw() {
frameDispatcher.scheduleFrame() frameDispatcher.scheduleFrame()
} }
override fun redrawImmediately() {
layer.update(System.nanoTime())
layer.draw()
}
} }
\ No newline at end of file
...@@ -3,5 +3,6 @@ package org.jetbrains.skiko.redrawer ...@@ -3,5 +3,6 @@ package org.jetbrains.skiko.redrawer
interface Redrawer { interface Redrawer {
fun dispose() fun dispose()
fun needRedraw() fun needRedraw()
fun redrawImmediately()
fun syncSize() = Unit fun syncSize() = Unit
} }
\ No newline at end of file
...@@ -2,7 +2,6 @@ package org.jetbrains.skiko.redrawer ...@@ -2,7 +2,6 @@ package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.jetbrains.skiko.FrameDispatcher import org.jetbrains.skiko.FrameDispatcher
...@@ -10,13 +9,12 @@ import org.jetbrains.skiko.HardwareLayer ...@@ -10,13 +9,12 @@ import org.jetbrains.skiko.HardwareLayer
import org.jetbrains.skiko.OpenGLApi import org.jetbrains.skiko.OpenGLApi
import org.jetbrains.skiko.SkikoProperties import org.jetbrains.skiko.SkikoProperties
internal class WindowsRedrawer( internal class WindowsOpenGLRedrawer(
private val layer: HardwareLayer private val layer: HardwareLayer
) : Redrawer { ) : Redrawer {
private val device = getDevice(layer) private val device = getDevice(layer)
private val context = createContext(device) private val context = createContext(device)
private var isDisposed = false private var isDisposed = false
private val job = Job()
init { init {
makeCurrent() makeCurrent()
...@@ -31,7 +29,6 @@ internal class WindowsRedrawer( ...@@ -31,7 +29,6 @@ internal class WindowsRedrawer(
check(!isDisposed) check(!isDisposed)
deleteContext(context) deleteContext(context)
isDisposed = true isDisposed = true
job.cancel()
} }
override fun needRedraw() { override fun needRedraw() {
...@@ -40,10 +37,17 @@ internal class WindowsRedrawer( ...@@ -40,10 +37,17 @@ internal class WindowsRedrawer(
frameDispatcher.scheduleFrame() frameDispatcher.scheduleFrame()
} }
private suspend fun update(nanoTime: Long) { override fun redrawImmediately() {
withContext(job) { check(!isDisposed)
layer.update(nanoTime) update(System.nanoTime())
makeCurrent()
draw()
swapBuffers()
OpenGLApi.instance.glFinish()
} }
private fun update(nanoTime: Long) {
layer.update(nanoTime)
} }
private fun draw() { private fun draw() {
...@@ -54,9 +58,9 @@ internal class WindowsRedrawer( ...@@ -54,9 +58,9 @@ internal class WindowsRedrawer(
private fun swapBuffers() = swapBuffers(device) private fun swapBuffers() = swapBuffers(device)
companion object { companion object {
private val toRedraw = mutableSetOf<WindowsRedrawer>() private val toRedraw = mutableSetOf<WindowsOpenGLRedrawer>()
private val toRedrawCopy = mutableSetOf<WindowsRedrawer>() private val toRedrawCopy = mutableSetOf<WindowsOpenGLRedrawer>()
private val toRedrawAlive = toRedrawCopy.asSequence().filterNot(WindowsRedrawer::isDisposed) private val toRedrawAlive = toRedrawCopy.asSequence().filterNot(WindowsOpenGLRedrawer::isDisposed)
private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) { private val frameDispatcher = FrameDispatcher(Dispatchers.Swing) {
toRedrawCopy.clear() toRedrawCopy.clear()
......
...@@ -69,7 +69,7 @@ JavaVM *jvm = NULL; ...@@ -69,7 +69,7 @@ JavaVM *jvm = NULL;
@end @end
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_initContainer(JNIEnv *env, jobject redrawer, jobject layer) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsOpenGLRedrawerKt_initContainer(JNIEnv *env, jobject redrawer, jobject layer)
{ {
JAWT awt; JAWT awt;
awt.version = JAWT_VERSION_9; awt.version = JAWT_VERSION_9;
...@@ -101,14 +101,14 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_initCo ...@@ -101,14 +101,14 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_initCo
return (jlong) container; return (jlong) container;
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_setContentScale(JNIEnv *env, jobject obj, jlong layerPtr, jfloat contentScale) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MacOsOpenGLRedrawerKt_setContentScale(JNIEnv *env, jobject obj, jlong layerPtr, jfloat contentScale)
{ {
CALayer *layer = (CALayer *) layerPtr; CALayer *layer = (CALayer *) layerPtr;
assert(contentScale != 0); assert(contentScale != 0);
layer.contentsScale = contentScale; layer.contentsScale = contentScale;
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_initAWTGLLayer(JNIEnv *env, jobject obj, jlong containerPtr, jobject layer, jboolean setNeedsDisplayOnBoundsChange) JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsOpenGLRedrawerKt_initAWTGLLayer(JNIEnv *env, jobject obj, jlong containerPtr, jobject layer, jboolean setNeedsDisplayOnBoundsChange)
{ {
CALayer *container = (CALayer *) containerPtr; CALayer *container = (CALayer *) containerPtr;
...@@ -120,7 +120,7 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_initAW ...@@ -120,7 +120,7 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_initAW
return (jlong) glLayer; return (jlong) glLayer;
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MacOsRedrawerKt_disposeAWTGLLayer(JNIEnv *env, jobject obj, jlong ptr) JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MacOsOpenGLRedrawerKt_disposeAWTGLLayer(JNIEnv *env, jobject obj, jlong ptr)
{ {
AWTGLLayer *glLayer = (AWTGLLayer *) ptr; AWTGLLayer *glLayer = (AWTGLLayer *) ptr;
[glLayer removeFromSuperlayer]; [glLayer removeFromSuperlayer];
......
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