Unverified Commit 7c12a857 authored by Nikolai Rykunov's avatar Nikolai Rykunov Committed by GitHub

Fix memory leak because of missing autoreleasepool in offscreen rendering for Swing interop (#764)

parent 1afda4d3
...@@ -25,7 +25,26 @@ internal fun MetalAdapter.dispose() { ...@@ -25,7 +25,26 @@ internal fun MetalAdapter.dispose() {
disposeAdapter(ptr) disposeAdapter(ptr)
} }
/**
* [@autoreleasepool](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html)
*/
@Suppress("SpellCheckingInspection")
internal inline fun <R> autoreleasepool(block: () -> R): R {
val handle = openAutoreleasepool()
return try {
block()
} finally {
closeAutoreleasepool(handle)
}
}
private external fun chooseAdapter(adapterPriority: Int): Long private external fun chooseAdapter(adapterPriority: Int): Long
private external fun disposeAdapter(adapter: Long) private external fun disposeAdapter(adapter: Long)
private external fun getAdapterName(adapter: Long): String private external fun getAdapterName(adapter: Long): String
private external fun getAdapterMemorySize(adapter: Long): Long private external fun getAdapterMemorySize(adapter: Long): Long
\ No newline at end of file
@Suppress("SpellCheckingInspection")
private external fun openAutoreleasepool(): Long
@Suppress("SpellCheckingInspection")
private external fun closeAutoreleasepool(handle: Long)
\ No newline at end of file
...@@ -154,11 +154,8 @@ internal class MetalRedrawer( ...@@ -154,11 +154,8 @@ internal class MetalRedrawer(
// - it makes frames consistent and limits FPS // - it makes frames consistent and limits FPS
displayLinkThrottler.waitVSync(windowPtr = layer.windowHandle) displayLinkThrottler.waitVSync(windowPtr = layer.windowHandle)
val handle = startRendering() autoreleasepool {
try {
contextHandler.draw() contextHandler.draw()
} finally {
endRendering(handle)
} }
} }
} }
...@@ -188,6 +185,4 @@ internal class MetalRedrawer( ...@@ -188,6 +185,4 @@ internal class MetalRedrawer(
private external fun setContentScale(device: Long, contentScale: Float) private external fun setContentScale(device: Long, contentScale: Float)
private external fun setVSyncEnabled(device: Long, enabled: Boolean) private external fun setVSyncEnabled(device: Long, enabled: Boolean)
private external fun isOccluded(window: Long): Boolean private external fun isOccluded(window: Long): Boolean
private external fun startRendering(): Long
private external fun endRendering(handle: Long)
} }
...@@ -44,21 +44,25 @@ internal class MetalSwingRedrawer( ...@@ -44,21 +44,25 @@ internal class MetalSwingRedrawer(
super.dispose() super.dispose()
} }
override fun onRender(g: Graphics2D, width: Int, height: Int, nanoTime: Long) = autoCloseScope { override fun onRender(g: Graphics2D, width: Int, height: Int, nanoTime: Long) {
val renderTarget = makeRenderTarget(width, height).autoClose() autoreleasepool {
val surface = Surface.makeFromBackendRenderTarget( autoCloseScope {
context, val renderTarget = makeRenderTarget(width, height).autoClose()
renderTarget, val surface = Surface.makeFromBackendRenderTarget(
SurfaceOrigin.TOP_LEFT, context,
SurfaceColorFormat.BGRA_8888, renderTarget,
ColorSpace.sRGB, SurfaceOrigin.TOP_LEFT,
SurfaceProps(pixelGeometry = PixelGeometry.UNKNOWN) SurfaceColorFormat.BGRA_8888,
)?.autoClose() ?: throw RenderException("Cannot create surface") ColorSpace.sRGB,
SurfaceProps(pixelGeometry = PixelGeometry.UNKNOWN)
val canvas = surface.canvas )?.autoClose() ?: throw RenderException("Cannot create surface")
canvas.clear(Color.TRANSPARENT)
skikoView.onRender(canvas, width, height, nanoTime) val canvas = surface.canvas
flush(surface, g) canvas.clear(Color.TRANSPARENT)
skikoView.onRender(canvas, width, height, nanoTime)
flush(surface, g)
}
}
} }
private fun flush(surface: Surface, g: Graphics2D) { private fun flush(surface: Surface, g: Graphics2D) {
......
...@@ -26,6 +26,21 @@ ...@@ -26,6 +26,21 @@
extern "C" extern "C"
{ {
extern "C" void* objc_autoreleasePoolPush(void);
extern "C" void objc_autoreleasePoolPop(void*);
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_openAutoreleasepool(
JNIEnv * env, jobject redrawer)
{
return (jlong)objc_autoreleasePoolPush();
}
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_MetalApiKt_closeAutoreleasepool(
JNIEnv * env, jobject redrawer, jlong handle)
{
objc_autoreleasePoolPop((void*)handle);
}
BOOL isUsingIntegratedGPU() { BOOL isUsingIntegratedGPU() {
kern_return_t kernResult = 0; kern_return_t kernResult = 0;
io_iterator_t iterator = IO_OBJECT_NULL; io_iterator_t iterator = IO_OBJECT_NULL;
......
...@@ -54,21 +54,6 @@ ...@@ -54,21 +54,6 @@
extern "C" extern "C"
{ {
extern "C" void* objc_autoreleasePoolPush(void);
extern "C" void objc_autoreleasePoolPop(void*);
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_startRendering(
JNIEnv * env, jobject redrawer)
{
return (jlong)objc_autoreleasePoolPush();
}
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_endRendering(
JNIEnv * env, jobject redrawer, jlong handle)
{
objc_autoreleasePoolPop((void*)handle);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_createMetalDevice( JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_createMetalDevice(
JNIEnv *env, jobject redrawer, jlong windowPtr, jboolean transparency, jlong adapterPtr, jlong platformInfoPtr) JNIEnv *env, jobject redrawer, jlong windowPtr, jboolean transparency, jlong adapterPtr, jlong platformInfoPtr)
{ {
......
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