Unverified Commit 7670c518 authored by Elijah Semyonov's avatar Elijah Semyonov Committed by GitHub

Fix crash during MetalAdapter initialisation (#786)

* Correctly handle nulls when working with Obj-C API.
Throw RenderException if MTLDevice is null to allow RedrawerManager fallback to software renderer.

* Perform minor refactor
parent 38090dc7
...@@ -8,6 +8,11 @@ package org.jetbrains.skiko ...@@ -8,6 +8,11 @@ package org.jetbrains.skiko
*/ */
internal fun chooseMetalAdapter(adapterPriority: GpuPriority): MetalAdapter { internal fun chooseMetalAdapter(adapterPriority: GpuPriority): MetalAdapter {
val adapter = chooseAdapter(adapterPriority.ordinal) val adapter = chooseAdapter(adapterPriority.ordinal)
if (adapter == 0L) {
throw RenderException("MetalApi.chooseAdapter returned null")
}
val adapterName = getAdapterName(adapter) val adapterName = getAdapterName(adapter)
val adapterMemorySize = getAdapterMemorySize(adapter) val adapterMemorySize = getAdapterMemorySize(adapter)
......
...@@ -19,29 +19,26 @@ ...@@ -19,29 +19,26 @@
#define kOpen 0 #define kOpen 0
#define kGetMuxState 3 #define kGetMuxState 3
#define kDriverClassName "AppleGraphicsControl" #define kDriverClassName "AppleGraphicsControl"
#define AdpapterPriorityAuto 0 #define AdapterPriorityAuto 0
#define AdpapterPriorityIntegrated 1 #define AdapterPriorityIntegrated 1
#define AdpapterPriorityDiscrete 2 #define AdapterPriorityDiscrete 2
extern "C" extern "C" {
{
extern "C" void* objc_autoreleasePoolPush(void); void *objc_autoreleasePoolPush(void);
extern "C" void objc_autoreleasePoolPop(void*); void objc_autoreleasePoolPop(void *);
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_openAutoreleasepool( JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_openAutoreleasepool(
JNIEnv * env, jobject redrawer) JNIEnv *env, jobject redrawer) {
{
return (jlong)objc_autoreleasePoolPush(); return (jlong)objc_autoreleasePoolPush();
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_MetalApiKt_closeAutoreleasepool( JNIEXPORT void JNICALL Java_org_jetbrains_skiko_MetalApiKt_closeAutoreleasepool(
JNIEnv * env, jobject redrawer, jlong handle) JNIEnv *env, jobject redrawer, jlong handle) {
{ objc_autoreleasePoolPop((void *)handle);
objc_autoreleasePoolPop((void*)handle);
} }
BOOL isUsingIntegratedGPU() { static 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;
io_service_t service = IO_OBJECT_NULL; io_service_t service = IO_OBJECT_NULL;
...@@ -72,62 +69,69 @@ BOOL isUsingIntegratedGPU() { ...@@ -72,62 +69,69 @@ BOOL isUsingIntegratedGPU() {
return output != 0; return output != 0;
} }
id<MTLDevice> MTLCreateIntegratedDevice(int adapterPriority) { static BOOL preferLowPowerGPU(int adapterPriority) {
BOOL isIntegratedGPU = NO; switch (adapterPriority) {
case AdapterPriorityAuto:
if (adapterPriority == AdpapterPriorityAuto) { return isUsingIntegratedGPU();
isIntegratedGPU = isUsingIntegratedGPU();
} else if (adapterPriority == AdpapterPriorityIntegrated) { case AdapterPriorityIntegrated:
isIntegratedGPU = YES; return YES;
default: // AdapterPriorityDiscrete or invalid adapterPriority
return NO;
} }
}
id<MTLDevice> gpu = nil; static id<MTLDevice> createIntegratedMTLDevice(int adapterPriority) {
if (preferLowPowerGPU(adapterPriority)) {
if (isIntegratedGPU) {
NSArray<id<MTLDevice>> *devices = MTLCopyAllDevices(); NSArray<id<MTLDevice>> *devices = MTLCopyAllDevices();
for (id<MTLDevice> device in devices) { for (id<MTLDevice> device in devices) {
if (device.isLowPower) { if (device.isLowPower) {
gpu = device; return device;
break;
} }
} }
} }
if (gpu == nil) {
gpu = MTLCreateSystemDefaultDevice(); return MTLCreateSystemDefaultDevice();
}
return gpu;
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_chooseAdapter( JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_chooseAdapter(
JNIEnv *env, jobject obj, jlong adapterPriority) JNIEnv *env, jobject obj, jlong adapterPriority) {
{
@autoreleasepool { @autoreleasepool {
id<MTLDevice> adapter = MTLCreateIntegratedDevice(adapterPriority); id<MTLDevice> adapter = createIntegratedMTLDevice(adapterPriority);
return (jlong) (__bridge_retained void *) adapter;
if (adapter) {
return (jlong) (__bridge_retained void *) adapter;
} else {
return 0;
}
} }
} }
JNIEXPORT void JNICALL Java_org_jetbrains_skiko_MetalApiKt_disposeAdapter( JNIEXPORT void JNICALL Java_org_jetbrains_skiko_MetalApiKt_disposeAdapter(
JNIEnv *env, jobject obj, jlong adapterPtr) JNIEnv *env, jobject obj, jlong adapterPtr) {
{
@autoreleasepool { @autoreleasepool {
id<MTLDevice> adapter = (__bridge_transfer id<MTLDevice>) (void *) adapterPtr; id<MTLDevice> adapter = (__bridge_transfer id<MTLDevice>) (void *) adapterPtr;
} }
} }
JNIEXPORT jstring JNICALL Java_org_jetbrains_skiko_MetalApiKt_getAdapterName( JNIEXPORT jstring JNICALL Java_org_jetbrains_skiko_MetalApiKt_getAdapterName(
JNIEnv *env, jobject obj, jlong adapterPtr) JNIEnv *env, jobject obj, jlong adapterPtr) {
{
@autoreleasepool { @autoreleasepool {
id<MTLDevice> adapter = (__bridge id<MTLDevice>) (void *) adapterPtr; id<MTLDevice> adapter = (__bridge id<MTLDevice>) (void *) adapterPtr;
const char *currentAdapterName = [[adapter name] cStringUsingEncoding:NSASCIIStringEncoding];
return env->NewStringUTF(currentAdapterName); const char *currentAdapterName = [[adapter name] cStringUsingEncoding:NSUTF8StringEncoding];
if (currentAdapterName) {
return env->NewStringUTF(currentAdapterName);
} else {
return env->NewStringUTF("Unknown Metal adapter");
}
} }
} }
JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_getAdapterMemorySize( JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_getAdapterMemorySize(
JNIEnv *env, jobject obj, jlong adapterPtr) JNIEnv *env, jobject obj, jlong adapterPtr) {
{
@autoreleasepool { @autoreleasepool {
id<MTLDevice> adapter = (__bridge id<MTLDevice>) (void *) adapterPtr; id<MTLDevice> adapter = (__bridge id<MTLDevice>) (void *) adapterPtr;
uint64_t totalMemory = [adapter recommendedMaxWorkingSetSize]; uint64_t totalMemory = [adapter recommendedMaxWorkingSetSize];
...@@ -135,5 +139,6 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_getAdapterMemorySize ...@@ -135,5 +139,6 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_skiko_MetalApiKt_getAdapterMemorySize
} }
} }
} // extern C } // extern "C"
#endif
#endif // SK_METAL
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