|
8 | 8 | #include <errno.h> |
9 | 9 | #include <fcntl.h> |
10 | 10 | #include <limits.h> |
| 11 | +#include <mach-o/dyld.h> |
11 | 12 | #include <math.h> |
12 | 13 | #include <stdarg.h> |
13 | 14 | #include <stdio.h> |
@@ -325,6 +326,25 @@ static int h3_gpu_dispatch_rows(H3GPU *gpu, NSString *name, uint32_t rows, |
325 | 326 | return 1; |
326 | 327 | } |
327 | 328 |
|
| 329 | +static NSString *h3_gpu_executable_relative_path(NSString *relative_path) { |
| 330 | + if (!relative_path || relative_path.isAbsolutePath) return nil; |
| 331 | + |
| 332 | + uint32_t size = 0; |
| 333 | + if (_NSGetExecutablePath(NULL, &size) != -1 || !size) return nil; |
| 334 | + char *buffer = malloc(size); |
| 335 | + if (!buffer) return nil; |
| 336 | + if (_NSGetExecutablePath(buffer, &size) != 0) { |
| 337 | + free(buffer); |
| 338 | + return nil; |
| 339 | + } |
| 340 | + |
| 341 | + NSString *executable = [NSString stringWithUTF8String:buffer]; |
| 342 | + free(buffer); |
| 343 | + if (!executable) return nil; |
| 344 | + return [[executable stringByDeletingLastPathComponent] |
| 345 | + stringByAppendingPathComponent:relative_path]; |
| 346 | +} |
| 347 | + |
328 | 348 | h3_gpu *h3_gpu_create(const char *shader_source_path, |
329 | 349 | char *error, size_t error_size) { |
330 | 350 | @autoreleasepool { |
@@ -352,11 +372,24 @@ static int h3_gpu_dispatch_rows(H3GPU *gpu, NSString *name, uint32_t rows, |
352 | 372 | } |
353 | 373 | const char *source_path = shader_source_path ? shader_source_path : |
354 | 374 | "h3_shaders.metal"; |
355 | | - NSString *path = [NSString stringWithUTF8String:source_path]; |
| 375 | + NSString *requestedPath = [NSString stringWithUTF8String:source_path]; |
| 376 | + NSString *path = requestedPath; |
| 377 | + NSString *executableRelativePath = nil; |
356 | 378 | NSError *libraryError = nil; |
357 | 379 | NSString *source = [NSString stringWithContentsOfFile:path |
358 | 380 | encoding:NSUTF8StringEncoding |
359 | 381 | error:&libraryError]; |
| 382 | + if (!source) { |
| 383 | + executableRelativePath = |
| 384 | + h3_gpu_executable_relative_path(requestedPath); |
| 385 | + if (executableRelativePath) { |
| 386 | + libraryError = nil; |
| 387 | + source = [NSString stringWithContentsOfFile:executableRelativePath |
| 388 | + encoding:NSUTF8StringEncoding |
| 389 | + error:&libraryError]; |
| 390 | + if (source) path = executableRelativePath; |
| 391 | + } |
| 392 | + } |
360 | 393 | if (source) { |
361 | 394 | MTLCompileOptions *options = [[MTLCompileOptions alloc] init]; |
362 | 395 | options.mathMode = MTLMathModeSafe; |
@@ -396,8 +429,16 @@ static int h3_gpu_dispatch_rows(H3GPU *gpu, NSString *name, uint32_t rows, |
396 | 429 | if (!gpu.library) { |
397 | 430 | if (error && error_size) { |
398 | 431 | const char *description = libraryError.localizedDescription.UTF8String; |
399 | | - snprintf(error, error_size, "cannot compile %s: %s", |
400 | | - source_path, description ? description : "unknown error"); |
| 432 | + if (!source && executableRelativePath) { |
| 433 | + snprintf(error, error_size, "cannot read %s or %s: %s", |
| 434 | + requestedPath.UTF8String, |
| 435 | + executableRelativePath.UTF8String, |
| 436 | + description ? description : "unknown error"); |
| 437 | + } else { |
| 438 | + snprintf(error, error_size, "cannot compile %s: %s", |
| 439 | + path.UTF8String, |
| 440 | + description ? description : "unknown error"); |
| 441 | + } |
401 | 442 | } |
402 | 443 | return NULL; |
403 | 444 | } |
|
0 commit comments