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
internal class MetalRedrawer(
private val layer: SkiaLayer,
private val properties: SkiaLayerProperties
properties: SkiaLayerProperties
) : Redrawer {
private var isDisposed = false
private var disposeLock = Any()
......@@ -58,6 +58,8 @@ internal class MetalRedrawer(
}
private suspend fun draw() {
withContext(Dispatchers.IO) {
val handle = startRendering()
if (layer.prepareDrawContext()) {
// 2,3 GHz 8-Core Intel Core i9
//
......@@ -70,26 +72,27 @@ internal class MetalRedrawer(
//
// Executors.newSingleThreadExecutor().asCoroutineDispatcher(): 50 FPS, 150% CPU
// Dispatchers.IO: 50 FPS, 200% CPU
withContext(Dispatchers.IO) {
synchronized(disposeLock) {
if (!isDisposed) {
layer.draw()
}
}
}
endRendering(handle)
}
// 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
// `NSWindowDidChangeOcclusionStateNotification`, but current approach seems to work as well in practise.
if (isOccluded(windowHandle))
delay(300)
}
}
override fun syncSize() {
val rootPane = getRootPane(layer)
val globalPosition = convertPoint(layer, layer.x, layer.y, rootPane)
setContentScale(device, layer.contentScale)
resizeLayers(device,
resizeLayers(
device,
globalPosition.x,
rootPane.height - globalPosition.y - layer.height,
layer.width.coerceAtLeast(0),
......@@ -130,4 +133,6 @@ internal class MetalRedrawer(
private external fun isOccluded(window: Long): Boolean
private external fun getAdapterName(device: Long): String
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
MetalDevice *device = (MetalDevice *) devicePtr;
GrBackendRenderTarget* renderTarget = NULL;
@autoreleasepool {
id<CAMetalDrawable> currentDrawable = [device.layer nextDrawable];
if (!currentDrawable) return 0;
device.drawableHandle = currentDrawable;
GrMtlTextureInfo info;
info.fTexture.retain(currentDrawable.texture);
renderTarget = new GrBackendRenderTarget(width, height, 0, info);
}
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() {
kern_return_t kernResult = 0;
io_iterator_t iterator = IO_OBJECT_NULL;
......@@ -241,18 +254,13 @@ JNIEXPORT void JNICALL Java_org_jetbrains_skiko_redrawer_MetalRedrawer_finishFra
id<CAMetalDrawable> currentDrawable = device.drawableHandle;
if (currentDrawable) {
id<MTLCommandBuffer> commandBuffer = [device.queue commandBuffer];
commandBuffer.label = @"Present";
[currentDrawable addPresentedHandler:^(id<MTLDrawable> dr) {
CFRelease(currentDrawable);
}];
[commandBuffer presentDrawable:currentDrawable];
[commandBuffer commit];
device.drawableHandle = nil;
currentDrawable = nil;
}
}
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