Unverified Commit 64946688 authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

Fix memory leak. (#140)

parent b3fb7a60
...@@ -16,7 +16,7 @@ import javax.swing.SwingUtilities.getRootPane ...@@ -16,7 +16,7 @@ import javax.swing.SwingUtilities.getRootPane
internal class MetalRedrawer( internal class MetalRedrawer(
private val layer: SkiaLayer, private val layer: SkiaLayer,
private val properties: SkiaLayerProperties properties: SkiaLayerProperties
) : Redrawer { ) : Redrawer {
private var isDisposed = false private var isDisposed = false
private var disposeLock = Any() private var disposeLock = Any()
...@@ -58,6 +58,8 @@ internal class MetalRedrawer( ...@@ -58,6 +58,8 @@ internal class MetalRedrawer(
} }
private suspend fun draw() { private suspend fun draw() {
withContext(Dispatchers.IO) {
val handle = startRendering()
if (layer.prepareDrawContext()) { if (layer.prepareDrawContext()) {
// 2,3 GHz 8-Core Intel Core i9 // 2,3 GHz 8-Core Intel Core i9
// //
...@@ -70,26 +72,27 @@ internal class MetalRedrawer( ...@@ -70,26 +72,27 @@ internal class MetalRedrawer(
// //
// Executors.newSingleThreadExecutor().asCoroutineDispatcher(): 50 FPS, 150% CPU // Executors.newSingleThreadExecutor().asCoroutineDispatcher(): 50 FPS, 150% CPU
// Dispatchers.IO: 50 FPS, 200% CPU // Dispatchers.IO: 50 FPS, 200% CPU
withContext(Dispatchers.IO) {
synchronized(disposeLock) { synchronized(disposeLock) {
if (!isDisposed) { if (!isDisposed) {
layer.draw() layer.draw()
} }
} }
} }
endRendering(handle)
}
// When window is not visible - it doesn't make sense to redraw fast to avoid battery drain. // When window is not visible - it doesn't make sense to redraw fast to avoid battery drain.
// In theory, we could be more precise, and just suspend rendering in // In theory, we could be more precise, and just suspend rendering in
// `NSWindowDidChangeOcclusionStateNotification`, but current approach seems to work as well in practise. // `NSWindowDidChangeOcclusionStateNotification`, but current approach seems to work as well in practise.
if (isOccluded(windowHandle)) if (isOccluded(windowHandle))
delay(300) delay(300)
} }
}
override fun syncSize() { override fun syncSize() {
val rootPane = getRootPane(layer) val rootPane = getRootPane(layer)
val globalPosition = convertPoint(layer, layer.x, layer.y, rootPane) val globalPosition = convertPoint(layer, layer.x, layer.y, rootPane)
setContentScale(device, layer.contentScale) setContentScale(device, layer.contentScale)
resizeLayers(device, resizeLayers(
device,
globalPosition.x, globalPosition.x,
rootPane.height - globalPosition.y - layer.height, rootPane.height - globalPosition.y - layer.height,
layer.width.coerceAtLeast(0), layer.width.coerceAtLeast(0),
...@@ -130,4 +133,6 @@ internal class MetalRedrawer( ...@@ -130,4 +133,6 @@ internal class MetalRedrawer(
private external fun isOccluded(window: Long): Boolean private external fun isOccluded(window: Long): Boolean
private external fun getAdapterName(device: Long): String private external fun getAdapterName(device: Long): String
private external fun getAdapterMemorySize(device: Long): Long private external fun getAdapterMemorySize(device: Long): Long
private external fun startRendering(): Long
private external fun endRendering(handle: Long)
} }
...@@ -101,17 +101,30 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_makeMeta ...@@ -101,17 +101,30 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_makeMeta
MetalDevice *device = (MetalDevice *) devicePtr; MetalDevice *device = (MetalDevice *) devicePtr;
GrBackendRenderTarget* renderTarget = NULL; GrBackendRenderTarget* renderTarget = NULL;
@autoreleasepool {
id<CAMetalDrawable> currentDrawable = [device.layer nextDrawable]; id<CAMetalDrawable> currentDrawable = [device.layer nextDrawable];
if (!currentDrawable) return 0; if (!currentDrawable) return 0;
device.drawableHandle = currentDrawable; device.drawableHandle = currentDrawable;
GrMtlTextureInfo info; GrMtlTextureInfo info;
info.fTexture.retain(currentDrawable.texture); info.fTexture.retain(currentDrawable.texture);
renderTarget = new GrBackendRenderTarget(width, height, 0, info); renderTarget = new GrBackendRenderTarget(width, height, 0, info);
}
return (jlong) renderTarget; return (jlong) renderTarget;
} }
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);
}
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;
...@@ -241,18 +254,13 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_finishFra ...@@ -241,18 +254,13 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_finishFra
id<CAMetalDrawable> currentDrawable = device.drawableHandle; id<CAMetalDrawable> currentDrawable = device.drawableHandle;
if (currentDrawable) {
id<MTLCommandBuffer> commandBuffer = [device.queue commandBuffer]; id<MTLCommandBuffer> commandBuffer = [device.queue commandBuffer];
commandBuffer.label = @"Present"; commandBuffer.label = @"Present";
[currentDrawable addPresentedHandler:^(id<MTLDrawable> dr) {
CFRelease(currentDrawable);
}];
[commandBuffer presentDrawable:currentDrawable]; [commandBuffer presentDrawable:currentDrawable];
[commandBuffer commit]; [commandBuffer commit];
device.drawableHandle = nil; device.drawableHandle = nil;
}
currentDrawable = nil;
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_disposeDevice( JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_disposeDevice(
......
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